@ -407,6 +407,13 @@ LauncherTarget missile_launcher_target(GameState *gs, Entity *launcher)
return ( LauncherTarget ) { . target_found = target_found , . facing_angle = to_face } ;
}
void destroy_constraints ( cpBody * body , cpConstraint * constraint , void * data )
{
( ( Entity * ) cpConstraintGetUserData ( constraint ) ) - > landed_constraint = NULL ;
cpSpaceRemoveConstraint ( cpBodyGetSpace ( body ) , constraint ) ;
cpConstraintFree ( constraint ) ;
}
void destroy_child_shape ( cpBody * body , cpShape * shape , void * data )
{
GameState * gs = ( GameState * ) data ;
@ -447,14 +454,22 @@ void entity_memory_free(GameState *gs, Entity *e)
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 ) ;
cpBodyEachShape ( e - > body , destroy_child_shape , ( void * ) gs ) ;
cpSpaceRemoveBody ( gs - > space , e - > body ) ;
cpBodyFree ( e - > body ) ;
e - > body = NULL ;
}
Entity * front_of_free_list = get_entity ( gs , gs - > free_list ) ;
if ( front_of_free_list ! = NULL )
flight_assert ( ! front_of_free_list - > exists ) ;
@ -518,6 +533,12 @@ void create_body(GameState *gs, Entity *e)
cpBodySetUserData ( e - > body , ( void * ) e ) ;
}
// must always call this after creating a constraint
void on_create_constraint ( Entity * e , cpConstraint * c )
{
cpConstraintSetUserData ( c , ( cpDataPointer ) e ) ;
}
cpVect player_vel ( GameState * gs , Entity * player )
{
flight_assert ( player - > is_player ) ;
@ -666,7 +687,7 @@ void box_add_to_boxes(GameState *gs, Entity *grid, Entity *box_to_add)
// box must be passed as a parameter as the box added to chipmunk uses this pointer in its
// user data. pos is in local coordinates. Adds the box to the grid's chain of boxes
// Must pass in a type so it knows what filter to give the collision shape
void box_ create( GameState * gs , Entity * new_box , Entity * grid , cpVect pos , enum BoxType type )
void create_box ( GameState * gs , Entity * new_box , Entity * grid , cpVect pos , enum BoxType type )
{
new_box - > is_box = true ;
flight_assert ( gs - > space ! = NULL ) ;
@ -951,7 +972,7 @@ static void grid_correct_for_holes(GameState *gs, struct Entity *grid)
cpShapeSetUserData ( cur - > shape , NULL ) ;
cur - > shape = NULL ;
box_ create( gs , cur , new_grid , new_shape_position , cur - > box_type ) ; // destroys next/prev fields on cur
create_box ( gs , cur , new_grid , new_shape_position , cur - > box_type ) ; // destroys next/prev fields on cur
cur = next ;
}
@ -1604,6 +1625,41 @@ SerMaybeFailure ser_entity(SerState *ser, GameState *gs, Entity *e)
case BoxMissileLauncher :
SER_MAYBE_RETURN ( ser_f ( ser , & e - > missile_construction_charge ) ) ;
break ;
case BoxLandingGear :
{
bool is_null = e - > landed_constraint = = NULL ;
SER_VAR ( & is_null ) ;
if ( ! is_null )
{
EntityID from = { 0 } ;
EntityID to = { 0 } ;
cpVect pin = { 0 } ;
if ( ser - > serializing )
{
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_entityid ( ser , & from ) ) ;
SER_MAYBE_RETURN ( ser_entityid ( ser , & to ) ) ;
SER_MAYBE_RETURN ( ser_V2 ( ser , & pin ) ) ;
if ( ! ser - > serializing )
{
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 ) ;
}
}
}
break ;
}
default :
break ;
}
@ -2306,7 +2362,7 @@ void create_bomb_station(GameState *gs, cpVect pos, enum BoxType platonic_type)
# define BOX_AT_TYPE(grid, pos, type) \
{ \
Entity * box = new_entity ( gs ) ; \
box_ create( gs , box , grid , pos , type ) ; \
create_box ( gs , box , grid , pos , type ) ; \
box - > compass_rotation = rot ; \
box - > indestructible = indestructible ; \
}
@ -2317,7 +2373,7 @@ void create_bomb_station(GameState *gs, cpVect pos, enum BoxType platonic_type)
grid_create ( gs , grid ) ;
entity_set_pos ( grid , pos ) ;
Entity * platonic_box = new_entity ( gs ) ;
box_ create( gs , platonic_box , grid , ( cpVect ) { 0 } , platonic_type ) ;
create_box ( gs , platonic_box , grid , ( cpVect ) { 0 } , platonic_type ) ;
platonic_box - > is_platonic = true ;
BOX_AT_TYPE ( grid , ( ( cpVect ) { BOX_SIZE , 0 } ) , BoxExplosive ) ;
BOX_AT_TYPE ( grid , ( ( cpVect ) { BOX_SIZE * 2 , 0 } ) , BoxHullpiece ) ;
@ -2355,7 +2411,7 @@ void create_hard_shell_station(GameState *gs, cpVect pos, enum BoxType platonic_
grid_create ( gs , grid ) ;
entity_set_pos ( grid , pos ) ;
Entity * platonic_box = new_entity ( gs ) ;
box_ create( gs , platonic_box , grid , ( cpVect ) { 0 } , platonic_type ) ;
create_box ( gs , platonic_box , grid , ( cpVect ) { 0 } , platonic_type ) ;
platonic_box - > is_platonic = true ;
BOX_AT_TYPE ( grid , ( ( cpVect ) { BOX_SIZE * 2 , 0 } ) , BoxHullpiece ) ;
BOX_AT_TYPE ( grid , ( ( cpVect ) { BOX_SIZE * 3 , 0 } ) , BoxHullpiece ) ;
@ -2432,7 +2488,7 @@ void create_initial_world(GameState *gs)
create_hard_shell_station ( gs , ( cpVect ) { - 5.0 , 5.0 } , BoxCloaking ) ;
# endif
# if 1 // scanner box
# if 0 // scanner box
bool indestructible = false ;
enum CompassRotation rot = Right ;
{
@ -2456,6 +2512,29 @@ void create_initial_world(GameState *gs)
# endif
# if 1 // landing gear box
bool indestructible = false ;
cpVect from = cpv ( 4.0 * BOX_SIZE , 0.0 ) ;
enum CompassRotation rot = Right ;
{
Entity * grid = new_entity ( gs ) ;
grid_create ( gs , grid ) ;
entity_set_pos ( grid , from ) ;
BOX_AT_TYPE ( grid , ( ( cpVect ) { 0.0 , 0.0 } ) , BoxLandingGear ) ;
// BOX_AT(grid, ((cpVect){0.0, -BOX_SIZE}));
// BOX_AT_TYPE(grid, ((cpVect){BOX_SIZE, 0.0}), BoxMerge);
entity_ensure_in_orbit ( gs , grid ) ;
cpBodySetVelocity ( grid - > body , cpv ( 0.1 , 0.0 ) ) ;
}
{
Entity * grid = new_entity ( gs ) ;
grid_create ( gs , grid ) ;
entity_set_pos ( grid , cpvadd ( from , cpv ( 2.0 * BOX_SIZE , 0.0 ) ) ) ;
BOX_AT_TYPE ( grid , ( ( cpVect ) { 0.0 , 0.0 } ) , BoxHullpiece ) ;
entity_ensure_in_orbit ( gs , grid ) ;
}
# endif
#if 0 // merge box
bool indestructible = false ;
double theta = deg2rad ( 65.0 ) ;
@ -2793,7 +2872,7 @@ void process(struct GameState *gs, double dt)
# if 1 // building
if ( player - > input . dobuild )
{
player - > input . dobuild = false ; // handle the input. if didn't do this, after destruction of hovered box, would try to build on it again the next frame
player - > input . dobuild = false ; // handle the input. if didn't do this, after destruction of hovered box, would try to build on it again the next frame . @Robust handle the input in one place
cpPointQueryInfo info = { 0 } ;
cpVect world_build = world_hand_pos ;
@ -2830,7 +2909,7 @@ void process(struct GameState *gs, double dt)
created_box_position = grid_world_to_local ( target_grid , world_build ) ;
}
Entity * new_box = new_entity ( gs ) ;
box_ create( gs , new_box , target_grid , created_box_position , player - > input . build_type ) ;
create_box ( gs , new_box , target_grid , created_box_position , player - > input . build_type ) ;
new_box - > owning_squad = player - > squad ;
grid_correct_for_holes ( gs , target_grid ) ; // no holey ship for you!
new_box - > compass_rotation = player - > input . build_rotation ;
@ -3097,7 +3176,7 @@ void process(struct GameState *gs, double dt)
enum CompassRotation new_rotation = facing_vector_to_compass ( from_grid , other_grid , box_facing_vector ( cur ) ) ;
cur - > compass_rotation = new_rotation ;
cpVect new_cur_pos = grid_snapped_box_pos ( from_grid , cpvadd ( snap_movement_vect , world ) ) ;
box_ create( gs , cur , from_grid , grid_world_to_local ( from_grid , new_cur_pos ) , cur - > box_type ) ; // destroys next/prev fields on cur
create_box ( gs , cur , from_grid , grid_world_to_local ( from_grid , new_cur_pos ) , cur - > box_type ) ; // destroys next/prev fields on cur
flight_assert ( box_grid ( cur ) = = box_grid ( from_merge ) ) ;
cur = next ;
}
@ -3413,6 +3492,27 @@ void process(struct GameState *gs, double dt)
cur_box - > scanner_head_rotate + = cur_box - > scanner_head_rotate_speed * dt ;
cur_box - > scanner_head_rotate = fmod ( cur_box - > scanner_head_rotate , 2.0 * PI ) ;
}
if ( cur_box - > box_type = = BoxLandingGear )
{
if ( cur_box - > landed_constraint = = NULL )
{
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 ) ) ;
cpSegmentQueryInfo query_result = { 0 } ;
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 ) ;
}
}
}
}
}
}