fp: Make transported entities adopt the new mob spawner waypoints

This commit is contained in:
doyle 2023-10-14 12:01:22 +11:00
parent 22439814a8
commit a064dc6d09
3 changed files with 57 additions and 38 deletions

View File

@ -327,10 +327,6 @@ NamespaceIndentation: None
PackConstructorInitializers: CurrentLine PackConstructorInitializers: CurrentLine
PointerAlignment: Right PointerAlignment: Right
# Different ways to arrange specifiers and qualifiers (e.g. const/volatile).
QualifierAlignment: Custom
QualifierOrder: ['inline', 'static', 'type', 'const', 'volatile']
# false: # false:
# // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information # // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
# /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */ # /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */

View File

@ -588,6 +588,37 @@ FP_GetClosestPortalMonkeyResult FP_GetClosestPortalMonkey(FP_Game *game, FP_Game
return result; return result;
} }
static void FP_AppendMobSpawnerWaypoints(FP_Game *game, FP_GameEntityHandle src_handle, FP_GameEntityHandle dest_handle)
{
FP_GameEntity *src = FP_Game_GetEntity(game, src_handle);
FP_GameEntity *dest = FP_Game_GetEntity(game, dest_handle);
if (FP_Game_IsNilEntity(src) || FP_Game_IsNilEntity(dest))
return;
Dqn_f32 one_meter = FP_Game_MetersToPixelsNx1(game->play, 1.f);
for (FP_GameEntity *waypoint_entity = src->first_child; waypoint_entity; waypoint_entity = waypoint_entity->next) {
if ((waypoint_entity->flags & FP_GameEntityFlag_MobSpawnerWaypoint) == 0)
continue;
// NOTE: Add the waypoint
FP_SentinelListLink<FP_GameWaypoint> *waypoint = FP_SentinelList_Make(&dest->waypoints, game->play.chunk_pool);
waypoint->data.entity = waypoint_entity->handle;
waypoint->data.arrive = FP_GameWaypointArrive_WhenWithinEntitySize;
waypoint->data.value = 1.5f;
uint32_t min_vary = DQN_CAST(uint32_t)(one_meter * .5f);
uint32_t max_vary = DQN_CAST(uint32_t)(one_meter * 2.f);
waypoint->data.offset += Dqn_V2_InitNx2(DQN_CAST(Dqn_f32) Dqn_PCG32_Range(&game->play.rng, min_vary, max_vary),
DQN_CAST(Dqn_f32) Dqn_PCG32_Range(&game->play.rng, min_vary, max_vary));
if (Dqn_PCG32_NextF32(&game->play.rng) >= .5f)
waypoint->data.offset.x *= -1;
if (Dqn_PCG32_NextF32(&game->play.rng) >= .5f)
waypoint->data.offset.y *= -1;
}
}
void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_PlatformInput *input, FP_GameEntity *entity, Dqn_V2 *acceleration_meters_per_s) void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_PlatformInput *input, FP_GameEntity *entity, Dqn_V2 *acceleration_meters_per_s)
{ {
TELY_AssetSpriteSheet *sheet = &game->atlas_sprite_sheet; TELY_AssetSpriteSheet *sheet = &game->atlas_sprite_sheet;
@ -1119,10 +1150,12 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
entity->building_patron = {}; entity->building_patron = {};
// NOTE: Add a waypoint for the plane to the mob spawn // NOTE: Add a waypoint for the plane to the mob spawn
FP_GameEntityHandle mob_spawner = {};
Dqn_V2 mob_spawner_pos = {};
{ {
uint32_t mob_spawner_index = Dqn_PCG32_Range(&game->play.rng, 0, DQN_CAST(uint32_t)game->play.mob_spawners.size); uint32_t mob_spawner_index = Dqn_PCG32_Range(&game->play.rng, 0, DQN_CAST(uint32_t)game->play.mob_spawners.size);
FP_GameEntityHandle mob_spawner = game->play.mob_spawners.data[mob_spawner_index]; mob_spawner = game->play.mob_spawners.data[mob_spawner_index];
Dqn_V2 target_pos = FP_Game_CalcEntityWorldPos(game, mob_spawner); mob_spawner_pos = FP_Game_CalcEntityWorldPos(game, mob_spawner);
plane->waypoints = FP_SentinelList_Init<FP_GameWaypoint>(game->play.chunk_pool); plane->waypoints = FP_SentinelList_Init<FP_GameWaypoint>(game->play.chunk_pool);
FP_SentinelListLink<FP_GameWaypoint> *link = FP_SentinelList_MakeBefore(&plane->waypoints, FP_SentinelListLink<FP_GameWaypoint> *link = FP_SentinelList_MakeBefore(&plane->waypoints,
FP_SentinelList_Front(&plane->waypoints), FP_SentinelList_Front(&plane->waypoints),
@ -1132,6 +1165,11 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
waypoint->type = FP_GameWaypointType_ClosestSide; waypoint->type = FP_GameWaypointType_ClosestSide;
} }
// NOTE: Update the mob's waypoints to the mob spawner waypoints
FP_GameEntity *patron = FP_Game_GetEntity(game, plane->building_patron);
FP_SentinelList_Clear(&patron->waypoints, game->play.chunk_pool);
FP_AppendMobSpawnerWaypoints(game, entity->handle, plane->building_patron);
FP_Game_EntityTransitionState(game, entity, FP_EntityAirportTerryState_Idle); FP_Game_EntityTransitionState(game, entity, FP_EntityAirportTerryState_Idle);
} }
} break; } break;
@ -1876,14 +1914,13 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
// NOTE: Remove them from the queue // NOTE: Remove them from the queue
Dqn_FArray_EraseRange(&waypoint_entity->building_queue, 0 /*index*/, 1 /*count*/, Dqn_ArrayErase_Stable); Dqn_FArray_EraseRange(&waypoint_entity->building_queue, 0 /*index*/, 1 /*count*/, Dqn_ArrayErase_Stable);
Dqn_Rect hit_box = FP_Game_CalcEntityWorldHitBox(game, building->handle); Dqn_Rect building_hit_box = FP_Game_CalcEntityWorldHitBox(game, building->handle);
Dqn_V2 exit_pos = Dqn_Rect_InterpolatedPoint(hit_box, Dqn_V2_InitNx2(0.5f, 1.1f)); Dqn_V2 exit_pos = Dqn_Rect_InterpolatedPoint(building_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 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);
@ -2130,13 +2167,11 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
entity->next_spawn_timestamp_s = DQN_CAST(uint64_t)(input->timer_s + 2.5f); entity->next_spawn_timestamp_s = DQN_CAST(uint64_t)(input->timer_s + 2.5f);
FP_SentinelListLink<FP_GameEntityHandle> *link = FP_SentinelList_Make(&entity->spawn_list, game->play.chunk_pool); FP_SentinelListLink<FP_GameEntityHandle> *link = FP_SentinelList_Make(&entity->spawn_list, game->play.chunk_pool);
Dqn_f32 one_meter = FP_Game_MetersToPixelsNx1(game->play, 1.f);
Dqn_V2 entity_world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle); Dqn_V2 entity_world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle);
Dqn_Rect entity_hit_box = FP_Game_CalcEntityWorldHitBox(game, entity->handle); Dqn_Rect entity_hit_box = FP_Game_CalcEntityWorldHitBox(game, entity->handle);
Dqn_f32 step_y = (entity_hit_box.size.h / spawn_count) * 1.5f; Dqn_f32 step_y = (entity_hit_box.size.h / spawn_count) * 1.5f;
Dqn_f32 mob_y_offset = (Dqn_PCG32_NextF32(&game->play.rng) * step_y) + (step_y * spawn_index); Dqn_f32 mob_y_offset = (Dqn_PCG32_NextF32(&game->play.rng) * step_y) + (step_y * spawn_index);
if (Dqn_PCG32_NextF32(&game->play.rng) >= .5f) if (Dqn_PCG32_NextF32(&game->play.rng) >= .5f)
mob_y_offset *= -1; mob_y_offset *= -1;
@ -2157,31 +2192,12 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
mob->hp_cap *= hp_adjustment; mob->hp_cap *= hp_adjustment;
mob->hp = mob->hp_cap; mob->hp = mob->hp_cap;
for (FP_GameEntity *waypoint_entity = entity->first_child; waypoint_entity; waypoint_entity = waypoint_entity->next) { FP_AppendMobSpawnerWaypoints(game, entity->handle, mob->handle);
if ((waypoint_entity->flags & FP_GameEntityFlag_MobSpawnerWaypoint) == 0)
continue;
// NOTE: Add the waypoint
FP_SentinelListLink<FP_GameWaypoint> *waypoint = FP_SentinelList_Make(&mob->waypoints, game->play.chunk_pool);
waypoint->data.entity = waypoint_entity->handle;
waypoint->data.arrive = FP_GameWaypointArrive_WhenWithinEntitySize;
waypoint->data.value = 1.5f;
uint32_t min_vary = DQN_CAST(uint32_t)(one_meter * .5f);
uint32_t max_vary = DQN_CAST(uint32_t)(one_meter * 2.f);
waypoint->data.offset += Dqn_V2_InitNx2(DQN_CAST(Dqn_f32)Dqn_PCG32_Range(&game->play.rng, min_vary, max_vary),
DQN_CAST(Dqn_f32)Dqn_PCG32_Range(&game->play.rng, min_vary, max_vary));
if (Dqn_PCG32_NextF32(&game->play.rng) >= .5f)
waypoint->data.offset *= -1;
}
game->play.enemies_spawned_this_wave++; game->play.enemies_spawned_this_wave++;
if (game->play.enemies_spawned_this_wave >= game->play.enemies_per_wave) if (game->play.enemies_spawned_this_wave >= game->play.enemies_per_wave)
game->play.wave_cooldown_timestamp_ms = game->play.clock_ms + 30'000; game->play.wave_cooldown_timestamp_ms = game->play.clock_ms + 30'000;
} }
} }
} }
} }

View File

@ -115,14 +115,21 @@ FP_SentinelListLink<T> *FP_SentinelList_Erase(FP_SentinelList<T> *list, FP_Senti
} }
template <typename T> template <typename T>
void FP_SentinelList_Deinit(FP_SentinelList<T> *list, TELY_ChunkPool *pool) void FP_SentinelList_Clear(FP_SentinelList<T> *list, TELY_ChunkPool *pool)
{ {
if (!list || !pool) if (!list || !pool)
return; return;
for (FP_SentinelListLink<T> *link = nullptr; FP_SentinelList_Iterate(list, &link); ) for (FP_SentinelListLink<T> *link = nullptr; FP_SentinelList_Iterate(list, &link); )
link = FP_SentinelList_Erase(list, link, pool); link = FP_SentinelList_Erase(list, link, pool);
}
template <typename T>
void FP_SentinelList_Deinit(FP_SentinelList<T> *list, TELY_ChunkPool *pool)
{
if (!list || !pool)
return;
FP_SentinelList_Clear(list, pool);
TELY_ChunkPool_Dealloc(pool, list->sentinel); TELY_ChunkPool_Dealloc(pool, list->sentinel);
*list = {}; *list = {};
} }