fp: Implement the plane
This commit is contained in:
parent
15a591dcb7
commit
8ebbb64877
257
feely_pona.cpp
257
feely_pona.cpp
@ -160,114 +160,117 @@ static void FP_Game_MoveEntity(FP_Game *game, FP_GameEntityHandle entity_handle,
|
||||
Dqn_f32 global_earliest_t = SENTINEL_T;
|
||||
Dqn_V2 global_earliest_pos_just_before_collide = {};
|
||||
|
||||
for (FP_GameEntityIterator collider_it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &collider_it, game->root_entity); ) {
|
||||
FP_GameEntity *collider = collider_it.entity;
|
||||
if (collider->handle == entity->handle)
|
||||
continue;
|
||||
if ((entity->flags & FP_GameEntityFlag_NoClip) == 0) {
|
||||
for (FP_GameEntityIterator collider_it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &collider_it, game->root_entity); ) {
|
||||
FP_GameEntity *collider = collider_it.entity;
|
||||
if (collider->handle == entity->handle)
|
||||
continue;
|
||||
|
||||
// TODO(doyle): Calculate the list of collidables at the start of the frame
|
||||
if ((collider->flags & FP_GameEntityFlag_NonTraversable) == 0)
|
||||
continue;
|
||||
// TODO(doyle): Calculate the list of collidables at the start of the frame
|
||||
if ((collider->flags & FP_GameEntityFlag_NonTraversable) == 0)
|
||||
continue;
|
||||
|
||||
bool entity_collides_with_collider = true;
|
||||
switch (entity->type) {
|
||||
case FP_EntityType_Catfish: /*FALLTHRU*/
|
||||
case FP_EntityType_Smoochie: /*FALLTHRU*/
|
||||
case FP_EntityType_Clinger: {
|
||||
if (collider->type == FP_EntityType_Smoochie || collider->type == FP_EntityType_Clinger || collider->type == FP_EntityType_Catfish) {
|
||||
entity_collides_with_collider = false;
|
||||
} else if (FP_Entity_IsBuildingForMobs(collider)) {
|
||||
#if 0
|
||||
// NOTE: We disable collision on buildings we have visited to avoid some
|
||||
// problems ...
|
||||
if (FP_SentinelList_Find(&entity->buildings_visited, collider->handle)) {
|
||||
bool entity_collides_with_collider = true;
|
||||
switch (entity->type) {
|
||||
case FP_EntityType_Catfish: /*FALLTHRU*/
|
||||
case FP_EntityType_Smoochie: /*FALLTHRU*/
|
||||
case FP_EntityType_Clinger: {
|
||||
if (collider->type == FP_EntityType_Smoochie || collider->type == FP_EntityType_Clinger || collider->type == FP_EntityType_Catfish) {
|
||||
entity_collides_with_collider = false;
|
||||
} else if (FP_Entity_IsBuildingForMobs(collider)) {
|
||||
#if 0
|
||||
// NOTE: We disable collision on buildings we have visited to avoid some
|
||||
// problems ...
|
||||
if (FP_SentinelList_Find(&entity->buildings_visited, collider->handle)) {
|
||||
entity_collides_with_collider = false;
|
||||
}
|
||||
#else
|
||||
entity_collides_with_collider = false;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
entity_collides_with_collider = false;
|
||||
#endif
|
||||
}
|
||||
} break;
|
||||
} break;
|
||||
|
||||
case FP_EntityType_Terry: {
|
||||
// NOTE: Don't collide with mobs when dashing (e.g. phase through)
|
||||
FP_EntityTerryState state = *DQN_CAST(FP_EntityTerryState *)&entity->action.state;
|
||||
if (state == FP_EntityTerryState_Dash) {
|
||||
if (collider->type == FP_EntityType_Smoochie || collider->type == FP_EntityType_Clinger || collider->type == FP_EntityType_Catfish)
|
||||
entity_collides_with_collider = false;
|
||||
}
|
||||
} break;
|
||||
case FP_EntityType_Terry: {
|
||||
// NOTE: Don't collide with mobs when dashing (e.g. phase through)
|
||||
FP_EntityTerryState state = *DQN_CAST(FP_EntityTerryState *)&entity->action.state;
|
||||
if (state == FP_EntityTerryState_Dash) {
|
||||
if (collider->type == FP_EntityType_Smoochie || collider->type == FP_EntityType_Clinger || collider->type == FP_EntityType_Catfish)
|
||||
entity_collides_with_collider = false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case FP_EntityType_Nil: break;
|
||||
case FP_EntityType_MerchantTerry: break;
|
||||
case FP_EntityType_Count: break;
|
||||
case FP_EntityType_ClubTerry: break;
|
||||
case FP_EntityType_Map: break;
|
||||
case FP_EntityType_MerchantGraveyard: break;
|
||||
case FP_EntityType_MerchantGym: break;
|
||||
case FP_EntityType_MerchantPhoneCompany: break;
|
||||
case FP_EntityType_Heart: break;
|
||||
case FP_EntityType_AirportTerry: break;
|
||||
case FP_EntityType_ChurchTerry: break;
|
||||
case FP_EntityType_KennelTerry: break;
|
||||
case FP_EntityType_PhoneMessageProjectile: break;
|
||||
}
|
||||
case FP_EntityType_Nil: break;
|
||||
case FP_EntityType_MerchantTerry: break;
|
||||
case FP_EntityType_Count: break;
|
||||
case FP_EntityType_ClubTerry: break;
|
||||
case FP_EntityType_Map: break;
|
||||
case FP_EntityType_MerchantGraveyard: break;
|
||||
case FP_EntityType_MerchantGym: break;
|
||||
case FP_EntityType_MerchantPhoneCompany: break;
|
||||
case FP_EntityType_Heart: break;
|
||||
case FP_EntityType_AirportTerry: break;
|
||||
case FP_EntityType_ChurchTerry: break;
|
||||
case FP_EntityType_KennelTerry: break;
|
||||
case FP_EntityType_PhoneMessageProjectile: break;
|
||||
}
|
||||
|
||||
if (!entity_collides_with_collider)
|
||||
continue;
|
||||
if (!entity_collides_with_collider)
|
||||
continue;
|
||||
|
||||
// NOTE: Sweep collider with half the radius of the source entity
|
||||
Dqn_Rect collider_world_hit_box = FP_Game_CalcEntityWorldHitBox(game, collider->handle);
|
||||
if (Dqn_V2_Area(collider_world_hit_box.size) <= 0)
|
||||
continue;
|
||||
// NOTE: Sweep collider with half the radius of the source entity
|
||||
Dqn_Rect collider_world_hit_box = FP_Game_CalcEntityWorldHitBox(game, collider->handle);
|
||||
if (Dqn_V2_Area(collider_world_hit_box.size) <= 0)
|
||||
continue;
|
||||
|
||||
Dqn_Rect swept_collider_world_hit_box = collider_world_hit_box;
|
||||
swept_collider_world_hit_box.pos -= (entity_world_hit_box.size * .5f);
|
||||
swept_collider_world_hit_box.size += entity_world_hit_box.size;
|
||||
Dqn_Rect swept_collider_world_hit_box = collider_world_hit_box;
|
||||
swept_collider_world_hit_box.pos -= (entity_world_hit_box.size * .5f);
|
||||
swept_collider_world_hit_box.size += entity_world_hit_box.size;
|
||||
|
||||
if (!Dqn_Rect_ContainsPoint(swept_collider_world_hit_box, entity_new_pos))
|
||||
continue;
|
||||
if (!Dqn_Rect_ContainsPoint(swept_collider_world_hit_box, entity_new_pos))
|
||||
continue;
|
||||
|
||||
Dqn_f32 collider_left_wall_x = swept_collider_world_hit_box.pos.x;
|
||||
Dqn_f32 collider_right_wall_x = swept_collider_world_hit_box.pos.x + swept_collider_world_hit_box.size.w;
|
||||
Dqn_f32 collider_top_wall_y = swept_collider_world_hit_box.pos.y;
|
||||
Dqn_f32 collider_bottom_wall_y = swept_collider_world_hit_box.pos.y + swept_collider_world_hit_box.size.h;
|
||||
Dqn_f32 collider_left_wall_x = swept_collider_world_hit_box.pos.x;
|
||||
Dqn_f32 collider_right_wall_x = swept_collider_world_hit_box.pos.x + swept_collider_world_hit_box.size.w;
|
||||
Dqn_f32 collider_top_wall_y = swept_collider_world_hit_box.pos.y;
|
||||
Dqn_f32 collider_bottom_wall_y = swept_collider_world_hit_box.pos.y + swept_collider_world_hit_box.size.h;
|
||||
|
||||
Dqn_V2 o = entity_pos;
|
||||
Dqn_V2 d = delta_pos;
|
||||
Dqn_V2 o = entity_pos;
|
||||
Dqn_V2 d = delta_pos;
|
||||
|
||||
// NOTE: Solve collision by determining the 't' value at which
|
||||
// we hit one of the walls of the collider and move the entity
|
||||
// at exactly that point.
|
||||
// O + td = x
|
||||
// td = x - O
|
||||
// t = (x - O) / d
|
||||
// NOTE: Solve collision by determining the 't' value at which
|
||||
// we hit one of the walls of the collider and move the entity
|
||||
// at exactly that point.
|
||||
// O + td = x
|
||||
// td = x - O
|
||||
// t = (x - O) / d
|
||||
|
||||
Dqn_f32 earliest_t = SENTINEL_T;
|
||||
if (d.x != 0.f) {
|
||||
Dqn_f32 left_t = (collider_left_wall_x - o.x) / d.x;
|
||||
Dqn_f32 right_t = (collider_right_wall_x - o.x) / d.x;
|
||||
if (left_t >= 0.f && left_t <= 1.f)
|
||||
earliest_t = DQN_MIN(earliest_t, left_t);
|
||||
if (right_t >= 0.f && right_t <= 1.f)
|
||||
earliest_t = DQN_MIN(earliest_t, right_t);
|
||||
}
|
||||
Dqn_f32 earliest_t = SENTINEL_T;
|
||||
if (d.x != 0.f) {
|
||||
Dqn_f32 left_t = (collider_left_wall_x - o.x) / d.x;
|
||||
Dqn_f32 right_t = (collider_right_wall_x - o.x) / d.x;
|
||||
if (left_t >= 0.f && left_t <= 1.f)
|
||||
earliest_t = DQN_MIN(earliest_t, left_t);
|
||||
if (right_t >= 0.f && right_t <= 1.f)
|
||||
earliest_t = DQN_MIN(earliest_t, right_t);
|
||||
}
|
||||
|
||||
if (d.y != 0.f) {
|
||||
Dqn_f32 top_t = (collider_top_wall_y - o.y) / d.y;
|
||||
Dqn_f32 bottom_t = (collider_bottom_wall_y - o.y) / d.y;
|
||||
if (top_t >= 0.f && top_t <= 1.f)
|
||||
earliest_t = DQN_MIN(earliest_t, top_t);
|
||||
if (bottom_t >= 0.f && bottom_t <= 1.f)
|
||||
earliest_t = DQN_MIN(earliest_t, bottom_t);
|
||||
}
|
||||
if (d.y != 0.f) {
|
||||
Dqn_f32 top_t = (collider_top_wall_y - o.y) / d.y;
|
||||
Dqn_f32 bottom_t = (collider_bottom_wall_y - o.y) / d.y;
|
||||
if (top_t >= 0.f && top_t <= 1.f)
|
||||
earliest_t = DQN_MIN(earliest_t, top_t);
|
||||
if (bottom_t >= 0.f && bottom_t <= 1.f)
|
||||
earliest_t = DQN_MIN(earliest_t, bottom_t);
|
||||
}
|
||||
|
||||
if (earliest_t < global_earliest_t) {
|
||||
global_earliest_t = earliest_t;
|
||||
global_earliest_pos_just_before_collide = entity_pos + (d * earliest_t);
|
||||
if (earliest_t < global_earliest_t) {
|
||||
global_earliest_t = earliest_t;
|
||||
global_earliest_pos_just_before_collide = entity_pos + (d * earliest_t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (global_earliest_t == SENTINEL_T) {
|
||||
entity->local_pos += delta_pos;
|
||||
} else {
|
||||
@ -443,14 +446,15 @@ void TELY_DLL_Init(void *user_data)
|
||||
game->merchant_phone_company = FP_Entity_CreateMerchantPhoneCompany(game, base_top_right, "PhoneCompany");
|
||||
}
|
||||
|
||||
FP_Entity_CreateClubTerry(game, Dqn_V2_InitNx2(+500, -191), "Club Terry");
|
||||
FP_Entity_CreateAirportTerry(game, Dqn_V2_InitNx2(+200, -191), "Airport Terry");
|
||||
FP_Entity_CreateKennelTerry(game, Dqn_V2_InitNx2(-300, -191), "Kennel Terry");
|
||||
FP_Entity_CreateChurchTerry(game, Dqn_V2_InitNx2(-800, -191), "Church Terry");
|
||||
FP_Entity_CreateClubTerry(game, Dqn_V2_InitNx2(+500, -191), "Club Terry");
|
||||
FP_Entity_CreateKennelTerry(game, Dqn_V2_InitNx2(-300, -191), "Kennel Terry");
|
||||
FP_Entity_CreateChurchTerry(game, Dqn_V2_InitNx2(-800, -191), "Church Terry");
|
||||
FP_Entity_CreateAirportTerry(game, Dqn_V2_InitNx2(-1200, -191), "Airport Terry");
|
||||
|
||||
game->tile_size = 37;
|
||||
Dqn_V2I max_tile = platform->core.window_size / game->tile_size;
|
||||
|
||||
|
||||
// NOTE: Mid lane mob spawner ==================================================================
|
||||
Dqn_V2 base_mid_p = Dqn_V2_InitNx2(1580, 0.f);
|
||||
Dqn_V2 mid_lane_mob_spawner_pos = Dqn_V2_InitNx2(game->map->local_hit_box_size.w * -0.5f, 0.f);
|
||||
@ -460,7 +464,7 @@ void TELY_DLL_Init(void *user_data)
|
||||
FP_Game_PushParentEntity(game, mob_spawner);
|
||||
FP_Entity_CreateWaypointF(game, Dqn_V2_InitNx2(-mid_lane_mob_spawner_pos.x + base_mid_p.x, base_mid_p.y), "Waypoint");
|
||||
FP_Game_PopParentEntity(game);
|
||||
|
||||
Dqn_FArray_Add(&game->mob_spawners, mob_spawner);
|
||||
}
|
||||
|
||||
// NOTE: Bottom lane spawner ===================================================================
|
||||
@ -472,6 +476,7 @@ void TELY_DLL_Init(void *user_data)
|
||||
FP_Entity_CreateWaypointF(game, Dqn_V2_InitNx2(-bottom_lane_mob_spawner_pos.x + base_mid_p.x, 0.f), "Waypoint");
|
||||
FP_Entity_CreateWaypointF(game, Dqn_V2_InitNx2(-bottom_lane_mob_spawner_pos.x + base_mid_p.x, -932.f), "Waypoint");
|
||||
FP_Game_PopParentEntity(game);
|
||||
Dqn_FArray_Add(&game->mob_spawners, mob_spawner);
|
||||
}
|
||||
|
||||
// NOTE: Top lane spawner ===================================================================
|
||||
@ -482,6 +487,7 @@ void TELY_DLL_Init(void *user_data)
|
||||
FP_Entity_CreateWaypointF(game, Dqn_V2_InitNx2(-top_lane_mob_spawner_pos.x + base_mid_p.x, 0.f), "Waypoint");
|
||||
FP_Entity_CreateWaypointF(game, Dqn_V2_InitNx2(-top_lane_mob_spawner_pos.x + base_mid_p.x, +915.f), "Waypoint");
|
||||
FP_Game_PopParentEntity(game);
|
||||
Dqn_FArray_Add(&game->mob_spawners, mob_spawner);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -993,17 +999,63 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
|
||||
}
|
||||
|
||||
if (action_has_finished) {
|
||||
if (!FP_Game_IsNilEntityHandle(game, entity->building_patron)) {
|
||||
FP_GameEntity *patron = FP_Game_GetEntity(game, entity->building_patron);
|
||||
patron->flags &= ~FP_GameEntityFlag_OccupiedInBuilding;
|
||||
}
|
||||
Dqn_V2 world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle);
|
||||
FP_GameEntityHandle plane_handle = FP_Entity_CreateAirportTerryPlane(game, world_pos, "Aiport Terry Plane");
|
||||
FP_GameEntity *plane = FP_Game_GetEntity(game, plane_handle);
|
||||
|
||||
// NOTE: Transfer the entity to the plane
|
||||
plane->building_patron = entity->building_patron;
|
||||
entity->building_patron = {};
|
||||
|
||||
// NOTE: Add a waypoint for the plane to the mob spawn
|
||||
{
|
||||
uint32_t mob_spawner_index = Dqn_PCG32_Range(&game->rng, 0, DQN_CAST(uint32_t)game->mob_spawners.size);
|
||||
FP_GameEntityHandle mob_spawner = game->mob_spawners.data[mob_spawner_index];
|
||||
Dqn_V2 target_pos = FP_Game_CalcEntityWorldPos(game, mob_spawner);
|
||||
plane->waypoints = FP_SentinelList_Init<FP_GameWaypoint>(game->chunk_pool);
|
||||
FP_SentinelListLink<FP_GameWaypoint> *link = FP_SentinelList_MakeBefore(&plane->waypoints,
|
||||
FP_SentinelList_Front(&plane->waypoints),
|
||||
game->chunk_pool);
|
||||
FP_GameWaypoint *waypoint = &link->data;
|
||||
waypoint->entity = mob_spawner;
|
||||
waypoint->type = FP_GameWaypointType_ClosestSide;
|
||||
}
|
||||
|
||||
FP_Game_EntityTransitionState(game, entity, FP_EntityAirportTerryState_Idle);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case FP_EntityType_AirportTerryPlane: {
|
||||
FP_EntityAirportTerryPlaneState *state = DQN_CAST(FP_EntityAirportTerryPlaneState *)&action->state;
|
||||
switch (*state) {
|
||||
case FP_EntityAirportTerryPlaneState_Nil: {
|
||||
FP_Game_EntityTransitionState(game, entity, FP_EntityAirportTerryPlaneState_Idle);
|
||||
} break;
|
||||
|
||||
case FP_EntityAirportTerryPlaneState_Idle: {
|
||||
if (entering_new_state) {
|
||||
uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER;
|
||||
FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite);
|
||||
}
|
||||
|
||||
if (!FP_Game_IsNilEntityHandle(game, entity->building_patron))
|
||||
FP_Game_EntityTransitionState(game, entity, FP_EntityAirportTerryPlaneState_FlyPassenger);
|
||||
} break;
|
||||
|
||||
case FP_EntityAirportTerryPlaneState_FlyPassenger: {
|
||||
if (entity->waypoints.size == 0) {
|
||||
FP_GameEntity *patron = FP_Game_GetEntity(game, entity->building_patron);
|
||||
patron->local_pos = entity->local_pos;
|
||||
patron->flags &= ~(FP_GameEntityFlag_OccupiedInBuilding | FP_GameEntityFlag_PointOfInterestHeart);
|
||||
FP_Game_DeleteEntity(game, entity->handle);
|
||||
return;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case FP_EntityType_Catfish: {
|
||||
FP_EntityCatfishState *state = DQN_CAST(FP_EntityCatfishState *) & action->state;
|
||||
switch (*state) {
|
||||
@ -1232,6 +1284,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
|
||||
entity->attack_box_size = {};
|
||||
}
|
||||
} break;
|
||||
case FP_EntityType_AirportTerryPlane: break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1351,6 +1404,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
||||
case FP_EntityType_ChurchTerry: break;
|
||||
case FP_EntityType_KennelTerry: break;
|
||||
case FP_EntityType_PhoneMessageProjectile: break;
|
||||
case FP_EntityType_AirportTerryPlane: break;
|
||||
}
|
||||
|
||||
if (move_entity) {
|
||||
@ -1595,19 +1649,20 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
||||
if (FP_Game_IsNilEntityHandle(game, building->building_patron)) {
|
||||
building->building_patron = entity->handle;
|
||||
|
||||
Dqn_Rect hit_box = FP_Game_CalcEntityWorldHitBox(game, building->handle);
|
||||
Dqn_V2 exit_pos = Dqn_Rect_InterpolatedPoint(hit_box, Dqn_V2_InitNx2(0.5f, 1.1f));
|
||||
if (building->type == FP_EntityType_ClubTerry) {
|
||||
FP_Game_EntityTransitionState(game, building, FP_EntityClubTerryState_PartyTime);
|
||||
entity->local_pos = exit_pos; // TODO(doyle): Only works when parent world pos is 0,0
|
||||
} else if (building->type == FP_EntityType_AirportTerry) {
|
||||
FP_Game_EntityTransitionState(game, building, FP_EntityAirportTerryState_FlyPassenger);
|
||||
entity->local_pos = exit_pos; // TODO(doyle): Only works when parent world pos is 0,0
|
||||
} else {
|
||||
DQN_ASSERT(building->type == FP_EntityType_ChurchTerry);
|
||||
FP_Game_EntityTransitionState(game, building, FP_EntityChurchTerryState_ConvertPatron);
|
||||
}
|
||||
|
||||
entity->flags |= FP_GameEntityFlag_OccupiedInBuilding;
|
||||
Dqn_Rect hit_box = FP_Game_CalcEntityWorldHitBox(game, building->handle);
|
||||
Dqn_V2 exit_pos = Dqn_Rect_InterpolatedPoint(hit_box, Dqn_V2_InitNx2(0.5f, 1.1f));
|
||||
entity->local_pos = exit_pos; // TODO(doyle): Only works when parent world pos is 0,0
|
||||
can_attack = false;
|
||||
FP_SentinelList_Erase(&entity->waypoints, waypoint_link, game->chunk_pool);
|
||||
FP_SentinelList_Add(&entity->buildings_visited, game->chunk_pool, building->handle);
|
||||
|
@ -7,6 +7,7 @@ enum FP_EntityType
|
||||
{
|
||||
FP_EntityType_Nil,
|
||||
FP_EntityType_AirportTerry,
|
||||
FP_EntityType_AirportTerryPlane,
|
||||
FP_EntityType_Catfish,
|
||||
FP_EntityType_ChurchTerry,
|
||||
FP_EntityType_Clinger,
|
||||
@ -100,6 +101,13 @@ enum FP_EntityAirportTerryState
|
||||
FP_EntityAirportTerryState_FlyPassenger,
|
||||
};
|
||||
|
||||
enum FP_EntityAirportTerryPlaneState
|
||||
{
|
||||
FP_EntityAirportTerryPlaneState_Nil,
|
||||
FP_EntityAirportTerryPlaneState_Idle,
|
||||
FP_EntityAirportTerryPlaneState_FlyPassenger,
|
||||
};
|
||||
|
||||
enum FP_EntityChurchTerryState
|
||||
{
|
||||
FP_EntityChurchTerryState_Nil,
|
||||
|
@ -250,6 +250,11 @@ FP_EntityRenderData FP_Entity_GetRenderData(FP_Game *game, FP_EntityType type, u
|
||||
result.anim_name = g_anim_names.terry_attack_phone_message;
|
||||
} break;
|
||||
|
||||
case FP_EntityType_AirportTerryPlane: {
|
||||
result.height.meters = 1.5f;
|
||||
result.anim_name = g_anim_names.airport_terry_plane;
|
||||
} break;
|
||||
|
||||
case FP_EntityType_Count: DQN_INVALID_CODE_PATH; break;
|
||||
}
|
||||
|
||||
@ -687,3 +692,29 @@ static FP_GameEntityHandle FP_Entity_CreatePhoneMessageProjectile(FP_Game *game,
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static FP_GameEntityHandle FP_Entity_CreateAirportTerryPlane(FP_Game *game, Dqn_V2 pos, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args);
|
||||
FP_GameEntityHandle result = entity->handle;
|
||||
va_end(args);
|
||||
|
||||
entity->type = FP_EntityType_AirportTerryPlane;
|
||||
FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down);
|
||||
|
||||
entity->local_pos = pos;
|
||||
entity->sprite_height = render_data.height;
|
||||
entity->flags |= FP_GameEntityFlag_NoClip;
|
||||
FP_Entity_AddDebugEditorFlags(game, result);
|
||||
|
||||
entity->local_hit_box_offset = Dqn_V2_InitNx2(0, render_data.render_size.h * .1f);
|
||||
entity->local_hit_box_size = Dqn_V2_InitNx2(render_data.render_size.w, render_data.render_size.h - (render_data.render_size.h * .4f));
|
||||
entity->base_acceleration_per_s.meters = 32.f;
|
||||
|
||||
uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER;
|
||||
FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ enum FP_GameEntityFlag
|
||||
FP_GameEntityFlag_TTL = 1 << 16,
|
||||
FP_GameEntityFlag_Friendly = 1 << 17,
|
||||
FP_GameEntityFlag_Foe = 1 << 18,
|
||||
FP_GameEntityFlag_NoClip = 1 << 19,
|
||||
};
|
||||
|
||||
enum FP_GameShapeType
|
||||
@ -325,6 +326,8 @@ struct FP_Game
|
||||
FP_GameActiveMenu active_menu;
|
||||
bool build_mode_can_place_building;
|
||||
Dqn_usize build_mode_building_index;
|
||||
|
||||
Dqn_FArray<FP_GameEntityHandle, 4> mob_spawners;
|
||||
};
|
||||
|
||||
struct FP_GameAStarNode
|
||||
|
Loading…
Reference in New Issue
Block a user