@ -409,7 +409,7 @@ LauncherTarget missile_launcher_target(GameState *gs, Entity *launcher)
void destroy_constraints ( cpBody * body , cpConstraint * constraint , void * data )
{
( ( Entity * ) cpConstraintGetUserData ( constraint ) ) - > landed_constraint = NULL ;
( ( Entity * ) cpConstraintGetUserData ( constraint ) ) - > landed_constraint = NULL ;
cpSpaceRemoveConstraint ( cpBodyGetSpace ( body ) , constraint ) ;
cpConstraintFree ( constraint ) ;
}
@ -430,6 +430,19 @@ void destroy_child_shape(cpBody *body, cpShape *shape, void *data)
}
}
void entity_free_allocated ( Entity * e )
{
# define MAYBE_FREE(variable, free_call) \
if ( variable ! = NULL ) \
{ \
free_call ( variable ) ; \
variable = NULL ; \
}
MAYBE_FREE ( e - > shape , cpShapeFree ) ;
MAYBE_FREE ( e - > body , cpBodyFree ) ;
MAYBE_FREE ( e - > landed_constraint , cpConstraintFree ) ;
}
// Destroys the entity and puts its slot back into the free list. Doesn't obey game rules
// like making sure grids don't have holes in them, for that you want entity_destroy.
// *Does* free all owned memory/entities though, e.g grids free the boxes they own.
@ -451,25 +464,20 @@ void entity_memory_free(GameState *gs, Entity *e)
if ( e - > shape ! = NULL )
{
cpSpaceRemoveShape ( gs - > space , e - > shape ) ;
cpShapeFree ( e - > shape ) ;
e - > shape = NULL ;
}
if ( e - > landed_constraint ! = NULL )
{
cpSpaceRemoveConstraint ( gs - > space , e - > landed_constraint ) ;
cpConstraintFree ( e - > landed_constraint ) ;
e - > landed_constraint = NULL ;
}
if ( e - > body ! = NULL )
{
// need to do this here because body which constraint is attached to can be destroyed
// NOT TRUE: can't do this here because the handle to the constraint cannot be set to NULL. Constraints are freed by the entities that own them
cpBodyEachConstraint ( e - > body , destroy_constraints , NULL ) ;
// NOT TRUE: can't do this here because the handle to the constraint cannot be set to NULL. Constraints are freed by the entities that own them
cpBodyEachConstraint ( e - > body , destroy_constraints , NULL ) ;
cpBodyEachShape ( e - > body , destroy_child_shape , ( void * ) gs ) ;
cpSpaceRemoveBody ( gs - > space , e - > body ) ;
cpBodyFree ( e - > body ) ;
e - > body = NULL ;
}
entity_free_allocated ( e ) ;
Entity * front_of_free_list = get_entity ( gs , gs - > free_list ) ;
if ( front_of_free_list ! = NULL )
flight_assert ( ! front_of_free_list - > exists ) ;
@ -534,7 +542,7 @@ void create_body(GameState *gs, Entity *e)
}
// must always call this after creating a constraint
void on_create_constraint ( Entity * e , cpConstraint * c )
void on_create_constraint ( Entity * e , cpConstraint * c )
{
cpConstraintSetUserData ( c , ( cpDataPointer ) e ) ;
}
@ -595,29 +603,41 @@ static const cpShapeFilter FILTER_DEFAULT = {CP_NO_GROUP, DEFAULT, CP_ALL_CATEGO
// size is (1/2 the width, 1/2 the height)
void create_rectangle_shape ( GameState * gs , Entity * e , Entity * parent , cpVect pos , cpVect size , double mass )
{
// @Robust remove this garbage
if ( e - > shape ! = NULL )
PROFILE_SCOPE ( " Create rectangle shape " )
{
cpSpaceRemoveShape ( gs - > space , e - > shape ) ;
cpShapeFree ( e - > shape ) ;
e - > shape = NULL ;
}
cpBB box = cpBBNew ( - size . x + pos . x , - size . y + pos . y , size . x + pos . x , size . y + pos . y ) ;
cpVect verts [ 4 ] = {
cpv ( box . r , box . b ) ,
cpv ( box . r , box . t ) ,
cpv ( box . l , box . t ) ,
cpv ( box . l , box . b ) ,
} ;
// @Robust remove this garbage
if ( e - > shape ! = NULL )
{
PROFILE_SCOPE ( " Freeing shape " )
{
cpSpaceRemoveShape ( gs - > space , e - > shape ) ;
cpShapeFree ( e - > shape ) ;
e - > shape = NULL ;
}
}
e - > shape_size = size ;
e - > shape_parent_entity = get_id ( gs , parent ) ;
e - > shape = ( cpShape * ) cpPolyShapeInitRaw ( cpPolyShapeAlloc ( ) , parent - > body , 4 , verts , 0.0 ) ; // this cast is done in chipmunk, not sure why it works
cpShapeSetUserData ( e - > shape , ( void * ) e ) ;
cpShapeSetMass ( e - > shape , mass ) ;
cpSpaceAddShape ( gs - > space , e - > shape ) ;
cpShapeSetFilter ( e - > shape , FILTER_DEFAULT ) ;
cpBB box = cpBBNew ( - size . x + pos . x , - size . y + pos . y , size . x + pos . x , size . y + pos . y ) ;
cpVect verts [ 4 ] = {
cpv ( box . r , box . b ) ,
cpv ( box . r , box . t ) ,
cpv ( box . l , box . t ) ,
cpv ( box . l , box . b ) ,
} ;
e - > shape_size = size ;
e - > shape_parent_entity = get_id ( gs , parent ) ;
e - > shape = ( cpShape * ) cpPolyShapeInitRaw ( cpPolyShapeAlloc ( ) , parent - > body , 4 , verts , 0.0 ) ; // this cast is done in chipmunk, not sure why it works
cpShapeSetUserData ( e - > shape , ( void * ) e ) ;
PROFILE_SCOPE ( " Setting mass " )
{
cpShapeSetMass ( e - > shape , mass ) ;
}
PROFILE_SCOPE ( " Adding shape " )
{
cpSpaceAddShape ( gs - > space , e - > shape ) ;
}
cpShapeSetFilter ( e - > shape , FILTER_DEFAULT ) ;
}
}
void create_circle_shape ( GameState * gs , Entity * e , double radius )
{
@ -815,24 +835,22 @@ bool could_learn_from_scanner(Player *for_player, Entity *box)
return ( for_player - > box_unlocks | box - > blueprints_learned ) ! = for_player - > box_unlocks ;
}
bool box_enterable ( Entity * box )
{
return box - > box_type = = BoxMedbay | | box - > box_type = = BoxCockpit ;
}
bool box_interactible ( GameState * gs , Player * for_player , Entity * box )
{
flight_assert ( box - > is_box ) ;
if ( box - > box_type = = BoxCockpit | | box - > box_type = = BoxMedbay )
if ( box - > box_type = = Box Merge )
{
return true ;
return merge_box_is_merged ( gs , box ) ;
}
else
{
if ( box - > box_type = = BoxMerge )
{
return merge_box_is_merged ( gs , box ) ;
}
else
{
return false ;
}
return false ;
}
}
@ -1018,9 +1036,6 @@ static void on_damage(cpArbiter *arb, cpSpace *space, cpDataPointer userData)
}
}
// if(entity_a->is_missile) {getPointFunc = cpArbiterGetPointA;
// if(entity_b->is_missile) getPointFunc = cpArbiterGetPointB;
double damage = cpvlength ( ( cpArbiterTotalImpulse ( arb ) ) ) * COLLISION_DAMAGE_SCALING ;
if ( entity_a - > is_box & & entity_a - > box_type = = BoxExplosive )
@ -1030,45 +1045,45 @@ static void on_damage(cpArbiter *arb, cpSpace *space, cpDataPointer userData)
if ( damage > 0.05 )
{
// Log("Collision with damage %f\n", damage);
entity_a - > damage + = damage ;
entity_b - > damage + = damage ;
}
// b must be the key passed into the post step removed, the key is cast into its shape
// cpSpaceAddPostStepCallback(space, (cpPostStepFunc)postStepRemove, b, NULL);
// cpSpaceAddPostStepCallback(space, (cpPostStepFunc)postStepRemove, a, NULL);
}
// must be called with zero initialized game state, because copies the server side computing!
void initialize ( GameState * gs , void * entity_arena , size_t entity_arena_size )
{
bool is_server_side = gs - > server_side_computing ;
* gs = ( GameState ) { 0 } ;
memset ( entity_arena , 0 , entity_arena_size ) ; // SUPER critical. Random vals in the entity data causes big problem
gs - > entities = ( Entity * ) entity_arena ;
gs - > max_entities = ( unsigned int ) ( entity_arena_size / sizeof ( Entity ) ) ;
gs - > space = cpSpaceNew ( ) ;
cpSpaceSetUserData ( gs - > space , ( cpDataPointer ) gs ) ; // needed in the handler
cpCollisionHandler * handler = cpSpaceAddCollisionHandler ( gs - > space , 0 , 0 ) ;
handler - > postSolveFunc = on_damage ;
gs - > server_side_computing = is_server_side ;
PROFILE_SCOPE ( " Initialize " )
{
bool is_server_side = gs - > server_side_computing ;
* gs = ( GameState ) { 0 } ;
gs - > entities = ( Entity * ) entity_arena ;
gs - > max_entities = ( unsigned int ) ( entity_arena_size / sizeof ( Entity ) ) ;
gs - > space = cpSpaceNew ( ) ;
cpSpaceSetUserData ( gs - > space , ( cpDataPointer ) gs ) ; // needed in the handler
cpCollisionHandler * handler = cpSpaceAddCollisionHandler ( gs - > space , 0 , 0 ) ;
handler - > postSolveFunc = on_damage ;
gs - > server_side_computing = is_server_side ;
}
}
void destroy ( GameState * gs )
{
// can't zero out gs data because the entity memory arena is reused
// on deserialization
for ( size_t i = 0 ; i < gs - > cur_next_entity ; i + + )
PROFILE_SCOPE ( " Destroy " )
{
if ( gs - > entities [ i ] . exists )
// can't zero out gs data because the entity memory arena is reused
// on deserialization
for ( size_t i = 0 ; i < gs - > cur_next_entity ; i + + )
{
entity_memory_free ( gs , & gs - > entities [ i ] ) ;
gs - > entities [ i ] = ( Entity ) { 0 } ;
if ( gs - > entities [ i ] . exists )
{
entity_free_allocated ( & gs - > entities [ i ] ) ;
gs - > entities [ i ] = ( Entity ) { 0 } ; // IMPORTANT expects zeroed for initialize
}
}
cpSpaceFree ( gs - > space ) ;
gs - > space = NULL ;
gs - > cur_next_entity = 0 ;
}
cpSpaceFree ( gs - > space ) ;
gs - > space = NULL ;
gs - > cur_next_entity = 0 ;
}
// center of mass, not the literal position
cpVect grid_com ( Entity * grid )
@ -1399,6 +1414,7 @@ SerMaybeFailure ser_inputframe(SerState *ser, InputFrame *i)
SER_MAYBE_RETURN ( ser_entityid ( ser , & i - > invite_this_player ) ) ;
SER_VAR ( & i - > seat_action ) ;
SER_VAR ( & i - > interact_action ) ;
SER_MAYBE_RETURN ( ser_fV2 ( ser , & i - > hand_pos ) ) ;
SER_VAR ( & i - > dobuild ) ;
@ -1436,235 +1452,207 @@ SerMaybeFailure ser_player(SerState *ser, Player *p)
SerMaybeFailure ser_entity ( SerState * ser , GameState * gs , Entity * e )
{
SER_VAR ( & e - > no_save_to_disk ) ;
SER_VAR ( & e - > always_visible ) ;
SER_VAR ( & e - > generation ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > damage ) ) ;
bool has_body = ser - > serializing & & e - > body ! = NULL ;
SER_VAR ( & has_body ) ;
if ( has_body )
{
struct BodyData body_data ;
if ( ser - > serializing )
populate ( e - > body , & body_data ) ;
SER_MAYBE_RETURN ( ser_bodydata ( ser , & body_data ) ) ;
if ( ! ser - > serializing )
{
create_body ( gs , e ) ;
update_from ( e - > body , & body_data ) ;
}
}
bool has_shape = ser - > serializing & & e - > shape ! = NULL ;
SER_VAR ( & has_shape ) ;
if ( has_shape )
PROFILE_SCOPE ( " Ser entity " )
{
SER_VAR ( & e - > is_circle_shape ) ;
if ( e - > is_circle_shape )
{
SER_MAYBE_RETURN ( ser_f ( ser , & e - > shape_radius ) ) ;
}
else
{
SER_MAYBE_RETURN ( ser_fV2 ( ser , & e - > shape_size ) ) ;
}
SER_MAYBE_RETURN ( ser_entityid ( ser , & e - > shape_parent_entity ) ) ;
Entity * parent = get_entity ( gs , e - > shape_parent_entity ) ;
SER_ASSERT ( parent ! = NULL ) ;
cpVect shape_pos ;
if ( ser - > serializing )
shape_pos = entity_shape_pos ( e ) ;
SER_MAYBE_RETURN ( ser_fV2 ( ser , & shape_pos ) ) ;
SER_VAR ( & e - > no_save_to_disk ) ;
SER_VAR ( & e - > always_visible ) ;
SER_VAR ( & e - > generation ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > damage ) ) ;
double shape_mass ;
if ( ser - > serializing )
shape_mass = entity_shape_mass ( e ) ;
SER_VAR ( & shape_mass ) ;
SER_ASSERT ( ! isnan ( shape_mass ) ) ;
bool has_body = ser - > serializing & & e - > body ! = NULL ;
SER_VAR ( & has_body ) ;
cpShapeFilter filter ;
if ( ser - > serializing )
if ( has_body )
{
filter = cpShapeGetFilter ( e - > shape ) ;
struct BodyData body_data ;
if ( ser - > serializing )
populate ( e - > body , & body_data ) ;
SER_MAYBE_RETURN ( ser_bodydata ( ser , & body_data ) ) ;
if ( ! ser - > serializing )
{
create_body ( gs , e ) ;
update_from ( e - > body , & body_data ) ;
}
}
SER_VAR ( & filter . categories ) ;
SER_VAR ( & filter . group ) ;
SER_VAR ( & filter . mask ) ;
if ( ! ser - > serializing )
bool has_shape = ser - > serializing & & e - > shape ! = NULL ;
SER_VAR ( & has_shape ) ;
if ( has_shape )
{
SER_VAR ( & e - > is_circle_shape ) ;
if ( e - > is_circle_shape )
{
create_circle_shape( gs , e , e - > shape_radius ) ;
SER_MAYBE_RETURN( ser_f ( ser , & e - > shape_radius ) ) ;
}
else
{
create_rectangle_shape( gs , e , parent , shape_pos , e - > shape_size , shape_mass ) ;
SER_MAYBE_RETURN( ser_fV2 ( ser , & e - > shape_size ) ) ;
}
cpShapeSetFilter ( e - > shape , filter ) ;
}
}
if ( ! ser - > save_or_load_from_disk )
{
SER_MAYBE_RETURN ( ser_f ( ser , & e - > time_was_last_cloaked ) ) ;
}
SER_MAYBE_RETURN ( ser_entityid ( ser , & e - > shape_parent_entity ) ) ;
Entity * parent = get_entity ( gs , e - > shape_parent_entity ) ;
SER_ASSERT ( parent ! = NULL ) ;
SER_VAR ( & e - > owning_squad ) ;
cpVect shape_pos ;
if ( ser - > serializing )
shape_pos = entity_shape_pos ( e ) ;
SER_MAYBE_RETURN ( ser_fV2 ( ser , & shape_pos ) ) ;
SER_VAR ( & e - > is_player ) ;
if ( e - > is_player )
{
SER_ASSERT ( e - > no_save_to_disk ) ;
double shape_mass ;
if ( ser - > serializing )
shape_mass = entity_shape_mass ( e ) ;
SER_VAR ( & shape_mass ) ;
SER_ASSERT ( ! isnan ( shape_mass ) ) ;
SER_MAYBE_RETURN ( ser_entityid ( ser , & e - > currently_inside_of_box ) ) ;
SER_VAR ( & e - > squad_invited_to ) ;
cpShapeFilter filter ;
if ( ser - > serializing )
{
filter = cpShapeGetFilter ( e - > shape ) ;
}
SER_VAR ( & filter . categories ) ;
SER_VAR ( & filter . group ) ;
SER_VAR ( & filter . mask ) ;
if ( ! ser - > serializing )
{
if ( e - > is_circle_shape )
{
create_circle_shape ( gs , e , e - > shape_radius ) ;
}
else
{
create_rectangle_shape ( gs , e , parent , shape_pos , e - > shape_size , shape_mass ) ;
}
cpShapeSetFilter ( e - > shape , filter ) ;
}
}
if ( ser - > version < VNoGold )
if ( ! ser - > save_or_load_from_disk )
{
double goldness ;
SER_VAR_NAME ( & goldness , " &e->goldness " ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > time_was_last_cloaked ) ) ;
}
}
SER_VAR ( & e - > is_explosion ) ;
if ( e - > is_explosion )
{
SER_MAYBE_RETURN ( ser_V2 ( ser , & e - > explosion_pos ) ) ;
SER_MAYBE_RETURN ( ser_V2 ( ser , & e - > explosion_vel ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > explosion_progress ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > explosion_push_strength ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > explosion_radius ) ) ;
}
SER_VAR ( & e - > owning_squad ) ;
SER_VAR ( & e - > is_sun ) ;
if ( e - > is_sun )
{
SER_MAYBE_RETURN ( ser_V2 ( ser , & e - > sun_vel ) ) ;
SER_MAYBE_RETURN ( ser_V2 ( ser , & e - > sun_pos ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > sun_mass ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > sun_radius ) ) ;
if ( ser - > version > = VSafeSun )
SER_VAR ( & e - > sun_is_safe ) ;
}
SER_VAR ( & e - > is_player ) ;
if ( e - > is_player )
{
SER_ASSERT ( e - > no_save_to_disk ) ;
SER_VAR ( & e - > is_grid ) ;
if ( e - > is_grid )
{
SER_MAYBE_RETURN ( ser_f ( ser , & e - > total_energy_capacity ) ) ;
SER_MAYBE_RETURN ( ser_entityid ( ser , & e - > boxes ) ) ;
}
SER_MAYBE_RETURN ( ser_entityid ( ser , & e - > currently_inside_of_box ) ) ;
SER_VAR ( & e - > squad_invited_to ) ;
SER_VAR ( & e - > is_missile ) ;
if ( e - > is_missile )
{
SER_MAYBE_RETURN ( ser_f ( ser , & e - > time_burned_for ) ) ;
}
if ( ser - > version < VNoGold )
{
double goldness ;
SER_VAR_NAME ( & goldness , " &e->goldness " ) ;
}
}
SER_VAR ( & e - > is_orb ) ;
if ( e - > is_orb )
{
}
SER_VAR ( & e - > is_explosion ) ;
if ( e - > is_explosion )
{
SER_MAYBE_RETURN ( ser_V2 ( ser , & e - > explosion_pos ) ) ;
SER_MAYBE_RETURN ( ser_V2 ( ser , & e - > explosion_vel ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > explosion_progress ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > explosion_push_strength ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > explosion_radius ) ) ;
}
SER_VAR ( & e - > is_box ) ;
if ( e - > is_box )
{
SER_VAR ( & e - > box_type ) ;
SER_VAR ( & e - > is_platonic ) ;
SER_VAR ( & e - > is_sun ) ;
if ( e - > is_sun )
{
SER_MAYBE_RETURN ( ser_V2 ( ser , & e - > sun_vel ) ) ;
SER_MAYBE_RETURN ( ser_V2 ( ser , & e - > sun_pos ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > sun_mass ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > sun_radius ) ) ;
if ( ser - > version > = VSafeSun )
SER_VAR ( & e - > sun_is_safe ) ;
}
SER_VAR ( & e - > owning_squad ) ;
SER_VAR ( & e - > is_grid ) ;
if ( e - > is_grid )
{
SER_MAYBE_RETURN ( ser_f ( ser , & e - > total_energy_capacity ) ) ;
SER_MAYBE_RETURN ( ser_entityid ( ser , & e - > boxes ) ) ;
}
SER_MAYBE_RETURN ( ser_entityid ( ser , & e - > next_box ) ) ;
SER_MAYBE_RETURN ( ser_entityid ( ser , & e - > prev_box ) ) ;
SER_VAR ( & e - > compass_rotation ) ;
SER_VAR ( & e - > indestructible ) ;
switch ( e - > box_type )
SER_VAR ( & e - > is_missile ) ;
if ( e - > is_missile )
{
case BoxMedbay :
case BoxCockpit :
if ( ! ser - > save_or_load_from_disk )
SER_MAYBE_RETURN ( ser_entityid ( ser , & e - > player_who_is_inside_of_me ) ) ;
break ;
case BoxThruster :
SER_MAYBE_RETURN ( ser_f ( ser , & e - > thrust ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > wanted_thrust ) ) ;
break ;
case BoxGyroscope :
SER_MAYBE_RETURN ( ser_f ( ser , & e - > thrust ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > wanted_thrust ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > gyrospin_angle ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > gyrospin_velocity ) ) ;
break ;
case BoxBattery :
SER_MAYBE_RETURN ( ser_f ( ser , & e - > energy_used ) ) ;
break ;
case BoxSolarPanel :
SER_MAYBE_RETURN ( ser_f ( ser , & e - > sun_amount ) ) ;
break ;
case BoxScanner :
SER_MAYBE_RETURN ( ser_entityid ( ser , & e - > currently_scanning ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > currently_scanning_progress ) ) ;
SER_VAR ( & e - > blueprints_learned ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > scanner_head_rotate ) ) ;
for ( int i = 0 ; i < SCANNER_MAX_PLATONICS ; i + + )
{
SER_MAYBE_RETURN ( ser_V2 ( ser , & e - > detected_platonics [ i ] . direction ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > detected_platonics [ i ] . intensity ) ) ;
}
for ( int i = 0 ; i < SCANNER_MAX_POINTS ; i + + )
{
SER_VAR ( & e - > scanner_points [ i ] ) ;
}
break ;
case BoxCloaking :
SER_MAYBE_RETURN ( ser_f ( ser , & e - > cloaking_power ) ) ;
break ;
case BoxMissileLauncher :
SER_MAYBE_RETURN ( ser_f ( ser , & e - > missile_construction_charge ) ) ;
break ;
case BoxLandingGear :
SER_MAYBE_RETURN ( ser_f ( ser , & e - > time_burned_for ) ) ;
}
SER_VAR ( & e - > is_orb ) ;
if ( e - > is_orb )
{
bool is_null = e - > landed_constraint = = NULL ;
SER_VAR ( & is_null ) ;
if ( ! is_null )
}
SER_VAR ( & e - > is_box ) ;
if ( e - > is_box )
{
SER_VAR ( & e - > box_type ) ;
SER_VAR ( & e - > is_platonic ) ;
SER_VAR ( & e - > owning_squad ) ;
SER_MAYBE_RETURN ( ser_entityid ( ser , & e - > next_box ) ) ;
SER_MAYBE_RETURN ( ser_entityid ( ser , & e - > prev_box ) ) ;
SER_VAR ( & e - > compass_rotation ) ;
SER_VAR ( & e - > indestructible ) ;
switch ( e - > box_type )
{
EntityID from = { 0 } ;
EntityID to = { 0 } ;
cpVect pin = { 0 } ;
if ( ser - > serializing )
case BoxMedbay :
case BoxCockpit :
if ( ! ser - > save_or_load_from_disk )
SER_MAYBE_RETURN ( ser_entityid ( ser , & e - > player_who_is_inside_of_me ) ) ;
break ;
case BoxThruster :
SER_MAYBE_RETURN ( ser_f ( ser , & e - > thrust ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > wanted_thrust ) ) ;
break ;
case BoxGyroscope :
SER_MAYBE_RETURN ( ser_f ( ser , & e - > thrust ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > wanted_thrust ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > gyrospin_angle ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > gyrospin_velocity ) ) ;
break ;
case BoxBattery :
SER_MAYBE_RETURN ( ser_f ( ser , & e - > energy_used ) ) ;
break ;
case BoxSolarPanel :
SER_MAYBE_RETURN ( ser_f ( ser , & e - > sun_amount ) ) ;
break ;
case BoxScanner :
SER_MAYBE_RETURN ( ser_entityid ( ser , & e - > currently_scanning ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > currently_scanning_progress ) ) ;
SER_VAR ( & e - > blueprints_learned ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > scanner_head_rotate ) ) ;
for ( int i = 0 ; i < SCANNER_MAX_PLATONICS ; i + + )
{
from = get_id ( gs , cp_body_entity ( cpConstraintGetBodyA ( e - > landed_constraint ) ) ) ;
to = get_id ( gs , cp_body_entity ( cpConstraintGetBodyB ( e - > landed_constraint ) ) ) ;
pin = cpPivotJointGetAnchorA ( e - > landed_constraint ) ;
SER_MAYBE_RETURN ( ser_V2 ( ser , & e - > detected_platonics [ i ] . direction ) ) ;
SER_MAYBE_RETURN ( ser_f ( ser , & e - > detected_platonics [ i ] . intensity ) ) ;
}
SER_MAYBE_RETURN ( ser_entityid ( ser , & from ) ) ;
SER_MAYBE_RETURN ( ser_entityid ( ser , & to ) ) ;
SER_MAYBE_RETURN ( ser_V2 ( ser , & pin ) ) ;
if ( ! ser - > serializing )
for ( int i = 0 ; i < SCANNER_MAX_POINTS ; i + + )
{
Entity * from_entity = get_entity ( gs , from ) ;
Entity * to_entity = get_entity ( gs , to ) ;
if ( from_entity = = NULL | | to_entity = = NULL )
{
}
else
{
e - > landed_constraint = cpPivotJointNew ( from_entity - > body , to_entity - > body , pin ) ;
cpSpaceAddConstraint ( gs - > space , e - > landed_constraint ) ;
on_create_constraint ( e , e - > landed_constraint ) ;
}
SER_VAR ( & e - > scanner_points [ i ] ) ;
}
break ;
case BoxCloaking :
SER_MAYBE_RETURN ( ser_f ( ser , & e - > cloaking_power ) ) ;
break ;
case BoxMissileLauncher :
SER_MAYBE_RETURN ( ser_f ( ser , & e - > missile_construction_charge ) ) ;
break ;
case BoxLandingGear :
{
SER_MAYBE_RETURN ( ser_entityid ( ser , & e - > shape_to_land_on ) ) ;
break ;
}
default :
break ;
}
break ;
}
default :
break ;
}
}
return ser_ok ;
}
@ -2571,6 +2559,7 @@ void create_initial_world(GameState *gs)
# endif // debug world
}
// does not actually set seat in variables so can be used on respawn
void exit_seat ( GameState * gs , Entity * seat_in , Entity * p )
{
cpVect pilot_seat_exit_spot = cpvadd ( entity_pos ( seat_in ) , cpvmult ( box_facing_vector ( seat_in ) , BOX_SIZE ) ) ;
@ -2727,7 +2716,31 @@ void process(struct GameState *gs, double dt)
p - > damage = 0.0 ;
# endif
# if 1
cpVect world_hand_pos = get_world_hand_pos ( gs , & player - > input , p ) ;
if ( player - > input . interact_action )
{
player - > input . interact_action = false ;
cpPointQueryInfo query_info = { 0 } ;
cpShape * result = cpSpacePointQueryNearest ( gs - > space , ( world_hand_pos ) , 0.1 , FILTER_ONLY_BOXES , & query_info ) ;
if ( result ! = NULL )
{
Entity * potential_seat = cp_shape_entity ( result ) ;
flight_assert ( potential_seat - > is_box ) ;
// IMPORTANT: if you update these, make sure you update box_interactible so
// the button prompt still works
if ( potential_seat - > box_type = = BoxMerge ) // disconnect!
{
potential_seat - > wants_disconnect = true ;
grid_correct_for_holes ( gs , box_grid ( potential_seat ) ) ;
flight_assert ( potential_seat - > exists ) ;
flight_assert ( potential_seat - > is_box ) ;
flight_assert ( potential_seat - > box_type = = BoxMerge ) ;
}
}
}
if ( player - > input . seat_action )
{
player - > input . seat_action = false ; // "handle" the input
@ -2740,21 +2753,8 @@ void process(struct GameState *gs, double dt)
{
Entity * potential_seat = cp_shape_entity ( result ) ;
flight_assert ( potential_seat - > is_box ) ;
// IMPORTANT: if you update these, make sure you update box_interactible so
// IMPORTANT: if you update these, make sure you update box_enterable so
// the button prompt still works
if ( potential_seat - > box_type = = BoxScanner ) // learn everything from the scanner
{
player - > box_unlocks | = potential_seat - > blueprints_learned ;
}
if ( potential_seat - > box_type = = BoxMerge ) // disconnect!
{
potential_seat - > wants_disconnect = true ;
grid_correct_for_holes ( gs , box_grid ( potential_seat ) ) ;
flight_assert ( potential_seat - > exists ) ;
flight_assert ( potential_seat - > is_box ) ;
flight_assert ( potential_seat - > box_type = = BoxMerge ) ;
}
if ( potential_seat - > box_type = = BoxCockpit | | potential_seat - > box_type = = BoxMedbay )
{
// don't let players get inside of cockpits that somebody else is already inside of
@ -2934,6 +2934,7 @@ void process(struct GameState *gs, double dt)
PROFILE_SCOPE ( " process entities " )
{
ENTITIES_ITER ( gs , e )
if ( ! e - > flag_for_destruction )
{
if ( e - > body ! = NULL & & cpvlengthsq ( ( entity_pos ( e ) ) ) > ( INSTANT_DEATH_DISTANCE_FROM_CENTER * INSTANT_DEATH_DISTANCE_FROM_CENTER ) )
{
@ -3198,6 +3199,8 @@ void process(struct GameState *gs, double dt)
// PROFILE_SCOPE("Grid processing")
{
Entity * grid = e ;
float e ; // turn all references to e into errors
( void ) e ;
// calculate how much energy solar panels provide
double energy_to_add = 0.0 ;
BOXES_ITER ( gs , cur_box , grid )
@ -3239,6 +3242,7 @@ void process(struct GameState *gs, double dt)
// use the energy, stored in the batteries, in various boxes
BOXES_ITER ( gs , cur_box , grid )
{
if ( cur_box - > box_type = = BoxThruster )
{
cur_box - > energy_effectiveness = batteries_use_energy ( gs , grid , & non_battery_energy_left_over , cur_box - > wanted_thrust * THRUSTER_ENERGY_USED_PER_SECOND * dt ) ;
@ -3494,8 +3498,49 @@ void process(struct GameState *gs, double dt)
}
if ( cur_box - > box_type = = BoxLandingGear )
{
if ( cur_box - > landed_constraint = = NULL )
cpVect landing_point = cpvadd ( entity_pos ( cur_box ) , cpvmult ( box_facing_vector ( cur_box ) , BOX_SIZE / 2.0 ) ) ;
Entity * must_have_shape = get_entity ( gs , cur_box - > shape_to_land_on ) ;
bool want_have_constraint = true ;
if ( want_have_constraint )
want_have_constraint & = must_have_shape ! = NULL ;
if ( want_have_constraint )
want_have_constraint & = must_have_shape - > shape ! = NULL ;
if ( want_have_constraint )
want_have_constraint & = cpShapeGetBody ( must_have_shape - > shape ) ! = NULL ;
if ( want_have_constraint )
want_have_constraint & = cpvdist ( entity_pos ( must_have_shape ) , landing_point ) < BOX_SIZE + LANDING_GEAR_MAX_DIST ;
# define DELETE_CONSTRAINT(constraint) \
{ \
cpSpaceRemoveConstraint ( gs - > space , constraint ) ; \
cpConstraintFree ( constraint ) ; \
constraint = NULL ; \
}
if ( want_have_constraint )
{
flight_assert ( must_have_shape ! = NULL ) ;
cpBody * body_a = box_grid ( cur_box ) - > body ;
cpBody * body_b = cpShapeGetBody ( must_have_shape - > shape ) ;
if ( cur_box - > landed_constraint ! = NULL & & ( cpConstraintGetBodyA ( cur_box - > landed_constraint ) ! = body_a | | cpConstraintGetBodyB ( cur_box - > landed_constraint ) ! = body_b ) )
{
DELETE_CONSTRAINT ( cur_box - > landed_constraint ) ;
}
if ( cur_box - > landed_constraint = = NULL )
{
cur_box - > landed_constraint = cpPivotJointNew ( body_a , body_b , landing_point ) ;
cpSpaceAddConstraint ( gs - > space , cur_box - > landed_constraint ) ;
on_create_constraint ( cur_box , cur_box - > landed_constraint ) ;
}
}
else
{
if ( cur_box - > landed_constraint ! = NULL )
{
DELETE_CONSTRAINT ( cur_box - > landed_constraint ) ;
}
cur_box - > shape_to_land_on = ( EntityID ) { 0 } ;
// maybe see something to land on
cpVect along = box_facing_vector ( cur_box ) ;
cpVect from = cpvadd ( entity_pos ( cur_box ) , cpvmult ( along , BOX_SIZE / 2.0 + 0.03 ) ) ;
cpVect to = cpvadd ( from , cpvmult ( along , LANDING_GEAR_MAX_DIST ) ) ;
@ -3504,12 +3549,7 @@ void process(struct GameState *gs, double dt)
cpShape * found = cpSpaceSegmentQueryFirst ( gs - > space , from , to , 0.0 , FILTER_DEFAULT , & query_result ) ;
if ( found ! = NULL & & cpShapeGetBody ( found ) ! = box_grid ( cur_box ) - > body )
{
cpVect anchor = cpvadd ( entity_pos ( cur_box ) , cpvmult ( along , BOX_SIZE / 2.0 ) ) ;
cpBody * a = box_grid ( cur_box ) - > body ;
cpBody * b = cpShapeGetBody ( found ) ;
cur_box - > landed_constraint = cpPivotJointNew ( a , b , anchor ) ;
cpSpaceAddConstraint ( gs - > space , cur_box - > landed_constraint ) ;
on_create_constraint ( cur_box , cur_box - > landed_constraint ) ;
cur_box - > shape_to_land_on = get_id ( gs , cp_shape_entity ( found ) ) ;
}
}
}