4 Commits

Author SHA1 Message Date
doylet efec333b61 fp: Redo the attack boxes 2023-10-08 16:46:49 +11:00
doylet 98e3245682 fp: Reset game on game completion 2023-10-08 16:46:47 +11:00
doylet 1889b9f9c5 fp: Wire up game reset 2023-10-08 16:46:44 +11:00
Jojangles 2102ffa094 fp: Add more sfx 2023-10-08 16:21:39 +11:00
10 changed files with 554 additions and 420 deletions
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+1 -1
+396 -306
View File
File diff suppressed because it is too large Load Diff
+8 -8
View File
@@ -14,7 +14,7 @@ static bool FP_Entity_IsBuildingForMobs(FP_GameEntity *entity)
static Dqn_f32 FP_Entity_CalcSpriteScaleForDesiredHeight(FP_Game *game, FP_Meters height, Dqn_Rect sprite_rect) static Dqn_f32 FP_Entity_CalcSpriteScaleForDesiredHeight(FP_Game *game, FP_Meters height, Dqn_Rect sprite_rect)
{ {
Dqn_f32 sprite_in_meters = FP_Game_PixelsToMetersNx1(game, sprite_rect.size.y); Dqn_f32 sprite_in_meters = FP_Game_PixelsToMetersNx1(game->play, sprite_rect.size.y);
Dqn_f32 result = height.meters / sprite_in_meters; Dqn_f32 result = height.meters / sprite_in_meters;
return result; return result;
} }
@@ -318,7 +318,7 @@ static FP_GameEntityHandle FP_Entity_CreateClinger(FP_Game *game, Dqn_V2 pos, DQ
entity->attack_cooldown_ms = 1000; entity->attack_cooldown_ms = 1000;
entity->faction = FP_GameEntityFaction_Foe; entity->faction = FP_GameEntityFaction_Foe;
entity->local_hit_box_size = FP_Game_MetersToPixelsNx2(game, 0.7f, entity->sprite_height.meters * .5f); entity->local_hit_box_size = FP_Game_MetersToPixelsNx2(game->play, 0.7f, entity->sprite_height.meters * .5f);
FP_Entity_AddDebugEditorFlags(game, entity->handle); FP_Entity_AddDebugEditorFlags(game, entity->handle);
entity->flags |= FP_GameEntityFlag_NonTraversable; entity->flags |= FP_GameEntityFlag_NonTraversable;
entity->flags |= FP_GameEntityFlag_Attackable; entity->flags |= FP_GameEntityFlag_Attackable;
@@ -341,7 +341,7 @@ static FP_GameEntityHandle FP_Entity_CreateSmoochie(FP_Game *game, Dqn_V2 pos, D
entity->is_dying = false; entity->is_dying = false;
entity->local_pos = pos; entity->local_pos = pos;
entity->attack_cooldown_ms = 1000; entity->attack_cooldown_ms = 1000;
entity->local_hit_box_size = FP_Game_MetersToPixelsNx2(game, 0.7f, entity->sprite_height.meters * .6f); entity->local_hit_box_size = FP_Game_MetersToPixelsNx2(game->play, 0.7f, entity->sprite_height.meters * .6f);
FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down); FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down);
entity->sprite_height = render_data.height; entity->sprite_height = render_data.height;
@@ -375,7 +375,7 @@ static FP_GameEntityHandle FP_Entity_CreateCatfish(FP_Game *game, Dqn_V2 pos, DQ
FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite);
entity->attack_cooldown_ms = 1000; entity->attack_cooldown_ms = 1000;
entity->local_hit_box_size = FP_Game_MetersToPixelsNx2(game, 0.7f, entity->sprite_height.meters * .6f); entity->local_hit_box_size = FP_Game_MetersToPixelsNx2(game->play, 0.7f, entity->sprite_height.meters * .6f);
FP_Entity_AddDebugEditorFlags(game, entity->handle); FP_Entity_AddDebugEditorFlags(game, entity->handle);
entity->flags |= FP_GameEntityFlag_NonTraversable; entity->flags |= FP_GameEntityFlag_NonTraversable;
entity->flags |= FP_GameEntityFlag_Attackable; entity->flags |= FP_GameEntityFlag_Attackable;
@@ -434,7 +434,7 @@ static FP_GameEntityHandle FP_Entity_CreateMobSpawner(FP_Game *game, Dqn_V2 pos,
FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite);
entity->spawn_cap = spawn_cap; entity->spawn_cap = spawn_cap;
entity->spawn_list = FP_SentinelList_Init<FP_GameEntityHandle>(game->chunk_pool); entity->spawn_list = FP_SentinelList_Init<FP_GameEntityHandle>(game->play.chunk_pool);
return result; return result;
} }
@@ -456,10 +456,10 @@ static FP_GameEntityHandle FP_Entity_CreateTerry(FP_Game *game, Dqn_V2 pos, DQN_
FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite); FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite);
entity->attack_cooldown_ms = 500; entity->attack_cooldown_ms = 500;
entity->local_hit_box_size = FP_Game_MetersToPixelsNx2(game, 0.5f, entity->sprite_height.meters * .6f); entity->local_hit_box_size = FP_Game_MetersToPixelsNx2(game->play, 0.5f, entity->sprite_height.meters * .6f);
entity->hp_cap = FP_DEFAULT_DAMAGE * 3; entity->hp_cap = FP_DEFAULT_DAMAGE * 3;
entity->hp = entity->hp_cap; entity->hp = entity->hp_cap;
entity->coins = 0;//1'000'000; entity->coins = 1'000'000;
FP_Entity_AddDebugEditorFlags(game, result); FP_Entity_AddDebugEditorFlags(game, result);
entity->flags |= FP_GameEntityFlag_NonTraversable; entity->flags |= FP_GameEntityFlag_NonTraversable;
entity->flags |= FP_GameEntityFlag_Attackable; entity->flags |= FP_GameEntityFlag_Attackable;
@@ -756,7 +756,7 @@ static FP_GameEntityHandle FP_Entity_CreatePhoneMessageProjectile(FP_Game *game,
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->local_hit_box_size = Dqn_V2_InitNx2(render_data.render_size.w, render_data.render_size.h - (render_data.render_size.h * .4f));
entity->attack_box_offset = entity->local_hit_box_offset; entity->attack_box_offset = entity->local_hit_box_offset;
entity->attack_box_size = entity->local_hit_box_size; entity->attack_box_size = entity->local_hit_box_size;
entity->ttl_end_timestamp = game->clock_ms + 1000; entity->ttl_end_timestamp = game->play.clock_ms + 1000;
entity->projectile_owner = owner; entity->projectile_owner = owner;
entity->faction = FP_GameEntityFaction_Friendly; entity->faction = FP_GameEntityFaction_Friendly;
return result; return result;
+87 -54
View File
@@ -3,13 +3,13 @@
#include "feely_pona_unity.h" #include "feely_pona_unity.h"
#endif #endif
#define FP_Game_MetersToPixelsNx1(game, val) ((val) * (game)->meters_to_pixels) #define FP_Game_MetersToPixelsNx1(game, val) ((val) * (game).meters_to_pixels)
#define FP_Game_MetersToPixelsNx2(game, x, y) (Dqn_V2_InitNx2(x, y) * (game)->meters_to_pixels) #define FP_Game_MetersToPixelsNx2(game, x, y) (Dqn_V2_InitNx2(x, y) * (game).meters_to_pixels)
#define FP_Game_MetersToPixelsV2(game, xy) (xy * (game)->meters_to_pixels) #define FP_Game_MetersToPixelsV2(game, xy) (xy * (game).meters_to_pixels)
#define FP_Game_PixelsToMetersNx1(game, val) ((val) * (1.f/(game)->meters_to_pixels)) #define FP_Game_PixelsToMetersNx1(game, val) ((val) * (1.f/(game).meters_to_pixels))
#define FP_Game_PixelsToMetersNx2(game, x, y) (Dqn_V2_InitNx2(x, y) * (1.f/(game)->meters_to_pixels)) #define FP_Game_PixelsToMetersNx2(game, x, y) (Dqn_V2_InitNx2(x, y) * (1.f/(game).meters_to_pixels))
#define FP_Game_PixelsToMetersV2(game, xy) (xy * (1.f/(game)->meters_to_pixels)) #define FP_Game_PixelsToMetersV2(game, xy) (xy * (1.f/(game).meters_to_pixels))
static bool operator==(FP_GameEntityHandle const &lhs, FP_GameEntityHandle const &rhs) static bool operator==(FP_GameEntityHandle const &lhs, FP_GameEntityHandle const &rhs)
{ {
@@ -50,12 +50,12 @@ static FP_GameEntity *FP_Game_GetEntity(FP_Game *game, FP_GameEntityHandle handl
if (!game) if (!game)
return result; return result;
result = game->entities.data; result = game->play.entities.data;
uint64_t index_from_handle = handle.id & FP_GAME_ENTITY_HANDLE_INDEX_MASK; uint64_t index_from_handle = handle.id & FP_GAME_ENTITY_HANDLE_INDEX_MASK;
if (index_from_handle >= game->entities.size) if (index_from_handle >= game->play.entities.size)
return result; return result;
FP_GameEntity *candidate = game->entities.data + index_from_handle; FP_GameEntity *candidate = game->play.entities.data + index_from_handle;
if (candidate->handle == handle) if (candidate->handle == handle)
result = candidate; result = candidate;
return result; return result;
@@ -167,24 +167,24 @@ static bool FP_Game_DFSPostOrderWalkEntityTree(FP_Game *game, FP_GameEntityItera
// NOTE: Parent entity // NOTE: Parent entity
static void FP_Game_PushParentEntity(FP_Game *game, FP_GameEntityHandle handle) static void FP_Game_PushParentEntity(FP_Game *game, FP_GameEntityHandle handle)
{ {
DQN_ASSERTF(game->parent_entity_stack.size >= 1, "Sentinel/nil entity has not been assigned as the 0th slot yet"); DQN_ASSERTF(game->play.parent_entity_stack.size >= 1, "Sentinel/nil entity has not been assigned as the 0th slot yet");
if (game) if (game)
Dqn_FArray_Add(&game->parent_entity_stack, handle); Dqn_FArray_Add(&game->play.parent_entity_stack, handle);
} }
static void FP_Game_PopParentEntity(FP_Game *game) static void FP_Game_PopParentEntity(FP_Game *game)
{ {
// NOTE: 0th slot is reserved for the nil entity // NOTE: 0th slot is reserved for the nil entity
if (game && game->parent_entity_stack.size > 1) if (game && game->play.parent_entity_stack.size > 1)
Dqn_FArray_PopBack(&game->parent_entity_stack, 1); Dqn_FArray_PopBack(&game->play.parent_entity_stack, 1);
} }
static FP_GameEntityHandle FP_Game_ActiveParentEntity(FP_Game const *game) static FP_GameEntityHandle FP_Game_ActiveParentEntity(FP_Game const *game)
{ {
FP_GameEntityHandle result = {}; FP_GameEntityHandle result = {};
if (!game || !game->parent_entity_stack.size) if (!game || !game->play.parent_entity_stack.size)
return result; return result;
result = game->parent_entity_stack.data[game->parent_entity_stack.size - 1]; result = game->play.parent_entity_stack.data[game->play.parent_entity_stack.size - 1];
return result; return result;
} }
@@ -201,28 +201,28 @@ static FP_GameEntity *FP_Game_MakeEntityPointerFV(FP_Game *game, DQN_FMT_STRING_
if (!game) if (!game)
return result; return result;
DQN_ASSERTF(game->entities.size > 0, "Sentinel/nil entity has not been initialised yet"); DQN_ASSERTF(game->play.entities.size > 0, "Sentinel/nil entity has not been initialised yet");
DQN_ASSERTF(game->root_entity, "Sentinel/nil entity has not been assigned yet"); DQN_ASSERTF(game->play.root_entity, "Sentinel/nil entity has not been assigned yet");
result = game->root_entity; // TODO(doyle): Root entity or ... the nil entity? result = game->play.root_entity; // TODO(doyle): Root entity or ... the nil entity?
if (game->entity_free_list) { if (game->play.entity_free_list) {
result = game->entity_free_list; result = game->play.entity_free_list;
game->entity_free_list = game->entity_free_list->next; game->play.entity_free_list = game->play.entity_free_list->next;
result->next = nullptr; result->next = nullptr;
} else { } else {
if (game->entities.size >= (FP_GAME_ENTITY_HANDLE_INDEX_MAX + 1)) if (game->play.entities.size >= (FP_GAME_ENTITY_HANDLE_INDEX_MAX + 1))
return result; return result;
result = Dqn_VArray_Make(&game->entities, Dqn_ZeroMem_Yes); result = Dqn_VArray_Make(&game->play.entities, Dqn_ZeroMem_Yes);
if (!result) if (!result)
return result; return result;
result->handle.id = (game->entities.size - 1) & FP_GAME_ENTITY_HANDLE_INDEX_MASK; result->handle.id = (game->play.entities.size - 1) & FP_GAME_ENTITY_HANDLE_INDEX_MASK;
} }
result->sprite_height.meters = 1; result->sprite_height.meters = 1;
result->parent = FP_Game_ActiveParentEntityPointer(game); result->parent = FP_Game_ActiveParentEntityPointer(game);
result->name = TELY_ChunkPool_AllocFmtFV(game->chunk_pool, fmt, args); result->name = TELY_ChunkPool_AllocFmtFV(game->play.chunk_pool, fmt, args);
result->buildings_visited = FP_SentinelList_Init<FP_GameEntityHandle>(game->chunk_pool); result->buildings_visited = FP_SentinelList_Init<FP_GameEntityHandle>(game->play.chunk_pool);
result->action.sprite_alpha = 1.f; result->action.sprite_alpha = 1.f;
result->stamina_cap = 93; result->stamina_cap = 93;
@@ -251,7 +251,7 @@ static FP_GameEntity *FP_Game_MakeEntityPointerFV(FP_Game *game, DQN_FMT_STRING_
DQN_ASSERT(!result->next); DQN_ASSERT(!result->next);
DQN_ASSERT(result->handle.id); DQN_ASSERT(result->handle.id);
DQN_ASSERT(result->parent->handle == game->parent_entity_stack.data[game->parent_entity_stack.size - 1]); DQN_ASSERT(result->parent->handle == game->play.parent_entity_stack.data[game->play.parent_entity_stack.size - 1]);
return result; return result;
} }
@@ -308,7 +308,7 @@ static void FP_Game_DetachEntityIntoFreeList(FP_Game *game, FP_GameEntityHandle
return; return;
uint64_t const entity_index_from_handle = entity->handle.id & FP_GAME_ENTITY_HANDLE_INDEX_MASK; uint64_t const entity_index_from_handle = entity->handle.id & FP_GAME_ENTITY_HANDLE_INDEX_MASK;
DQN_ASSERT(entity_index_from_handle < game->entities.size); DQN_ASSERT(entity_index_from_handle < game->play.entities.size);
uint64_t const entity_generation_raw = entity->handle.id & FP_GAME_ENTITY_HANDLE_GENERATION_MASK; uint64_t const entity_generation_raw = entity->handle.id & FP_GAME_ENTITY_HANDLE_GENERATION_MASK;
uint64_t const entity_generation = entity_generation_raw >> FP_GAME_ENTITY_HANDLE_GENERATION_RSHIFT; uint64_t const entity_generation = entity_generation_raw >> FP_GAME_ENTITY_HANDLE_GENERATION_RSHIFT;
@@ -330,22 +330,23 @@ static void FP_Game_DetachEntityIntoFreeList(FP_Game *game, FP_GameEntityHandle
parent->last_child = entity->prev; parent->last_child = entity->prev;
if (entity->name.size) if (entity->name.size)
TELY_ChunkPool_Dealloc(game->chunk_pool, entity->name.data); TELY_ChunkPool_Dealloc(game->play.chunk_pool, entity->name.data);
FP_SentinelList_Deinit(&entity->spawn_list, game->chunk_pool); FP_SentinelList_Deinit(&entity->spawn_list, game->play.chunk_pool);
FP_SentinelList_Deinit(&entity->waypoints, game->chunk_pool); FP_SentinelList_Deinit(&entity->waypoints, game->play.chunk_pool);
FP_SentinelList_Deinit(&entity->buildings_visited, game->chunk_pool); FP_SentinelList_Deinit(&entity->buildings_visited, game->play.chunk_pool);
if (new_entity_generation > entity_generation) { if (new_entity_generation > entity_generation) {
// NOTE: Update the incremented handle disassociating all prior handles // NOTE: Update the incremented handle disassociating all prior handles
// to this entity which would reference older generation values // to this entity which would reference older generation values
*entity = {}; *entity = {};
entity->parent = game->play.root_entity;
entity->handle.id = entity_index_from_handle | (new_entity_generation << FP_GAME_ENTITY_HANDLE_GENERATION_RSHIFT); entity->handle.id = entity_index_from_handle | (new_entity_generation << FP_GAME_ENTITY_HANDLE_GENERATION_RSHIFT);
// NOTE: Attach entity to the free list // NOTE: Attach entity to the free list
entity->next = game->entity_free_list; entity->next = game->play.entity_free_list;
entity->prev = nullptr; entity->prev = nullptr;
game->entity_free_list = entity; game->play.entity_free_list = entity;
} else { } else {
// NOTE: We've cycled through all possible generations for this handle // NOTE: We've cycled through all possible generations for this handle
// We will not increment it and freeze it so it is no longer allocated // We will not increment it and freeze it so it is no longer allocated
@@ -357,10 +358,10 @@ static void FP_Game_DetachEntityIntoFreeList(FP_Game *game, FP_GameEntityHandle
static void FP_Game_DeleteEntity(FP_Game *game, FP_GameEntityHandle handle) static void FP_Game_DeleteEntity(FP_Game *game, FP_GameEntityHandle handle)
{ {
uint64_t index_from_handle = handle.id & FP_GAME_ENTITY_HANDLE_INDEX_MASK; uint64_t index_from_handle = handle.id & FP_GAME_ENTITY_HANDLE_INDEX_MASK;
if (!game || !DQN_CHECK(index_from_handle < game->entities.size)) if (!game || !DQN_CHECK(index_from_handle < game->play.entities.size))
return; return;
FP_GameEntity *root = game->entities.data + index_from_handle; FP_GameEntity *root = game->play.entities.data + index_from_handle;
if (root->handle != handle) if (root->handle != handle)
return; return;
@@ -382,7 +383,7 @@ static Dqn_V2 FP_Game_CalcEntityWorldPos(FP_Game const *game, FP_GameEntityHandl
return result; return result;
FP_GameEntity const *first = FP_Game_GetEntity(DQN_CAST(FP_Game *)game, handle); FP_GameEntity const *first = FP_Game_GetEntity(DQN_CAST(FP_Game *)game, handle);
for (FP_GameEntity const *entity = first; entity != game->root_entity; entity = entity->parent) for (FP_GameEntity const *entity = first; entity != game->play.root_entity; entity = entity->parent)
result += entity->local_pos; result += entity->local_pos;
return result; return result;
} }
@@ -413,6 +414,37 @@ static Dqn_Rect FP_Game_CalcEntityAttackWorldHitBox(FP_Game const *game, FP_Game
return result; return result;
} }
static Dqn_FArray<Dqn_Rect, FP_GameDirection_Count> FP_Game_CalcEntityMeleeAttackBoxes(FP_Game const *game, FP_GameEntityHandle handle)
{
Dqn_FArray<Dqn_Rect, FP_GameDirection_Count> result = {};
Dqn_Rect hit_box = FP_Game_CalcEntityWorldHitBox(game, handle);
DQN_FOR_UINDEX (dir_index, FP_GameDirection_Count) {
Dqn_Rect *rect = Dqn_FArray_Make(&result, Dqn_ZeroMem_Yes);
rect->size = hit_box.size;
switch (dir_index) {
case FP_GameDirection_Left: {
rect->pos = Dqn_Rect_InterpolatedPoint(hit_box, Dqn_V2_InitNx2(-1.f, 0.f));
} break;
case FP_GameDirection_Right: {
rect->pos = Dqn_Rect_InterpolatedPoint(hit_box, Dqn_V2_InitNx2(+1.f, 0.f));
} break;
case FP_GameDirection_Up: {
rect->pos = Dqn_Rect_InterpolatedPoint(hit_box, Dqn_V2_InitNx2(0.f, -1.f));
} break;
case FP_GameDirection_Down: {
rect->pos = Dqn_Rect_InterpolatedPoint(hit_box, Dqn_V2_InitNx2(0.f, +1.f));
} break;
case FP_GameDirection_Count: break;
}
}
return result;
}
static Dqn_Rect FP_Game_CalcEntityArrayWorldBoundingBox(FP_Game const *game, FP_GameEntityHandle const *handles, Dqn_usize count) static Dqn_Rect FP_Game_CalcEntityArrayWorldBoundingBox(FP_Game const *game, FP_GameEntityHandle const *handles, Dqn_usize count)
{ {
Dqn_Rect result = {}; Dqn_Rect result = {};
@@ -472,19 +504,19 @@ static void FP_Game_EntityActionReset(FP_Game *game, FP_GameEntityHandle entity_
if (!entity) if (!entity)
return; return;
entity->action.sprite = sprite; entity->action.sprite = sprite;
entity->action.started_at_clock_ms = game->clock_ms; entity->action.started_at_clock_ms = game->play.clock_ms;
entity->action.end_at_clock_ms = DQN_MAX(duration_ms, game->clock_ms + duration_ms); entity->action.end_at_clock_ms = DQN_MAX(duration_ms, game->play.clock_ms + duration_ms);
} }
static Dqn_V2I FP_Game_WorldPosToTilePos(FP_Game *game, Dqn_V2 world_pos) static Dqn_V2I FP_Game_WorldPosToTilePos(FP_Game *game, Dqn_V2 world_pos)
{ {
Dqn_V2I result = Dqn_V2I_InitNx2(world_pos.x / game->tile_size, world_pos.y / game->tile_size); Dqn_V2I result = Dqn_V2I_InitNx2(world_pos.x / game->play.tile_size, world_pos.y / game->play.tile_size);
return result; return result;
} }
static Dqn_V2 FP_Game_TilePosToWorldPos(FP_Game *game, Dqn_V2I tile_pos) static Dqn_V2 FP_Game_TilePosToWorldPos(FP_Game *game, Dqn_V2I tile_pos)
{ {
Dqn_V2 result = Dqn_V2_InitNx2(tile_pos.x * game->tile_size, tile_pos.y * game->tile_size); Dqn_V2 result = Dqn_V2_InitNx2(tile_pos.x * game->play.tile_size, tile_pos.y * game->play.tile_size);
return result; return result;
} }
@@ -495,8 +527,8 @@ static Dqn_Slice<Dqn_V2I> FP_Game_AStarPathFind(FP_Game *game,
Dqn_V2I dest_tile) Dqn_V2I dest_tile)
{ {
Dqn_Profiler_ZoneScopeWithIndex("FP_Update: A*", FP_ProfileZone_FPUpdate_AStar); Dqn_Profiler_ZoneScopeWithIndex("FP_Update: A*", FP_ProfileZone_FPUpdate_AStar);
Dqn_usize tile_count_x = DQN_CAST(Dqn_usize)(platform->core.window_size.w / game->tile_size); Dqn_usize tile_count_x = DQN_CAST(Dqn_usize)(platform->core.window_size.w / game->play.tile_size);
Dqn_usize tile_count_y = DQN_CAST(Dqn_usize)(platform->core.window_size.h / game->tile_size); Dqn_usize tile_count_y = DQN_CAST(Dqn_usize)(platform->core.window_size.h / game->play.tile_size);
Dqn_Slice<Dqn_V2I> result = {}; Dqn_Slice<Dqn_V2I> result = {};
if (dest_tile.x < 0 || dest_tile.x > tile_count_x || if (dest_tile.x < 0 || dest_tile.x > tile_count_x ||
@@ -509,7 +541,7 @@ static Dqn_Slice<Dqn_V2I> FP_Game_AStarPathFind(FP_Game *game,
// NOTE: Enumerate the entities that are collidable ============================================ // NOTE: Enumerate the entities that are collidable ============================================
bool dest_tile_is_non_traversable = false; bool dest_tile_is_non_traversable = false;
auto zone_enum_collidables = Dqn_Profiler_BeginZoneWithIndex(DQN_STRING8("FP_Update: A* enumerate collidables"), FP_ProfileZone_FPUpdate_AStarEnumerateCollidables); auto zone_enum_collidables = Dqn_Profiler_BeginZoneWithIndex(DQN_STRING8("FP_Update: A* enumerate collidables"), FP_ProfileZone_FPUpdate_AStarEnumerateCollidables);
for (FP_GameEntityIterator it = {}; FP_Game_DFSPreOrderWalkEntityTree(game, &it, game->root_entity); ) { for (FP_GameEntityIterator it = {}; FP_Game_DFSPreOrderWalkEntityTree(game, &it, game->play.root_entity); ) {
FP_GameEntity const *walk_entity = it.entity; FP_GameEntity const *walk_entity = it.entity;
if (entity == walk_entity->handle) if (entity == walk_entity->handle)
continue; continue;
@@ -644,7 +676,7 @@ static Dqn_Slice<Dqn_V2I> FP_Game_AStarPathFind(FP_Game *game,
for (uint32_t old_index = 1 /*Sentinel*/; old_index < astar_info.occupied; old_index++) { for (uint32_t old_index = 1 /*Sentinel*/; old_index < astar_info.occupied; old_index++) {
Dqn_DSMapSlot<FP_GameAStarNode> const *slot = astar_info.slots + old_index; Dqn_DSMapSlot<FP_GameAStarNode> const *slot = astar_info.slots + old_index;
FP_GameAStarNode const *node = &slot->value; FP_GameAStarNode const *node = &slot->value;
Dqn_V2 pos = FP_Game_TilePosToWorldPos(game, node->tile) + (game->tile_size * .5f); Dqn_V2 pos = FP_Game_TilePosToWorldPos(game, node->tile) + (game->play.tile_size * .5f);
TELY_Render_CircleColourV4(renderer, pos, 4.f, TELY_RenderShapeMode_Fill, TELY_COLOUR_BLUE_CADET_V4); TELY_Render_CircleColourV4(renderer, pos, 4.f, TELY_RenderShapeMode_Fill, TELY_COLOUR_BLUE_CADET_V4);
} }
#endif #endif
@@ -737,7 +769,7 @@ FP_GameFindClosestEntityResult FP_Game_FindClosestEntityWithType(FP_Game *game,
result.dist_squared = DQN_F32_MAX; result.dist_squared = DQN_F32_MAX;
result.pos = Dqn_V2_InitNx1(DQN_F32_MAX); result.pos = Dqn_V2_InitNx1(DQN_F32_MAX);
for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) { for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->play.root_entity); ) {
FP_GameEntity *it_entity = it.entity; FP_GameEntity *it_entity = it.entity;
if (it_entity->type != type) if (it_entity->type != type)
continue; continue;
@@ -791,11 +823,11 @@ static void FP_Game_EntityTransitionState(FP_Game *game, FP_GameEntity *entity,
case FP_EntityType_Terry: { case FP_EntityType_Terry: {
if (desired_state == FP_EntityTerryState_Attack || if (desired_state == FP_EntityTerryState_Attack ||
desired_state == FP_EntityTerryState_RangeAttack) { desired_state == FP_EntityTerryState_RangeAttack) {
if (!FP_Game_CanEntityAttack(entity, game->clock_ms)) { if (!FP_Game_CanEntityAttack(entity, game->play.clock_ms)) {
// NOTE: Cooldown not met do not transition // NOTE: Cooldown not met do not transition
return; return;
} }
entity->last_attack_timestamp = game->clock_ms; entity->last_attack_timestamp = game->play.clock_ms;
if (desired_state == FP_EntityTerryState_RangeAttack) { if (desired_state == FP_EntityTerryState_RangeAttack) {
if (entity->terry_mobile_data_plan < FP_TERRY_MOBILE_DATA_PER_RANGE_ATTACK) if (entity->terry_mobile_data_plan < FP_TERRY_MOBILE_DATA_PER_RANGE_ATTACK)
@@ -809,31 +841,31 @@ static void FP_Game_EntityTransitionState(FP_Game *game, FP_GameEntity *entity,
case FP_EntityType_Smoochie: { case FP_EntityType_Smoochie: {
if (desired_state == FP_EntitySmoochieState_Attack) { if (desired_state == FP_EntitySmoochieState_Attack) {
if (!FP_Game_CanEntityAttack(entity, game->clock_ms)) { if (!FP_Game_CanEntityAttack(entity, game->play.clock_ms)) {
// NOTE: Cooldown not met do not transition // NOTE: Cooldown not met do not transition
return; return;
} }
entity->last_attack_timestamp = game->clock_ms; entity->last_attack_timestamp = game->play.clock_ms;
} }
} break; } break;
case FP_EntityType_Clinger: { case FP_EntityType_Clinger: {
if (desired_state == FP_EntityClingerState_Attack) { if (desired_state == FP_EntityClingerState_Attack) {
if (!FP_Game_CanEntityAttack(entity, game->clock_ms)) { if (!FP_Game_CanEntityAttack(entity, game->play.clock_ms)) {
// NOTE: Cooldown not met do not transition // NOTE: Cooldown not met do not transition
return; return;
} }
entity->last_attack_timestamp = game->clock_ms; entity->last_attack_timestamp = game->play.clock_ms;
} }
} break; } break;
case FP_EntityType_Catfish: { case FP_EntityType_Catfish: {
if (desired_state == FP_EntityClingerState_Attack) { if (desired_state == FP_EntityClingerState_Attack) {
if (!FP_Game_CanEntityAttack(entity, game->clock_ms)) { if (!FP_Game_CanEntityAttack(entity, game->play.clock_ms)) {
// NOTE: Cooldown not met do not transition // NOTE: Cooldown not met do not transition
return; return;
} }
entity->last_attack_timestamp = game->clock_ms; entity->last_attack_timestamp = game->play.clock_ms;
} }
} break; } break;
@@ -893,3 +925,4 @@ static void FP_GameRenderCameraFollowScanlines(TELY_Renderer *renderer,
TELY_Render_LineColourV4(renderer, start, end, TELY_Colour_V4Alpha(TELY_COLOUR_BLACK_V4, 0.1f), scanline_thickness); TELY_Render_LineColourV4(renderer, start, end, TELY_Colour_V4Alpha(TELY_COLOUR_BLACK_V4, 0.1f), scanline_thickness);
} }
} }
+26 -18
View File
@@ -260,6 +260,9 @@ enum FP_GameAudio
FP_GameAudio_TestAudio, FP_GameAudio_TestAudio,
FP_GameAudio_TerryHit, FP_GameAudio_TerryHit,
FP_GameAudio_Smooch, FP_GameAudio_Smooch,
FP_GameAudio_Woosh,
FP_GameAudio_Ching,
FP_GameAudio_Church,
FP_GameAudio_Count, FP_GameAudio_Count,
}; };
@@ -274,27 +277,17 @@ enum FP_GameState
{ {
FP_GameState_IntroScreen, FP_GameState_IntroScreen,
FP_GameState_Play, FP_GameState_Play,
FP_GameState_WinGame,
}; };
struct FP_Game struct FP_GamePlay
{ {
Dqn_f32 delta_s_accumulator;
uint16_t tile_size;
TELY_ChunkPool *chunk_pool; TELY_ChunkPool *chunk_pool;
TELY_AssetFontHandle inter_regular_font_large; uint16_t tile_size;
TELY_AssetFontHandle inter_regular_font; Dqn_f32 delta_s_accumulator;
TELY_AssetFontHandle inter_italic_font; Dqn_Arena arena;
TELY_AssetFontHandle jetbrains_mono_font;
TELY_AssetFontHandle talkco_font;
TELY_AssetFontHandle talkco_font_large;
TELY_AssetAudioHandle audio[FP_GameAudio_Count];
Dqn_Slice<TELY_AssetSpriteAnimation> hero_sprite_anims;
TELY_AssetSpriteSheet hero_sprite_sheet;
Dqn_FArray<FP_GameEntityHandle, 8> parent_entity_stack;
Dqn_VArray<FP_GameEntity> entities; Dqn_VArray<FP_GameEntity> entities;
Dqn_FArray<FP_GameEntityHandle, 8> parent_entity_stack;
TELY_AssetSpriteSheet atlas_sprite_sheet;
FP_GameEntity *root_entity; FP_GameEntity *root_entity;
FP_GameEntity *entity_free_list; FP_GameEntity *entity_free_list;
@@ -318,14 +311,13 @@ struct FP_Game
FP_GameEntityHandle prev_active_entity; FP_GameEntityHandle prev_active_entity;
FP_GameCamera camera; FP_GameCamera camera;
TELY_RFui rfui;
Dqn_f32 meters_to_pixels; Dqn_f32 meters_to_pixels;
uint64_t clock_ms; uint64_t clock_ms;
uint64_t update_counter; uint64_t update_counter;
Dqn_PCG32 rng; Dqn_PCG32 rng;
bool debug_ui; bool debug_ui;
bool god_mode;
FP_GameInGameMenu in_game_menu; FP_GameInGameMenu in_game_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;
@@ -341,6 +333,22 @@ struct FP_Game
FP_GameState state; FP_GameState state;
}; };
struct FP_Game
{
TELY_AssetFontHandle inter_regular_font_large;
TELY_AssetFontHandle inter_regular_font;
TELY_AssetFontHandle inter_italic_font;
TELY_AssetFontHandle jetbrains_mono_font;
TELY_AssetFontHandle talkco_font;
TELY_AssetFontHandle talkco_font_large;
TELY_AssetAudioHandle audio[FP_GameAudio_Count];
Dqn_Slice<TELY_AssetSpriteAnimation> hero_sprite_anims;
TELY_AssetSpriteSheet hero_sprite_sheet;
TELY_AssetSpriteSheet atlas_sprite_sheet;
TELY_RFui rfui;
FP_GamePlay play;
};
struct FP_GameAStarNode struct FP_GameAStarNode
{ {
Dqn_usize cost; Dqn_usize cost;
+12 -12
View File
@@ -351,10 +351,10 @@ void FP_UnitTests(TELY_Platform *platform)
chunk_pool.arena = &platform->arena; chunk_pool.arena = &platform->arena;
FP_Game *game = Dqn_Arena_New(&platform->arena, FP_Game, Dqn_ZeroMem_Yes); FP_Game *game = Dqn_Arena_New(&platform->arena, FP_Game, Dqn_ZeroMem_Yes);
game->chunk_pool = &chunk_pool; game->play.chunk_pool = &chunk_pool;
game->entities = Dqn_VArray_Init<FP_GameEntity>(&platform->arena, 1024 * 8); game->play.entities = Dqn_VArray_Init<FP_GameEntity>(&platform->arena, 1024 * 8);
game->root_entity = Dqn_VArray_Make(&game->entities, Dqn_ZeroMem_No); game->play.root_entity = Dqn_VArray_Make(&game->play.entities, Dqn_ZeroMem_No);
Dqn_FArray_Add(&game->parent_entity_stack, game->root_entity->handle); Dqn_FArray_Add(&game->play.parent_entity_stack, game->play.root_entity->handle);
{ {
// NOTE: Setup entity-tree ================================================================= // NOTE: Setup entity-tree =================================================================
@@ -384,7 +384,7 @@ void FP_UnitTests(TELY_Platform *platform)
FP_GameEntity *pre_order_walk[9] = {}; FP_GameEntity *pre_order_walk[9] = {};
Dqn_usize pre_order_walk_count = 0; Dqn_usize pre_order_walk_count = 0;
for (FP_GameEntityIterator it = {}; FP_Game_DFSPreOrderWalkEntityTree(game, &it, game->root_entity);) { for (FP_GameEntityIterator it = {}; FP_Game_DFSPreOrderWalkEntityTree(game, &it, game->play.root_entity);) {
DQN_ASSERT(pre_order_walk_count < DQN_ARRAY_UCOUNT(pre_order_walk)); DQN_ASSERT(pre_order_walk_count < DQN_ARRAY_UCOUNT(pre_order_walk));
pre_order_walk[pre_order_walk_count++] = it.entity; pre_order_walk[pre_order_walk_count++] = it.entity;
} }
@@ -404,7 +404,7 @@ void FP_UnitTests(TELY_Platform *platform)
FP_GameEntity *post_order_walk[9] = {}; FP_GameEntity *post_order_walk[9] = {};
Dqn_usize post_order_walk_count = 0; Dqn_usize post_order_walk_count = 0;
for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity);) { for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->play.root_entity);) {
DQN_ASSERT(post_order_walk_count < DQN_ARRAY_UCOUNT(post_order_walk)); DQN_ASSERT(post_order_walk_count < DQN_ARRAY_UCOUNT(post_order_walk));
post_order_walk[post_order_walk_count++] = it.entity; post_order_walk[post_order_walk_count++] = it.entity;
} }
@@ -421,11 +421,11 @@ void FP_UnitTests(TELY_Platform *platform)
DQN_ASSERT(post_order_walk[8] == f); DQN_ASSERT(post_order_walk[8] == f);
// NOTE: Cleanup =========================================================================== // NOTE: Cleanup ===========================================================================
FP_Game_DeleteEntity(game, game->root_entity->handle); FP_Game_DeleteEntity(game, game->play.root_entity->handle);
DQN_ASSERT(game->root_entity->first_child == nullptr); DQN_ASSERT(game->play.root_entity->first_child == nullptr);
DQN_ASSERT(game->root_entity->last_child == nullptr); DQN_ASSERT(game->play.root_entity->last_child == nullptr);
DQN_ASSERT(game->root_entity->next == nullptr); DQN_ASSERT(game->play.root_entity->next == nullptr);
DQN_ASSERT(game->root_entity->prev == nullptr); DQN_ASSERT(game->play.root_entity->prev == nullptr);
DQN_ASSERT(game->root_entity->parent == nullptr); DQN_ASSERT(game->play.root_entity->parent == nullptr);
} }
} }