fp: Implement the plane

This commit is contained in:
doyle 2023-10-07 20:31:01 +11:00
parent 15a591dcb7
commit 8ebbb64877
4 changed files with 198 additions and 101 deletions

View File

@ -160,6 +160,7 @@ static void FP_Game_MoveEntity(FP_Game *game, FP_GameEntityHandle entity_handle,
Dqn_f32 global_earliest_t = SENTINEL_T; Dqn_f32 global_earliest_t = SENTINEL_T;
Dqn_V2 global_earliest_pos_just_before_collide = {}; Dqn_V2 global_earliest_pos_just_before_collide = {};
if ((entity->flags & FP_GameEntityFlag_NoClip) == 0) {
for (FP_GameEntityIterator collider_it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &collider_it, game->root_entity); ) { for (FP_GameEntityIterator collider_it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &collider_it, game->root_entity); ) {
FP_GameEntity *collider = collider_it.entity; FP_GameEntity *collider = collider_it.entity;
if (collider->handle == entity->handle) if (collider->handle == entity->handle)
@ -267,6 +268,8 @@ static void FP_Game_MoveEntity(FP_Game *game, FP_GameEntityHandle entity_handle,
global_earliest_pos_just_before_collide = entity_pos + (d * earliest_t); global_earliest_pos_just_before_collide = entity_pos + (d * earliest_t);
} }
} }
}
if (global_earliest_t == SENTINEL_T) { if (global_earliest_t == SENTINEL_T) {
entity->local_pos += delta_pos; entity->local_pos += delta_pos;
@ -444,13 +447,14 @@ void TELY_DLL_Init(void *user_data)
} }
FP_Entity_CreateClubTerry(game, Dqn_V2_InitNx2(+500, -191), "Club Terry"); 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_CreateKennelTerry(game, Dqn_V2_InitNx2(-300, -191), "Kennel Terry");
FP_Entity_CreateChurchTerry(game, Dqn_V2_InitNx2(-800, -191), "Church 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; game->tile_size = 37;
Dqn_V2I max_tile = platform->core.window_size / game->tile_size; Dqn_V2I max_tile = platform->core.window_size / game->tile_size;
// NOTE: Mid lane mob spawner ================================================================== // NOTE: Mid lane mob spawner ==================================================================
Dqn_V2 base_mid_p = Dqn_V2_InitNx2(1580, 0.f); 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); 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_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_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); FP_Game_PopParentEntity(game);
Dqn_FArray_Add(&game->mob_spawners, mob_spawner);
} }
// NOTE: Bottom lane 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, 0.f), "Waypoint");
FP_Entity_CreateWaypointF(game, Dqn_V2_InitNx2(-bottom_lane_mob_spawner_pos.x + base_mid_p.x, -932.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); FP_Game_PopParentEntity(game);
Dqn_FArray_Add(&game->mob_spawners, mob_spawner);
} }
// NOTE: Top lane 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, 0.f), "Waypoint");
FP_Entity_CreateWaypointF(game, Dqn_V2_InitNx2(-top_lane_mob_spawner_pos.x + base_mid_p.x, +915.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); FP_Game_PopParentEntity(game);
Dqn_FArray_Add(&game->mob_spawners, mob_spawner);
} }
#endif #endif
@ -993,17 +999,63 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
} }
if (action_has_finished) { if (action_has_finished) {
if (!FP_Game_IsNilEntityHandle(game, entity->building_patron)) { Dqn_V2 world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle);
FP_GameEntity *patron = FP_Game_GetEntity(game, entity->building_patron); FP_GameEntityHandle plane_handle = FP_Entity_CreateAirportTerryPlane(game, world_pos, "Aiport Terry Plane");
patron->flags &= ~FP_GameEntityFlag_OccupiedInBuilding; 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 = {}; 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); FP_Game_EntityTransitionState(game, entity, FP_EntityAirportTerryState_Idle);
} }
} break; } break;
} }
} 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: { case FP_EntityType_Catfish: {
FP_EntityCatfishState *state = DQN_CAST(FP_EntityCatfishState *) & action->state; FP_EntityCatfishState *state = DQN_CAST(FP_EntityCatfishState *) & action->state;
switch (*state) { switch (*state) {
@ -1232,6 +1284,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
entity->attack_box_size = {}; entity->attack_box_size = {};
} }
} break; } 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_ChurchTerry: break;
case FP_EntityType_KennelTerry: break; case FP_EntityType_KennelTerry: break;
case FP_EntityType_PhoneMessageProjectile: break; case FP_EntityType_PhoneMessageProjectile: break;
case FP_EntityType_AirportTerryPlane: break;
} }
if (move_entity) { 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)) { if (FP_Game_IsNilEntityHandle(game, building->building_patron)) {
building->building_patron = entity->handle; 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) { if (building->type == FP_EntityType_ClubTerry) {
FP_Game_EntityTransitionState(game, building, FP_EntityClubTerryState_PartyTime); 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) { } else if (building->type == FP_EntityType_AirportTerry) {
FP_Game_EntityTransitionState(game, building, FP_EntityAirportTerryState_FlyPassenger); 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 { } else {
DQN_ASSERT(building->type == FP_EntityType_ChurchTerry); DQN_ASSERT(building->type == FP_EntityType_ChurchTerry);
FP_Game_EntityTransitionState(game, building, FP_EntityChurchTerryState_ConvertPatron); FP_Game_EntityTransitionState(game, building, FP_EntityChurchTerryState_ConvertPatron);
} }
entity->flags |= FP_GameEntityFlag_OccupiedInBuilding; 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; can_attack = false;
FP_SentinelList_Erase(&entity->waypoints, waypoint_link, game->chunk_pool); FP_SentinelList_Erase(&entity->waypoints, waypoint_link, game->chunk_pool);
FP_SentinelList_Add(&entity->buildings_visited, game->chunk_pool, building->handle); FP_SentinelList_Add(&entity->buildings_visited, game->chunk_pool, building->handle);

View File

@ -7,6 +7,7 @@ enum FP_EntityType
{ {
FP_EntityType_Nil, FP_EntityType_Nil,
FP_EntityType_AirportTerry, FP_EntityType_AirportTerry,
FP_EntityType_AirportTerryPlane,
FP_EntityType_Catfish, FP_EntityType_Catfish,
FP_EntityType_ChurchTerry, FP_EntityType_ChurchTerry,
FP_EntityType_Clinger, FP_EntityType_Clinger,
@ -100,6 +101,13 @@ enum FP_EntityAirportTerryState
FP_EntityAirportTerryState_FlyPassenger, FP_EntityAirportTerryState_FlyPassenger,
}; };
enum FP_EntityAirportTerryPlaneState
{
FP_EntityAirportTerryPlaneState_Nil,
FP_EntityAirportTerryPlaneState_Idle,
FP_EntityAirportTerryPlaneState_FlyPassenger,
};
enum FP_EntityChurchTerryState enum FP_EntityChurchTerryState
{ {
FP_EntityChurchTerryState_Nil, FP_EntityChurchTerryState_Nil,

View File

@ -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; result.anim_name = g_anim_names.terry_attack_phone_message;
} break; } 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; case FP_EntityType_Count: DQN_INVALID_CODE_PATH; break;
} }
@ -687,3 +692,29 @@ static FP_GameEntityHandle FP_Entity_CreatePhoneMessageProjectile(FP_Game *game,
return result; 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;
}

View File

@ -24,6 +24,7 @@ enum FP_GameEntityFlag
FP_GameEntityFlag_TTL = 1 << 16, FP_GameEntityFlag_TTL = 1 << 16,
FP_GameEntityFlag_Friendly = 1 << 17, FP_GameEntityFlag_Friendly = 1 << 17,
FP_GameEntityFlag_Foe = 1 << 18, FP_GameEntityFlag_Foe = 1 << 18,
FP_GameEntityFlag_NoClip = 1 << 19,
}; };
enum FP_GameShapeType enum FP_GameShapeType
@ -325,6 +326,8 @@ struct FP_Game
FP_GameActiveMenu active_menu; FP_GameActiveMenu active_menu;
bool build_mode_can_place_building; bool build_mode_can_place_building;
Dqn_usize build_mode_building_index; Dqn_usize build_mode_building_index;
Dqn_FArray<FP_GameEntityHandle, 4> mob_spawners;
}; };
struct FP_GameAStarNode struct FP_GameAStarNode