2015-12-19 00:39:03 -06:00
# include <algorithm>
2019-04-20 07:12:32 -05:00
# include "simulation/ElementCommon.h"
2015-12-19 00:39:03 -06:00
2020-01-09 03:34:15 -06:00
static void initDeltaPos ( ) ;
static void changeType ( ELEMENT_CHANGETYPE_FUNC_ARGS ) ;
void Element : : Element_ETRD ( )
2012-05-07 11:59:50 -05:00
{
2013-03-13 14:54:34 -05:00
Identifier = " DEFAULT_PT_ETRD " ;
Name = " ETRD " ;
Colour = PIXPACK ( 0x404040 ) ;
MenuVisible = 1 ;
MenuSection = SC_ELEC ;
Enabled = 1 ;
2015-12-18 01:27:19 -06:00
2013-03-13 14:54:34 -05:00
Advection = 0.0f ;
AirDrag = 0.00f * CFDS ;
AirLoss = 0.90f ;
Loss = 0.00f ;
Collision = 0.0f ;
Gravity = 0.0f ;
Diffusion = 0.00f ;
HotAir = 0.000f * CFDS ;
Falldown = 0 ;
2015-12-18 01:27:19 -06:00
2013-03-13 14:54:34 -05:00
Flammable = 0 ;
Explosive = 0 ;
Meltable = 0 ;
Hardness = 1 ;
2015-12-18 01:27:19 -06:00
2013-03-13 14:54:34 -05:00
Weight = 100 ;
2015-12-18 01:27:19 -06:00
2013-03-13 14:54:34 -05:00
HeatConduct = 251 ;
Description = " Electrode. Creates a surface that allows Plasma arcs. (Use sparingly) " ;
2015-12-18 00:51:22 -06:00
2013-03-13 14:54:34 -05:00
Properties = TYPE_SOLID | PROP_CONDUCTS | PROP_LIFE_DEC ;
2015-12-18 01:27:19 -06:00
2013-03-13 14:54:34 -05:00
LowPressure = IPL ;
LowPressureTransition = NT ;
HighPressure = IPH ;
HighPressureTransition = NT ;
LowTemperature = ITL ;
LowTemperatureTransition = NT ;
HighTemperature = ITH ;
HighTemperatureTransition = NT ;
2015-12-18 01:27:19 -06:00
2020-01-09 03:34:15 -06:00
ChangeType = & changeType ;
2015-12-19 00:39:03 -06:00
2020-01-09 03:34:15 -06:00
initDeltaPos ( ) ;
2015-12-19 00:39:03 -06:00
}
2020-01-09 03:34:15 -06:00
static void changeType ( ELEMENT_CHANGETYPE_FUNC_ARGS )
Add CreateAllowed and ChangeType events
Used in create_part, kill_part, and part_change_type, allows us to remove element-specific stuff in those functions
Note: difference between Create and ChangeType is that Create is called when we want to initialize default element properties, but ChangeType is called every time a particle is changed to that type, even if it doesn't need default properties set. ChangeType is mainly used for things that need accurate state tracking, like the stkm spawn status.
ChangeType is called every time a particle is changed to or from its type, which includes if the particle is deleted, and also Lua.
Neither of these functions are called when loading saves, that's probably an oversight, will fix later
2019-11-29 18:32:33 -06:00
{
if ( sim - > etrd_count_valid )
{
if ( from = = PT_ETRD & & sim - > parts [ i ] . life = = 0 )
sim - > etrd_life0_count - - ;
if ( to = = PT_ETRD & & sim - > parts [ i ] . life = = 0 )
sim - > etrd_life0_count + + ;
}
}
2015-12-19 00:39:03 -06:00
class ETRD_deltaWithLength
{
public :
ETRD_deltaWithLength ( ui : : Point a , int b ) :
d ( a ) ,
length ( b )
{
}
ui : : Point d ;
int length ;
} ;
const int maxLength = 12 ;
std : : vector < ETRD_deltaWithLength > deltaPos ;
2020-01-09 03:34:15 -06:00
static void initDeltaPos ( )
2015-12-19 00:39:03 -06:00
{
deltaPos . clear ( ) ;
for ( int ry = - maxLength ; ry < = maxLength ; ry + + )
for ( int rx = - maxLength ; rx < = maxLength ; rx + + )
{
ui : : Point d ( rx , ry ) ;
if ( std : : abs ( d . X ) + std : : abs ( d . Y ) < = maxLength )
deltaPos . push_back ( ETRD_deltaWithLength ( d , std : : abs ( d . X ) + std : : abs ( d . Y ) ) ) ;
}
2020-01-09 03:34:15 -06:00
std : : stable_sort ( deltaPos . begin ( ) , deltaPos . end ( ) , [ ] ( const ETRD_deltaWithLength & a , const ETRD_deltaWithLength & b ) {
return a . length < b . length ;
} ) ;
2015-12-19 00:39:03 -06:00
}
2020-01-09 03:34:15 -06:00
int Element_ETRD_nearestSparkablePart ( Simulation * sim , int targetId )
2015-12-19 00:39:03 -06:00
{
if ( ! sim - > elementCount [ PT_ETRD ] )
return - 1 ;
if ( sim - > etrd_count_valid & & sim - > etrd_life0_count < = 0 )
return - 1 ;
Particle * parts = sim - > parts ;
int foundDistance = XRES + YRES ;
int foundI = - 1 ;
2021-02-15 14:11:10 -06:00
ui : : Point targetPos = ui : : Point ( int ( parts [ targetId ] . x ) , int ( parts [ targetId ] . y ) ) ;
2015-12-19 00:39:03 -06:00
if ( sim - > etrd_count_valid )
{
// countLife0 doesn't need recalculating, so just focus on finding the nearest particle
// If the simulation contains lots of particles, check near the target position first since going through all particles will be slow.
// Threshold = number of positions checked, *2 because it's likely to access memory all over the place (less cache friendly) and there's extra logic needed
// TODO: probably not optimal if excessive stacking is used
if ( sim - > parts_lastActiveIndex > ( int ) deltaPos . size ( ) * 2 )
{
for ( std : : vector < ETRD_deltaWithLength > : : iterator iter = deltaPos . begin ( ) , end = deltaPos . end ( ) ; iter ! = end ; + + iter )
{
ETRD_deltaWithLength delta = ( * iter ) ;
ui : : Point checkPos = targetPos + delta . d ;
int checkDistance = delta . length ;
if ( foundDistance < checkDistance )
{
// deltaPos is sorted in order of ascending length, so foundDistance < checkDistance means all later items are further away.
break ;
}
if ( sim - > InBounds ( checkPos . X , checkPos . Y ) & & checkDistance < = foundDistance )
{
int r = sim - > pmap [ checkPos . Y ] [ checkPos . X ] ;
2017-12-28 12:00:23 -06:00
if ( r & & TYP ( r ) = = PT_ETRD & & ! parts [ ID ( r ) ] . life & & ID ( r ) ! = targetId & & checkDistance < foundDistance )
2015-12-19 00:39:03 -06:00
{
foundDistance = checkDistance ;
2017-12-28 11:03:26 -06:00
foundI = ID ( r ) ;
2015-12-19 00:39:03 -06:00
}
}
}
}
// If neighbor search didn't find a suitable particle, search all particles
if ( foundI < 0 )
{
for ( int i = 0 ; i < = sim - > parts_lastActiveIndex ; i + + )
{
if ( parts [ i ] . type = = PT_ETRD & & ! parts [ i ] . life )
{
2021-02-15 14:11:10 -06:00
ui : : Point checkPos = ui : : Point ( int ( parts [ i ] . x ) - targetPos . X , int ( parts [ i ] . y ) - targetPos . Y ) ;
2015-12-19 00:39:03 -06:00
int checkDistance = std : : abs ( checkPos . X ) + std : : abs ( checkPos . Y ) ;
if ( checkDistance < foundDistance & & i ! = targetId )
{
foundDistance = checkDistance ;
foundI = i ;
}
}
}
}
}
else
{
// Recalculate countLife0, and search for the closest suitable particle
int countLife0 = 0 ;
for ( int i = 0 ; i < = sim - > parts_lastActiveIndex ; i + + )
{
if ( parts [ i ] . type = = PT_ETRD & & ! parts [ i ] . life )
{
countLife0 + + ;
2021-02-15 14:11:10 -06:00
ui : : Point checkPos = ui : : Point ( int ( parts [ i ] . x ) - targetPos . X , int ( parts [ i ] . y ) - targetPos . Y ) ;
2015-12-19 00:39:03 -06:00
int checkDistance = std : : abs ( checkPos . X ) + std : : abs ( checkPos . Y ) ;
if ( checkDistance < foundDistance & & i ! = targetId )
{
foundDistance = checkDistance ;
foundI = i ;
}
}
}
sim - > etrd_life0_count = countLife0 ;
sim - > etrd_count_valid = true ;
}
return foundI ;
2012-05-07 11:59:50 -05:00
}