@ -288,60 +288,101 @@ cpVect entity_vel(GameState *gs, Entity *e)
return ( cpVect ) { 0 } ;
}
static THREADLOCAL double to_face = 0.0 ;
static THREADLOCAL double nearest_dist = INFINITY ;
static THREADLOCAL bool target_found = false ;
static void on_missile_shape ( cpShape * shape , cpContactPointSet * points , void * data )
typedef struct QueryResult
{
Entity * launcher = ( Entity * ) data ;
Entity * other = cp_shape_entity ( shape ) ;
GameState * gs = entitys_gamestate ( launcher ) ;
flight_assert ( other - > is_box | | other - > is_player | | other - > is_missile ) ;
cpShape * shape ;
cpVect pointA ;
cpVect pointB ;
} QueryResult ;
static THREADLOCAL char query_result_data [ 128 * sizeof ( QueryResult ) ] = { 0 } ;
// the data starts off NULL, on the first call sets it to result data
static THREADLOCAL Queue query_result = { . data_length = 128 * sizeof ( QueryResult ) , . element_size = sizeof ( cpShape * ) } ;
cpVect to = cpvsub ( entity_pos ( other ) , entity_pos ( launcher ) ) ;
bool should_attack = true ;
if ( other - > is_box & & box_grid ( other ) = = box_grid ( launcher ) )
should_attack = false ;
if ( other - > owning_squad = = launcher - > owning_squad )
should_attack = false ;
if ( should_attack & & cpvlength ( to ) < nearest_dist )
static void shape_query_callback ( cpShape * shape , cpContactPointSet * points , void * data )
{
flight_assert ( points - > count > = 1 ) ; // bad, not exactly sure what the points look like. Just taking the first one for now. @Robust good debug drawing for this and figure it out. Make debug rects fade away instead of only drawn for one frame, makes one off things visible
QueryResult * new = queue_push_element ( & query_result ) ;
if ( new = = NULL )
{
target_found = true ;
nearest_dist = cpvlength ( to ) ;
// lookahead by their velocity
cpVect rel_velocity = cpvsub ( entity_vel ( gs , other ) , entity_vel ( gs , launcher ) ) ;
double dist = cpvdist ( entity_pos ( other ) , entity_pos ( launcher ) ) ;
double time_of_travel = sqrt ( ( 2.0 * dist ) / ( MISSILE_BURN_FORCE / MISSILE_MASS ) ) ;
( void ) queue_pop_element ( & query_result ) ;
new = queue_push_element ( & query_result ) ;
}
new - > shape = shape ;
new - > pointA = points - > points [ 0 ] . pointA ;
new - > pointB = points - > points [ 0 ] . pointB ;
}
cpVect other_future_pos = cpvadd ( entity_pos ( other ) , cpvmult ( rel_velocity , time_of_travel ) ) ;
// shapes are pushed to query result
static void shape_query ( cpSpace * space , cpShape * shape )
{
query_result . data = query_result_data ;
queue_clear ( & query_result ) ;
cpSpaceShapeQuery ( space , shape , shape_query_callback , NULL ) ;
}
cpVect adjusted_to = cpvsub ( other_future_pos , entity_pos ( launcher ) ) ;
// shapes are pushed to query result
static void circle_query ( cpSpace * space , cpVect pos , double radius )
{
cpBody * tmp_body = cpBodyNew ( 0 , 0 ) ;
cpBodySetPosition ( tmp_body , pos ) ;
cpShape * tmp_shape = cpCircleShapeNew ( tmp_body , radius , cpv ( 0 , 0 ) ) ;
shape_query ( space , tmp_shape ) ;
cpBodyFree ( tmp_body ) ;
cpShapeFree ( tmp_shape ) ;
}
to_face = cpvangle ( adjusted_to ) ;
}
static void rect_query ( cpSpace * space , BoxCentered box )
{
cpBody * tmp_body = cpBodyNew ( 0 , 0 ) ;
cpBodySetPosition ( tmp_body , box . pos ) ;
cpBodySetAngle ( tmp_body , box . rotation ) ;
cpShape * tmp_shape = cpBoxShapeNew ( tmp_body , box . size . x * 2.0 , box . size . y * 2.0 , 0.0 ) ;
shape_query ( space , tmp_shape ) ;
cpBodyFree ( tmp_body ) ;
cpShapeFree ( tmp_shape ) ;
}
LauncherTarget missile_launcher_target ( GameState * gs , Entity * launcher )
{
to_face = 0.0 ;
cpBody * tmp = cpBodyNew ( 0.0 , 0.0 ) ;
cpBodySetPosition ( tmp , ( entity_pos ( launcher ) ) ) ;
cpShape * circle = cpCircleShapeNew ( tmp , MISSILE_RANGE , cpv ( 0 , 0 ) ) ;
double to_face = 0.0 ;
double nearest_dist = INFINITY ;
bool target_found = false ;
circle_query ( gs - > space , entity_pos ( launcher ) , MISSILE_RANGE ) ;
QUEUE_ITER ( & query_result , QueryResult , res )
{
cpShape * cur_shape = res - > shape ;
Entity * other = cp_shape_entity ( cur_shape ) ;
flight_assert ( other - > is_box | | other - > is_player | | other - > is_missile ) ;
cpVect to = cpvsub ( entity_pos ( other ) , entity_pos ( launcher ) ) ;
bool should_attack = true ;
if ( other - > is_box & & box_grid ( other ) = = box_grid ( launcher ) )
should_attack = false ;
if ( other - > owning_squad = = launcher - > owning_squad )
should_attack = false ;
if ( should_attack & & cpvlength ( to ) < nearest_dist )
{
target_found = true ;
nearest_dist = cpvlength ( to ) ;
// lookahead by their velocity
cpVect rel_velocity = cpvsub ( entity_vel ( gs , other ) , entity_vel ( gs , launcher ) ) ;
double dist = cpvdist ( entity_pos ( other ) , entity_pos ( launcher ) ) - MISSILE_SPAWN_DIST ;
nearest_dist = INFINITY ;
to_face = 0.0 ;
target_found = false ;
cpSpaceShapeQuery ( gs - > space , circle , on_missile_shape , ( void * ) launcher ) ;
double time_of_travel = sqrt ( ( 2.0 * dist ) / ( MISSILE_BURN_FORCE / MISSILE_MASS ) ) ;
cpBodyFree ( tmp ) ;
cpShapeFree ( circle ) ;
cpVect other_future_pos = cpvadd ( entity_pos ( other ) , cpvmult ( rel_velocity , time_of_travel ) ) ;
cpVect adjusted_to = cpvsub ( other_future_pos , entity_pos ( launcher ) ) ;
to_face = cpvangle ( adjusted_to ) ;
}
}
return ( LauncherTarget ) { . target_found = target_found , . facing_angle = to_face } ;
}
void on_entity_child_shape ( cpBody * body , cpShape * shape , void * data ) ;
void on_entity_child_shape ( cpBody * body , cpShape * shape , void * data ) ; // declared here bc entity_destroy circular dependency
// gs is for iterating over all child shapes and destroying those, too
static void destroy_body ( GameState * gs , cpBody * * body )
@ -437,6 +478,7 @@ EntityID create_sun(GameState *gs, Entity *new_sun, cpVect pos, cpVect vel, doub
new_sun - > sun_vel = vel ;
new_sun - > sun_mass = mass ;
new_sun - > sun_radius = radius ;
new_sun - > always_visible = true ;
return get_id ( gs , new_sun ) ;
}
@ -644,12 +686,8 @@ static void grid_correct_for_holes(GameState *gs, struct Entity *grid)
# define MAX_SEPARATE_GRIDS 8
EntityID separate_grids [ MAX_SEPARATE_GRIDS ] = { 0 } ;
int cur_separate_grid_index = 0 ;
int cur_separate_grid_size = 0 ;
int processed_boxes = 0 ;
int biggest_separate_grid_index = 0 ;
uint32_t biggest_separate_grid_length = 0 ;
// process all boxes into separate, but correctly connected, grids
while ( processed_boxes < num_boxes )
{
@ -679,7 +717,6 @@ static void grid_correct_for_holes(GameState *gs, struct Entity *grid)
{
N - > next_box = separate_grids [ cur_separate_grid_index ] ;
separate_grids [ cur_separate_grid_index ] = get_id ( gs , N ) ;
cur_separate_grid_size + + ;
processed_boxes + + ;
if ( get_id ( gs , N ) . index > biggest_box_index )
@ -741,14 +778,8 @@ static void grid_correct_for_holes(GameState *gs, struct Entity *grid)
}
}
if ( biggest_box_index > biggest_separate_grid_length )
{
biggest_separate_grid_length = biggest_box_index ;
biggest_separate_grid_index = cur_separate_grid_index ;
}
cur_separate_grid_index + + ;
flight_assert ( cur_separate_grid_index < MAX_SEPARATE_GRIDS ) ;
cur_separate_grid_size = 0 ;
}
// create new grids for all lists of boxes except for the biggest one.
@ -1052,8 +1083,17 @@ SerMaybeFailure ser_data(SerState *ser, char *data, size_t data_len, const char
{
if ( ser - > write_varnames )
{
// the name
memcpy ( ser - > bytes + ser - > cursor , var_name , var_name_len ) ;
ser - > cursor + = var_name_len ;
SER_ASSERT ( ser - > cursor < ser - > max_size ) ;
// the size, compressed to a short
SER_ASSERT ( data_len < 65535 ) ; // uh oh stinky!
uint16_t size_to_write = ( uint16_t ) data_len ;
memcpy ( ser - > bytes + ser - > cursor , & size_to_write , sizeof ( size_to_write ) ) ;
ser - > cursor + = sizeof ( size_to_write ) ;
SER_ASSERT ( ser - > cursor < ser - > max_size ) ;
}
for ( int b = 0 ; b < data_len ; b + + )
{
@ -1096,6 +1136,18 @@ SerMaybeFailure ser_data(SerState *ser, char *data, size_t data_len, const char
// now compare!
SER_ASSERT ( strcmp ( read_name , name ) = = 0 ) ;
// deserialize and check the size too!
SER_ASSERT ( data_len < 65535 ) ; // uh oh stinky!
uint16_t expected_size = ( uint16_t ) data_len ;
uint16_t got_size = 0 ;
for ( int b = 0 ; b < sizeof ( got_size ) ; b + + )
{
( ( char * ) & got_size ) [ b ] = ser - > bytes [ ser - > cursor ] ;
ser - > cursor + = 1 ;
SER_ASSERT ( ser - > cursor < = ser - > max_size ) ;
}
SER_ASSERT ( got_size = = expected_size ) ;
}
for ( int b = 0 ; b < data_len ; b + + )
{
@ -1360,6 +1412,8 @@ SerMaybeFailure ser_entity(SerState *ser, GameState *gs, Entity *e)
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 ) ) ;
@ -1478,8 +1532,6 @@ SerMaybeFailure ser_server_to_client(SerState *ser, ServerToClient *s)
SER_VAR ( & gs - > tick ) ;
SER_VAR ( & gs - > subframe_time ) ;
SER_MAYBE_RETURN ( ser_V2 ( ser , & gs - > goldpos ) ) ;
if ( ! ser - > save_or_load_from_disk ) // don't save player info to disk, this is filled on connection/disconnection
{
for ( size_t i = 0 ; i < MAX_PLAYERS ; i + + )
@ -1521,7 +1573,18 @@ SerMaybeFailure ser_server_to_client(SerState *ser, ServerToClient *s)
{
if ( ! e - > is_box & & ! e - > is_grid )
{
SER_ENTITY ( ) ;
Entity * cur_entity = e ;
bool this_entity_in_range = ser - > save_or_load_from_disk ;
this_entity_in_range | = ser - > for_player = = NULL ;
this_entity_in_range | = ( ser - > for_player ! = NULL & & cpvdistsq ( entity_pos ( ser - > for_player ) , entity_pos ( cur_entity ) ) < VISION_RADIUS * VISION_RADIUS ) ; // only in vision radius
// don't have to check if the entity is cloaked because this is checked above
if ( cur_entity - > always_visible )
this_entity_in_range = true ;
if ( this_entity_in_range )
{
SER_ENTITY ( ) ;
}
}
if ( e - > is_grid )
{
@ -1549,7 +1612,7 @@ SerMaybeFailure ser_server_to_client(SerState *ser, ServerToClient *s)
EntityID cur_id = get_id ( gs , cur_box ) ;
SER_ASSERT ( cur_id . index < gs - > max_entities ) ;
SER_VAR ( & entities_done ) ;
size_t the_index = ( size_t ) cur_id . index ; // super critical. Type of &i is size_t. @BeforePatreon add debug info in serialization for what size the expected type is, maybe string nameof the type
size_t the_index = ( size_t ) cur_id . index ; // super critical. Type of &i is size_t. Checked when write varnames is true though!
SER_VAR_NAME ( & the_index , " &i " ) ;
SER_MAYBE_RETURN ( ser_entity ( ser , gs , cur_box ) ) ;
}
@ -1709,7 +1772,7 @@ SerMaybeFailure ser_client_to_server(SerState *ser, ClientToServer *msg)
{
size_t to_skip = queue_num_elements ( msg - > input_data ) - num ;
size_t i = 0 ;
QUEUE_ITER ( msg - > input_data , cur_heade r)
QUEUE_ITER ( msg - > input_data , InputFrame, cu r)
{
if ( i < to_skip )
{
@ -1717,7 +1780,6 @@ SerMaybeFailure ser_client_to_server(SerState *ser, ClientToServer *msg)
}
else
{
InputFrame * cur = ( InputFrame * ) cur_header - > data ;
SER_MAYBE_RETURN ( ser_inputframe ( ser , cur ) ) ;
}
}
@ -1797,51 +1859,32 @@ static bool merge_filter(Entity *potential_merge)
return potential_merge - > is_box & & potential_merge - > box_type = = BoxMerge & & box_grid ( potential_merge ) ! = grid_to_exclude ;
}
static void cloaking_shield_callback_func ( cpShape * shape , cpContactPointSet * points , void * data )
{
Entity * from_cloaking_box = ( Entity * ) data ;
GameState * gs = entitys_gamestate ( from_cloaking_box ) ;
Entity * to_cloak = cp_shape_entity ( shape ) ;
to_cloak - > time_was_last_cloaked = elapsed_time ( gs ) ;
to_cloak - > last_cloaked_by_squad = from_cloaking_box - > owning_squad ;
}
// has to be global var because can only get this information
static THREADLOCAL cpShape * closest_to_point_in_radius_result = NULL ;
static THREADLOCAL double closest_to_point_in_radius_result_largest_dist = 0.0 ;
static THREADLOCAL bool ( * closest_to_point_in_radius_filter_func ) ( Entity * ) ;
static void closest_point_callback_func ( cpShape * shape , cpContactPointSet * points , void * data )
{
flight_assert ( points - > count = = 1 ) ;
Entity * e = cp_shape_entity ( shape ) ;
if ( ! e - > is_box )
return ;
if ( closest_to_point_in_radius_filter_func ! = NULL & & ! closest_to_point_in_radius_filter_func ( e ) )
return ;
double dist = cpvlength ( ( cpvsub ( points - > points [ 0 ] . pointA , points - > points [ 0 ] . pointB ) ) ) ;
// double dist = -points->points[0].distance;
if ( dist > closest_to_point_in_radius_result_largest_dist )
{
closest_to_point_in_radius_result_largest_dist = dist ;
closest_to_point_in_radius_result = shape ;
}
}
// filter func null means everything is ok, if it's not null and returns false, that means
// exclude it from the selection. This returns the closest box entity!
Entity * closest_box_to_point_in_radius ( struct GameState * gs , cpVect point , double radius , bool ( * filter_func ) ( Entity * ) )
{
closest_to_point_in_radius_result = NULL ;
closest_to_point_in_radius_result_largest_dist = 0.0 ;
closest_to_point_in_radius_filter_func = filter_func ;
cpBody * tmpbody = cpBodyNew ( 0.0 , 0.0 ) ;
cpShape * circle = cpCircleShapeNew ( tmpbody , radius , ( point ) ) ;
cpSpaceShapeQuery ( gs - > space , circle , closest_point_callback_func , NULL ) ;
cpShape * closest_to_point_in_radius_result = NULL ;
double closest_to_point_in_radius_result_largest_dist = 0.0 ;
circle_query ( gs - > space , point , radius ) ;
QUEUE_ITER ( & query_result , QueryResult , res )
{
cpShape * shape = res - > shape ;
cpShapeFree ( circle ) ;
cpBodyFree ( tmpbody ) ;
Entity * e = cp_shape_entity ( shape ) ;
if ( ! e - > is_box )
continue ;
if ( filter_func ! = NULL & & ! filter_func ( e ) )
continue ;
double dist = cpvlength ( ( cpvsub ( res - > pointA , res - > pointB ) ) ) ;
// double dist = -points->points[0].distance;
if ( dist > closest_to_point_in_radius_result_largest_dist )
{
closest_to_point_in_radius_result_largest_dist = dist ;
closest_to_point_in_radius_result = shape ;
}
}
if ( closest_to_point_in_radius_result ! = NULL )
{
@ -1861,33 +1904,23 @@ static bool scanner_filter(Entity *e)
return true ;
}
static double cur_explosion_damage = 0.0 ;
static cpVect explosion_origin = { 0 } ;
static double explosion_push_strength = 0.0 ;
static void explosion_callback_func ( cpShape * shape , cpContactPointSet * points , void * data )
{
GameState * gs = ( GameState * ) data ;
cp_shape_entity ( shape ) - > damage + = cur_explosion_damage ;
Entity * parent = get_entity ( gs , cp_shape_entity ( shape ) - > shape_parent_entity ) ;
cpVect from_pos = entity_pos ( cp_shape_entity ( shape ) ) ;
cpVect impulse = cpvmult ( cpvnormalize ( cpvsub ( from_pos , explosion_origin ) ) , explosion_push_strength ) ;
flight_assert ( parent - > body ! = NULL ) ;
cpBodyApplyImpulseAtWorldPoint ( parent - > body , ( impulse ) , ( from_pos ) ) ;
}
static void do_explosion ( GameState * gs , Entity * explosion , double dt )
{
cpBody * tmpbody = cpBodyNew ( 0.0 , 0.0 ) ;
cpShape * circle = cpCircleShapeNew ( tmpbody , explosion - > explosion_radius , ( explosion_origin ) ) ;
cur_explosion_damage = dt * EXPLOSION_DAMAGE_PER_SEC ;
explosion_origin = explosion - > explosion_pos ;
explosion_push_strength = explosion - > explosion_push_strength ;
cpSpaceShapeQuery ( gs - > space , circle , explosion_callback_func , ( void * ) gs ) ;
cpShapeFree ( circle ) ;
cpBodyFree ( tmpbody ) ;
double cur_explosion_damage = dt * EXPLOSION_DAMAGE_PER_SEC ;
cpVect explosion_origin = explosion - > explosion_pos ;
double explosion_push_strength = explosion - > explosion_push_strength ;
circle_query ( gs - > space , explosion_origin , explosion - > explosion_radius ) ;
QUEUE_ITER ( & query_result , QueryResult , res )
{
cpShape * shape = res - > shape ;
cp_shape_entity ( shape ) - > damage + = cur_explosion_damage ;
Entity * parent = get_entity ( gs , cp_shape_entity ( shape ) - > shape_parent_entity ) ;
cpVect from_pos = entity_pos ( cp_shape_entity ( shape ) ) ;
cpVect impulse = cpvmult ( cpvnormalize ( cpvsub ( from_pos , explosion_origin ) ) , explosion_push_strength ) ;
flight_assert ( parent - > body ! = NULL ) ;
cpBodyApplyImpulseAtWorldPoint ( parent - > body , ( impulse ) , ( from_pos ) ) ;
}
}
cpVect box_facing_vector ( Entity * box )
@ -2186,11 +2219,12 @@ void create_hard_shell_station(GameState *gs, cpVect pos, enum BoxType platonic_
}
void create_initial_world ( GameState * gs )
{
const double mass_multiplier = 10.0 ;
EntityID suns [ ] = {
create_sun ( gs , new_entity ( gs ) , ( ( cpVect ) { 800.0 , 0.0 } ) , ( ( cpVect ) { 0.0 , 0.0 } ) , 1000000.0 , 30.0 ) ,
create_sun ( gs , new_entity ( gs ) , ( ( cpVect ) { 800.0 , 50.0} ) , ( ( cpVect ) { 5 0.0, 0.0 } ) , 10000.0 , 20.0 ) ,
create_sun ( gs , new_entity ( gs ) , ( ( cpVect ) { 800.0 , - 50.0} ) , ( ( cpVect ) { - 5 0.0, 0.0 } ) , 10000.0 , 20.0 ) ,
create_sun ( gs , new_entity ( gs ) , ( ( cpVect ) { - 25 00.0, - 50.0 } ) , ( ( cpVect ) { 0.0 , 0.0 } ) , 100000.0 , 20.0 ) ,
create_sun ( gs , new_entity ( gs ) , ( ( cpVect ) { 800.0 , 0.0 } ) , ( ( cpVect ) { 0.0 , 0.0 } ) , 1000000.0 * mass_multiplier , 30.0 ) ,
create_sun ( gs , new_entity ( gs ) , ( ( cpVect ) { 800.0 , 100.0} ) , ( ( cpVect ) { 6 0.0, 0.0 } ) , 10000.0 * mass_multiplier , 20.0 ) ,
create_sun ( gs , new_entity ( gs ) , ( ( cpVect ) { 800.0 , - 100.0} ) , ( ( cpVect ) { - 6 0.0, 0.0 } ) , 10000.0 * mass_multiplier , 20.0 ) ,
create_sun ( gs , new_entity ( gs ) , ( ( cpVect ) { - 70 00.0, - 50.0 } ) , ( ( cpVect ) { 0.0 , 0.0 } ) , 100000.0 * mass_multiplier , 20.0 ) ,
} ;
for ( int i = 0 ; i < ARRLEN ( suns ) ; i + + )
@ -2203,7 +2237,7 @@ void create_initial_world(GameState *gs)
// create_hard_shell_station(gs, (cpVect){800.0, 400.0}, BoxGyroscope);
create_bomb_station ( gs , ( cpVect ) { 800.0 , - 800.0 } , BoxCloaking ) ;
create_bomb_station ( gs , ( cpVect ) { 1600.0 , 800.0 } , BoxMissileLauncher ) ;
create_hard_shell_station ( gs , ( cpVect ) { - 25 00.0, 200.0 } , BoxMerge ) ;
create_hard_shell_station ( gs , ( cpVect ) { - 70 00.0, 200.0 } , BoxMerge ) ;
# else
Log ( " Creating debug world \n " ) ;
// pos, mass, radius
@ -2255,12 +2289,34 @@ void exit_seat(GameState *gs, Entity *seat_in, Entity *p)
cpBodySetVelocity ( p - > body , cpBodyGetVelocity ( box_grid ( seat_in ) - > body ) ) ;
}
void shape_integrity_check ( cpShape * shape , void * data )
{
flight_assert ( cpShapeGetUserData ( shape ) ! = NULL ) ;
flight_assert ( cp_shape_entity ( shape ) - > exists ) ;
flight_assert ( cp_shape_entity ( shape ) - > shape = = shape ) ;
}
void body_integrity_check ( cpBody * body , void * data )
{
flight_assert ( cpBodyGetUserData ( body ) ! = NULL ) ;
flight_assert ( cp_body_entity ( body ) - > exists ) ;
flight_assert ( cp_body_entity ( body ) - > body = = body ) ;
}
void process ( struct GameState * gs , double dt )
{
PROFILE_SCOPE ( " Gameplay processing " )
{
flight_assert ( gs - > space ! = NULL ) ;
# ifdef CHIPMUNK_INTEGRITY_CHECK
PROFILE_SCOPE ( " Chipmunk Integrity Checks " )
{
cpSpaceEachShape ( gs - > space , shape_integrity_check , NULL ) ;
cpSpaceEachBody ( gs - > space , body_integrity_check , NULL ) ;
}
# endif
gs - > tick + + ;
PROFILE_SCOPE ( " sun gravity " )
@ -2362,13 +2418,6 @@ void process(struct GameState *gs, double dt)
# ifdef INFINITE_RESOURCES
p - > damage = 0.0 ;
# endif
// update gold win condition
if ( cpvlength ( cpvsub ( ( cpBodyGetPosition ( p - > body ) ) , gs - > goldpos ) ) < GOLD_COLLECT_RADIUS )
{
p - > goldness + = 0.1 ;
p - > damage = 0.0 ;
gs - > goldpos = ( cpVect ) { . x = hash11 ( ( float ) elapsed_time ( gs ) ) * 20.0 , . y = hash11 ( ( float ) elapsed_time ( gs ) - 13.6 ) * 20.0 } ;
}
# if 1
cpVect world_hand_pos = get_world_hand_pos ( gs , & player - > input , p ) ;
if ( player - > input . seat_action )
@ -2386,10 +2435,12 @@ void process(struct GameState *gs, double dt)
if ( potential_seat - > box_type = = BoxScanner ) // learn everything from the scanner
{
flight_assert ( box_interactible ( potential_seat - > box_type ) ) ;
player - > box_unlocks | = potential_seat - > blueprints_learned ;
}
if ( potential_seat - > box_type = = BoxMerge ) // disconnect!
{
flight_assert ( box_interactible ( potential_seat - > box_type ) ) ;
potential_seat - > wants_disconnect = true ;
grid_correct_for_holes ( gs , box_grid ( potential_seat ) ) ;
flight_assert ( potential_seat - > exists ) ;
@ -2398,6 +2449,7 @@ void process(struct GameState *gs, double dt)
}
if ( potential_seat - > box_type = = BoxCockpit | | potential_seat - > box_type = = BoxMedbay )
{
flight_assert ( box_interactible ( potential_seat - > box_type ) ) ;
// don't let players get inside of cockpits that somebody else is already inside of
if ( get_entity ( gs , potential_seat - > player_who_is_inside_of_me ) = = NULL )
{
@ -2811,6 +2863,10 @@ void process(struct GameState *gs, double dt)
{
double energy_to_consume = cur_box - > wanted_thrust * THRUSTER_ENERGY_USED_PER_SECOND * dt ;
if ( cur_box - > wanted_thrust = = 0.0 )
{
cur_box - > thrust = 0.0 ;
}
if ( energy_to_consume > 0.0 )
{
cur_box - > thrust = 0.0 ;
@ -2822,12 +2878,29 @@ void process(struct GameState *gs, double dt)
}
if ( cur_box - > box_type = = BoxGyroscope )
{
double energy_to_consume = fabs ( cur_box - > wanted_thrust * GYROSCOPE_ENERGY_USED_PER_SECOND * dt ) ;
cur_box - > gyrospin_velocity = lerp ( cur_box - > gyrospin_velocity , cur_box - > thrust * 20.0 , dt * 5.0 ) ;
cur_box - > gyrospin_angle + = cur_box - > gyrospin_velocity * dt ;
if ( cur_box - > gyrospin_angle > 2.0 * PI )
{
cur_box - > gyrospin_angle - = 2.0 * PI ;
}
if ( cur_box - > gyrospin_angle < - 2.0 * PI )
{
cur_box - > gyrospin_angle + = 2.0 * PI ;
}
if ( cur_box - > wanted_thrust = = 0.0 )
{
cur_box - > thrust = 0.0 ;
}
double thrust_to_want = cur_box - > wanted_thrust ;
if ( cur_box - > wanted_thrust = = 0.0 )
thrust_to_want = clamp ( - cpBodyGetAngularVelocity ( grid - > body ) * GYROSCOPE_PROPORTIONAL_INERTIAL_RESPONSE , - 1.0 , 1.0 ) ;
double energy_to_consume = fabs ( thrust_to_want * GYROSCOPE_ENERGY_USED_PER_SECOND * dt ) ;
if ( energy_to_consume > 0.0 )
{
cur_box - > thrust = 0.0 ;
double energy_unconsumed = batteries_use_energy ( gs , grid , & non_battery_energy_left_over , energy_to_consume ) ;
cur_box - > thrust = ( 1.0 - energy_unconsumed / energy_to_consume ) * cur_box - > wanted_thrust ;
cur_box - > thrust = ( 1.0 - energy_unconsumed / energy_to_consume ) * thrust_to_wan t;
if ( fabs ( cur_box - > thrust ) > = 0.0 )
cpBodySetTorque ( grid - > body , cpBodyGetTorque ( grid - > body ) + cur_box - > thrust * GYROSCOPE_TORQUE ) ;
}
@ -2855,15 +2928,23 @@ void process(struct GameState *gs, double dt)
else
{
cur_box - > cloaking_power = lerp ( cur_box - > cloaking_power , 1.0 , dt * 3.0 ) ;
cpBody * tmp = cpBodyNew ( 0.0 , 0.0 ) ;
cpBodySetPosition ( tmp , ( entity_pos ( cur_box ) ) ) ;
cpBodySetAngle ( tmp , entity_rotation ( cur_box ) ) ;
// subtract a little from the panel size so that boxes just at the boundary of the panel
// aren't (sometimes cloaked)/(sometimes not) from floating point imprecision
cpShape * box_shape = cpBoxShapeNew ( tmp , CLOAKING_PANEL_SIZE - 0.03 , CLOAKING_PANEL_SIZE - 0.03 , 0.0 ) ;
cpSpaceShapeQuery ( gs - > space , box_shape , cloaking_shield_callback_func , ( void * ) cur_box ) ;
cpShapeFree ( box_shape ) ;
cpBodyFree ( tmp ) ;
rect_query ( gs - > space , ( BoxCentered ) {
. pos = entity_pos ( cur_box ) ,
. rotation = entity_rotation ( cur_box ) ,
// subtract a little from the panel size so that boxes just at the boundary of the panel
// aren't (sometimes cloaked)/(sometimes not) from floating point imprecision
. size = cpv ( CLOAKING_PANEL_SIZE - 0.03 , CLOAKING_PANEL_SIZE - 0.03 ) ,
} ) ;
QUEUE_ITER ( & query_result , QueryResult , res )
{
cpShape * shape = res - > shape ;
Entity * from_cloaking_box = cur_box ;
GameState * gs = entitys_gamestate ( from_cloaking_box ) ;
Entity * to_cloak = cp_shape_entity ( shape ) ;
to_cloak - > time_was_last_cloaked = elapsed_time ( gs ) ;
to_cloak - > last_cloaked_by_squad = from_cloaking_box - > owning_squad ;
}
}
}
if ( cur_box - > box_type = = BoxMissileLauncher )
@ -2883,8 +2964,7 @@ void process(struct GameState *gs, double dt)
Entity * new_missile = new_entity ( gs ) ;
create_missile ( gs , new_missile ) ;
new_missile - > owning_squad = cur_box - > owning_squad ; // missiles have teams and attack eachother!
double missile_spawn_dist = sqrt ( ( BOX_SIZE / 2.0 ) * ( BOX_SIZE / 2.0 ) * 2.0 ) + MISSILE_COLLIDER_SIZE . x / 2.0 + 0.1 ;
cpBodySetPosition ( new_missile - > body , ( cpvadd ( entity_pos ( cur_box ) , cpvspin ( ( cpVect ) { . x = missile_spawn_dist , 0.0 } , target . facing_angle ) ) ) ) ;
cpBodySetPosition ( new_missile - > body , ( cpvadd ( entity_pos ( cur_box ) , cpvspin ( ( cpVect ) { . x = MISSILE_SPAWN_DIST , 0.0 } , target . facing_angle ) ) ) ) ;
cpBodySetAngle ( new_missile - > body , target . facing_angle ) ;
cpBodySetVelocity ( new_missile - > body , ( box_vel ( cur_box ) ) ) ;
}