tely/asset: Load up the merchant

This commit is contained in:
doyle 2023-09-24 18:05:28 +10:00
parent ea9f63d709
commit d3444c84f1
62 changed files with 665 additions and 519 deletions

BIN
Data/Textures/smoochie_resized_25%.png (Stored with Git LFS)

Binary file not shown.

BIN
Data/Textures/smoochie_resized_25%.txt (Stored with Git LFS)

Binary file not shown.

BIN
Data/Textures/sprite_spec.txt (Stored with Git LFS)

Binary file not shown.

BIN
Data/Textures/terry_merchant_resized_25%.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Data/Textures/terry_merchant_resized_25%.txt (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Data/Textures/terry_resized_25%.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Data/Textures/terry_resized_25%.txt (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Data/Textures/terry_resized_25%/terry_attack_down_1.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Data/Textures/terry_resized_25%/terry_attack_down_2.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Data/Textures/terry_resized_25%/terry_attack_down_3.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Data/Textures/terry_resized_25%/terry_attack_side_1.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Data/Textures/terry_resized_25%/terry_attack_side_2.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Data/Textures/terry_resized_25%/terry_attack_side_3.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Data/Textures/terry_resized_25%/terry_attack_up_1.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Data/Textures/terry_resized_25%/terry_attack_up_2.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Data/Textures/terry_resized_25%/terry_attack_up_3.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Data/Textures/terry_walk_resized_25%.png (Stored with Git LFS)

Binary file not shown.

BIN
Data/Textures/terry_walk_resized_25%.txt (Stored with Git LFS)

Binary file not shown.

View File

@ -10,5 +10,6 @@ if not exist "%sprite_packer%" (
exit /B 1 exit /B 1
) )
%sprite_packer% 4096x2048 %script_dir%\Data\Textures\sprite_spec.txt %script_dir%\Data\Textures\terry_walk_resized_25%% %sprite_packer% 4096x4096 %script_dir%\Data\Textures\sprite_spec.txt %script_dir%\Data\Textures\terry_resized_25%% || exit /b 1
%sprite_packer% 4096x2048 %script_dir%\Data\Textures\sprite_spec.txt %script_dir%\Data\Textures\smoochie_resized_25%% %sprite_packer% 4096x2048 %script_dir%\Data\Textures\sprite_spec.txt %script_dir%\Data\Textures\terry_merchant_resized_25%% || exit /b 1
%sprite_packer% 4096x2048 %script_dir%\Data\Textures\sprite_spec.txt %script_dir%\Data\Textures\smoochie_resized_25%% || exit /b 1

View File

@ -5,18 +5,23 @@
struct FP_GlobalAnimations struct FP_GlobalAnimations
{ {
Dqn_String8 terry_walk_idle = DQN_STRING8("terry_walk_idle"); Dqn_String8 terry_walk_idle = DQN_STRING8("terry_walk_idle");
Dqn_String8 terry_walk_up = DQN_STRING8("terry_walk_up"); Dqn_String8 terry_walk_up = DQN_STRING8("terry_walk_up");
Dqn_String8 terry_walk_down = DQN_STRING8("terry_walk_down"); Dqn_String8 terry_walk_down = DQN_STRING8("terry_walk_down");
Dqn_String8 terry_walk_left = DQN_STRING8("terry_walk_left"); Dqn_String8 terry_walk_left = DQN_STRING8("terry_walk_left");
Dqn_String8 terry_walk_right = DQN_STRING8("terry_walk_right"); Dqn_String8 terry_walk_right = DQN_STRING8("terry_walk_right");
Dqn_String8 terry_attack_up = DQN_STRING8("terry_attack_up");
Dqn_String8 smoochie_walk_up = DQN_STRING8("smoochie_walk_up"); Dqn_String8 terry_attack_side = DQN_STRING8("terry_attack_side");
Dqn_String8 smoochie_walk_down = DQN_STRING8("smoochie_walk_down"); Dqn_String8 terry_attack_down = DQN_STRING8("terry_attack_down");
Dqn_String8 smoochie_walk_left = DQN_STRING8("smoochie_walk_left"); Dqn_String8 terry_merchant = DQN_STRING8("terry_merchant");
Dqn_String8 smoochie_walk_right = DQN_STRING8("smoochie_walk_right"); Dqn_String8 smoochie_walk_up = DQN_STRING8("smoochie_walk_up");
Dqn_String8 smoochie_attack = DQN_STRING8("smoochie_attack"); Dqn_String8 smoochie_walk_down = DQN_STRING8("smoochie_walk_down");
Dqn_String8 smoochie_death = DQN_STRING8("smoochie_death"); Dqn_String8 smoochie_walk_left = DQN_STRING8("smoochie_walk_left");
Dqn_String8 smoochie_walk_right = DQN_STRING8("smoochie_walk_right");
Dqn_String8 smoochie_attack_down = DQN_STRING8("smoochie_attack");
Dqn_String8 smoochie_attack_side = DQN_STRING8("smoochie_attack_side");
Dqn_String8 smoochie_attack_heart = DQN_STRING8("smoochie_attack_heart");
Dqn_String8 smoochie_death = DQN_STRING8("smoochie_death");
} }
g_anim_names; g_anim_names;
@ -117,352 +122,13 @@ void TELY_DLL_Init(void *user_data)
TELY_Platform *platform = DQN_CAST(TELY_Platform *)user_data; TELY_Platform *platform = DQN_CAST(TELY_Platform *)user_data;
TELY_DLL_Reload(user_data); TELY_DLL_Reload(user_data);
{ FP_UnitTests(platform);
uint32_t array[] = {1};
Dqn_BinarySearchResult result = {};
// NOTE: Match =============================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 1);
// NOTE: Lower bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 1);
// NOTE: Upper bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 1);
}
{
uint32_t array[] = {1, 2};
// NOTE: Match =============================================================================
Dqn_BinarySearchResult result = {};
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 2);
// NOTE: Lower bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 2);
// NOTE: Upper bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 2);
}
{
uint32_t array[] = {1, 2, 3};
Dqn_BinarySearchResult result = {};
// NOTE: Match =============================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 4U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 3);
// NOTE: Lower bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 4U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 3);
// NOTE: Upper bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 3);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 4U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 3);
}
{
uint32_t array[] = {1, 2, 3, 4};
Dqn_BinarySearchResult result = {};
// NOTE: Match =============================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 4U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 3);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 5U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 4);
// NOTE: Lower bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 4U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 3);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 5U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 4);
// NOTE: Upper bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 3);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 4U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 4);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 5U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 4);
}
{
uint32_t array[] = {1, 1, 2, 2, 3};
Dqn_BinarySearchResult result = {};
// NOTE: Match =============================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 4);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 4U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 5);
// NOTE: Lower bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 4);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 4U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 5);
// NOTE: Upper bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 4);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 5);
}
{
Dqn_Arena_TempMemoryScope(&platform->arena);
TELY_ChunkPool pool = {};
pool.arena = &platform->arena;
void *bytes16 = TELY_ChunkPool_Alloc(&pool, 16);
TELY_ChunkPool_Dealloc(&pool, bytes16);
DQN_ASSERT(pool.slots[TELY_ChunkPoolSlotSize_16b] == DQN_CAST(void *)(DQN_CAST(char *)bytes16 - sizeof(TELY_ChunkPoolSlot)));
DQN_ASSERT(pool.slots[TELY_ChunkPoolSlotSize_16b]->next == nullptr);
void *bytes17 = TELY_ChunkPool_Alloc(&pool, 17);
TELY_ChunkPool_Dealloc(&pool, bytes17);
DQN_ASSERT(pool.slots[TELY_ChunkPoolSlotSize_32b] == DQN_CAST(void *)(DQN_CAST(char *)bytes17 - sizeof(TELY_ChunkPoolSlot)));
DQN_ASSERT(pool.slots[TELY_ChunkPoolSlotSize_32b]->next == nullptr);
void *bytes1 = TELY_ChunkPool_Alloc(&pool, 1);
void *bytes2 = TELY_ChunkPool_Alloc(&pool, 1);
TELY_ChunkPool_Dealloc(&pool, bytes1);
TELY_ChunkPool_Dealloc(&pool, bytes2);
DQN_ASSERT(pool.slots[TELY_ChunkPoolSlotSize_16b] == DQN_CAST(void *)(DQN_CAST(char *)bytes2 - sizeof(TELY_ChunkPoolSlot)));
DQN_ASSERT(pool.slots[TELY_ChunkPoolSlotSize_16b]->next == DQN_CAST(void *)(DQN_CAST(char *)bytes1 - sizeof(TELY_ChunkPoolSlot)));
void *bytes128k = TELY_ChunkPool_Alloc(&pool, DQN_KILOBYTES(128));
TELY_ChunkPool_Dealloc(&pool, bytes128k);
DQN_ASSERT(pool.slots[TELY_ChunkPoolSlotSize_128k] == DQN_CAST(void *)(DQN_CAST(char *)bytes128k - sizeof(TELY_ChunkPoolSlot)));
DQN_ASSERT(pool.slots[TELY_ChunkPoolSlotSize_128k]->next == nullptr);
}
// NOTE: TELY Game ============================================================================= // NOTE: TELY Game =============================================================================
TELY_Assets *assets = &platform->assets; TELY_Assets *assets = &platform->assets;
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 = &platform->chunk_pool; game->chunk_pool = &platform->chunk_pool;
platform->user_data = game; platform->user_data = game;
{ {
TELY_AssetSpriteSheet *sheet = &game->hero_sprite_sheet; TELY_AssetSpriteSheet *sheet = &game->hero_sprite_sheet;
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
@ -501,24 +167,34 @@ void TELY_DLL_Init(void *user_data)
// NOTE: Load sprite sheets ==================================================================== // NOTE: Load sprite sheets ====================================================================
{ {
game->terry_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("terry_walk_resized_25%")); game->terry_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("terry_resized_25%"));
game->terry_action_mappings = Dqn_Slice_CopyArray<FP_ActionToAnimationMapping>(&platform->arena, { game->terry_action_mappings = Dqn_Slice_CopyArray<FP_ActionToAnimationMapping>(&platform->arena, {
{FP_ActionType_Idle, &game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_idle)}, {&game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_idle)},
{FP_ActionType_WalkUp, &game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_up)}, {&game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_up)},
{FP_ActionType_WalkDown, &game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_down)}, {&game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_down)},
{FP_ActionType_WalkLeft, &game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_left)}, {&game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_left)},
{FP_ActionType_WalkRight, &game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_right)}, {&game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_walk_right)},
{&game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_attack_up)},
{&game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_attack_side)},
{&game->terry_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_sprite_sheet, g_anim_names.terry_attack_down)},
});
game->terry_merchant_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("terry_merchant_resized_25%"));
game->terry_merchant_action_mappings = Dqn_Slice_CopyArray<FP_ActionToAnimationMapping>(&platform->arena, {
{&game->terry_merchant_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->terry_merchant_sprite_sheet, g_anim_names.terry_merchant)},
}); });
game->smoochie_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("smoochie_resized_25%")); game->smoochie_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("smoochie_resized_25%"));
game->smoochie_action_mappings = Dqn_Slice_CopyArray<FP_ActionToAnimationMapping>(&platform->arena, { game->smoochie_action_mappings = Dqn_Slice_CopyArray<FP_ActionToAnimationMapping>(&platform->arena, {
{FP_ActionType_Idle, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_down)}, {&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_down)},
{FP_ActionType_WalkUp, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_up)}, {&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_up)},
{FP_ActionType_WalkDown, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_down)}, {&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_down)},
{FP_ActionType_WalkLeft, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_left)}, {&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_left)},
{FP_ActionType_WalkRight, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_right)}, {&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_walk_right)},
{FP_ActionType_Attack, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_attack)}, {&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_attack_down)},
{FP_ActionType_Death, &game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_death)}, {&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_attack_side)},
{&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_attack_heart)},
{&game->smoochie_sprite_sheet, TELY_Asset_GetSpriteAnimation(&game->smoochie_sprite_sheet, g_anim_names.smoochie_death)},
}); });
} }
@ -526,80 +202,6 @@ void TELY_DLL_Init(void *user_data)
game->root_entity = Dqn_VArray_Make(&game->entities, Dqn_ZeroMem_No); game->root_entity = Dqn_VArray_Make(&game->entities, Dqn_ZeroMem_No);
Dqn_FArray_Add(&game->parent_entity_stack, game->root_entity->handle); Dqn_FArray_Add(&game->parent_entity_stack, game->root_entity->handle);
// NOTE: Unit test DFS pre-order and post-order walk
{
// NOTE: Setup entity-tree =================================================================
FP_GameEntity *f = FP_Game_MakeEntityPointerF(game, "F");
FP_Game_PushParentEntity(game, f->handle);
FP_GameEntity *b = FP_Game_MakeEntityPointerF(game, "B");
FP_GameEntity *g = FP_Game_MakeEntityPointerF(game, "G");
FP_Game_PushParentEntity(game, b->handle);
FP_GameEntity *a = FP_Game_MakeEntityPointerF(game, "A");
FP_GameEntity *d = FP_Game_MakeEntityPointerF(game, "D");
FP_Game_PushParentEntity(game, d->handle);
FP_GameEntity *c = FP_Game_MakeEntityPointerF(game, "C");
FP_GameEntity *e = FP_Game_MakeEntityPointerF(game, "E");
FP_Game_PopParentEntity(game);
FP_Game_PopParentEntity(game);
FP_Game_PushParentEntity(game, g->handle);
FP_GameEntity *i = FP_Game_MakeEntityPointerF(game, "I");
FP_Game_PushParentEntity(game, i->handle);
FP_GameEntity *h = FP_Game_MakeEntityPointerF(game, "H");
FP_Game_PopParentEntity(game);
FP_Game_PopParentEntity(game);
FP_Game_PopParentEntity(game);
// NOTE: Pre order test ====================================================================
FP_GameEntity *pre_order_walk[9] = {};
Dqn_usize pre_order_walk_count = 0;
for (FP_GameEntityIterator it = {}; FP_Game_DFSPreOrderWalkEntityTree(game, &it, game->root_entity);) {
DQN_ASSERT(pre_order_walk_count < DQN_ARRAY_UCOUNT(pre_order_walk));
pre_order_walk[pre_order_walk_count++] = it.entity;
}
DQN_ASSERT(pre_order_walk_count == DQN_ARRAY_UCOUNT(pre_order_walk));
DQN_ASSERT(pre_order_walk[0] == f);
DQN_ASSERT(pre_order_walk[1] == b);
DQN_ASSERT(pre_order_walk[2] == a);
DQN_ASSERT(pre_order_walk[3] == d);
DQN_ASSERT(pre_order_walk[4] == c);
DQN_ASSERT(pre_order_walk[5] == e);
DQN_ASSERT(pre_order_walk[6] == g);
DQN_ASSERT(pre_order_walk[7] == i);
DQN_ASSERT(pre_order_walk[8] == h);
// NOTE: Post order test ===================================================================
FP_GameEntity *post_order_walk[9] = {};
Dqn_usize post_order_walk_count = 0;
for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity);) {
DQN_ASSERT(post_order_walk_count < DQN_ARRAY_UCOUNT(post_order_walk));
post_order_walk[post_order_walk_count++] = it.entity;
}
DQN_ASSERT(post_order_walk_count == DQN_ARRAY_UCOUNT(post_order_walk));
DQN_ASSERT(post_order_walk[0] == a);
DQN_ASSERT(post_order_walk[1] == c);
DQN_ASSERT(post_order_walk[2] == e);
DQN_ASSERT(post_order_walk[3] == d);
DQN_ASSERT(post_order_walk[4] == b);
DQN_ASSERT(post_order_walk[5] == h);
DQN_ASSERT(post_order_walk[6] == i);
DQN_ASSERT(post_order_walk[7] == g);
DQN_ASSERT(post_order_walk[8] == f);
// NOTE: Cleanup ===========================================================================
FP_Game_DeleteEntity(game, game->root_entity->handle);
DQN_ASSERT(game->root_entity->first_child == nullptr);
DQN_ASSERT(game->root_entity->last_child == nullptr);
DQN_ASSERT(game->root_entity->next == nullptr);
DQN_ASSERT(game->root_entity->prev == nullptr);
DQN_ASSERT(game->root_entity->parent == nullptr);
}
// NOTE: Hero // NOTE: Hero
{ {
TELY_AssetSpriteSheet *sheet = &game->terry_sprite_sheet; TELY_AssetSpriteSheet *sheet = &game->terry_sprite_sheet;
@ -607,7 +209,7 @@ void TELY_DLL_Init(void *user_data)
entity->local_pos = Dqn_V2_InitNx2(1334, 396); entity->local_pos = Dqn_V2_InitNx2(1334, 396);
entity->action_to_anim_mapping = game->terry_action_mappings; entity->action_to_anim_mapping = game->terry_action_mappings;
entity->size_scale = Dqn_V2_InitNx1(0.25f); entity->size_scale = Dqn_V2_InitNx1(0.25f);
entity->local_hit_box_size = Dqn_V2_InitV2I(sheet->sprite_size); entity->local_hit_box_size = Dqn_V2_InitNx2(428, 471) * entity->size_scale;
entity->flags |= FP_GameEntityFlag_Clickable; entity->flags |= FP_GameEntityFlag_Clickable;
entity->flags |= FP_GameEntityFlag_MoveByKeyboard; entity->flags |= FP_GameEntityFlag_MoveByKeyboard;
entity->flags |= FP_GameEntityFlag_MoveByMouse; entity->flags |= FP_GameEntityFlag_MoveByMouse;
@ -618,6 +220,21 @@ void TELY_DLL_Init(void *user_data)
game->player = entity->handle; game->player = entity->handle;
} }
// NOTE: Merchant
{
FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "Merchant");
entity->type = FP_GameEntityType_Merchant;
entity->local_pos = Dqn_V2_InitNx2(1000, 124);
entity->local_hit_box_size = Dqn_V2_InitNx2(50, 50);
entity->size_scale = Dqn_V2_InitNx1(0.25f);
entity->action_to_anim_mapping = game->terry_merchant_action_mappings;
entity->flags |= FP_GameEntityFlag_Clickable;
entity->flags |= FP_GameEntityFlag_MoveByKeyboard;
entity->flags |= FP_GameEntityFlag_MoveByMouse;
entity->flags |= FP_GameEntityFlag_MoveByGamepad;
entity->flags |= FP_GameEntityFlag_NonTraversable;
}
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;
@ -684,19 +301,6 @@ void TELY_DLL_Init(void *user_data)
game->test_audio = platform->func_load_audio(assets, DQN_STRING8("Test Audio"), DQN_STRING8("Data/Audio/Purrple Cat - Moonwinds.qoa")); game->test_audio = platform->func_load_audio(assets, DQN_STRING8("Test Audio"), DQN_STRING8("Data/Audio/Purrple Cat - Moonwinds.qoa"));
} }
FP_ActionToAnimationMapping FP_Game_GetActionAnimMappingForType(FP_Game *game, FP_GameEntityHandle entity_handle, FP_ActionType type)
{
FP_GameEntity *entity = FP_Game_GetEntity(game, entity_handle);
FP_ActionToAnimationMapping result = {};
for (FP_ActionToAnimationMapping const &mapping : entity->action_to_anim_mapping) {
if (mapping.action_type == type) {
result = mapping;
break;
}
}
return result;
}
FP_ActionToAnimationMapping FP_Game_GetActionAnimMappingWithName(FP_Game *game, FP_GameEntityHandle entity_handle, Dqn_String8 name) FP_ActionToAnimationMapping FP_Game_GetActionAnimMappingWithName(FP_Game *game, FP_GameEntityHandle entity_handle, Dqn_String8 name)
{ {
FP_GameEntity *entity = FP_Game_GetEntity(game, entity_handle); FP_GameEntity *entity = FP_Game_GetEntity(game, entity_handle);
@ -710,7 +314,6 @@ FP_ActionToAnimationMapping FP_Game_GetActionAnimMappingWithName(FP_Game *game,
return result; return result;
} }
FP_ActionToAnimationMapping FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_GameEntity *entity, Dqn_V2 dir_vector) FP_ActionToAnimationMapping FP_EntityActionStateMachine(FP_Game *game, TELY_PlatformInput *input, FP_GameEntity *entity, Dqn_V2 dir_vector)
{ {
FP_GameEntityAction *action = &entity->action; FP_GameEntityAction *action = &entity->action;
@ -733,21 +336,42 @@ FP_ActionToAnimationMapping FP_EntityActionStateMachine(FP_Game *game, TELY_Plat
} else if (we_are_clicked_entity) { } else if (we_are_clicked_entity) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) || if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) { TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
FP_Game_EntityActionSetState(action, FP_GameTerryState_AttackA); switch (entity->direction) {
case FP_GameDirection_Up: {
FP_Game_EntityActionSetState(action, FP_GameTerryState_AttackUp);
} break;
case FP_GameDirection_Left: {
FP_Game_EntityActionSetState(action, FP_GameTerryState_AttackSide);
} break;
case FP_GameDirection_Right: {
FP_Game_EntityActionSetState(action, FP_GameTerryState_AttackSide);
} break;
case FP_GameDirection_Down: {
FP_Game_EntityActionSetState(action, FP_GameTerryState_AttackDown);
} break;
}
} else if (dir_vector.x || dir_vector.y) { } else if (dir_vector.x || dir_vector.y) {
FP_Game_EntityActionSetState(action, FP_GameTerryState_Run); FP_Game_EntityActionSetState(action, FP_GameTerryState_Run);
} }
} }
} }
if (*state == FP_GameTerryState_AttackA) { if (*state == FP_GameTerryState_AttackSide) {
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_walk_right); result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_attack_side);
action->flip_on_x = entity->direction == FP_GameDirection_Right;
if (action->flags & FP_GameEntityActionFlag_StateTransition) { if (action->flags & FP_GameEntityActionFlag_StateTransition) {
FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result); FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result);
} else if (action_has_finished) { } else if (action_has_finished) {
FP_Game_EntityActionSetState(action, FP_GameTerryState_Idle); FP_Game_EntityActionSetState(action, FP_GameTerryState_Idle);
} else if (!FP_Game_EntityActionHasFailed(action) && we_are_clicked_entity) { action->flip_on_x = false;
}
#if 0
else if (!FP_Game_EntityActionHasFailed(action) && we_are_clicked_entity) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) || if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) { TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
Dqn_f32 t01 = action->timer_s / action->end_at_s; Dqn_f32 t01 = action->timer_s / action->end_at_s;
@ -757,30 +381,20 @@ FP_ActionToAnimationMapping FP_EntityActionStateMachine(FP_Game *game, TELY_Plat
action->flags |= FP_GameEntityActionFlag_Failed; action->flags |= FP_GameEntityActionFlag_Failed;
} }
} }
#endif
} }
if (*state == FP_GameTerryState_AttackB) { if (*state == FP_GameTerryState_AttackUp) {
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_walk_right); result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_attack_up);
if (action->flags & FP_GameEntityActionFlag_StateTransition) { if (action->flags & FP_GameEntityActionFlag_StateTransition) {
FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result); FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result);
} else if (action_has_finished) { } else if (action_has_finished) {
FP_Game_EntityActionSetState(action, FP_GameTerryState_Idle); FP_Game_EntityActionSetState(action, FP_GameTerryState_Idle);
} else if (!FP_Game_EntityActionHasFailed(action) && we_are_clicked_entity) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
Dqn_f32 t01 = action->timer_s / action->end_at_s;
if (t01 > 0.5f)
FP_Game_EntityActionSetState(action, FP_GameTerryState_AttackC);
else
action->flags |= FP_GameEntityActionFlag_Failed;
}
} }
} }
if (*state == FP_GameTerryState_AttackC) { if (*state == FP_GameTerryState_AttackDown) {
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_walk_right); result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_attack_down);
if (action->flags & FP_GameEntityActionFlag_StateTransition) { if (action->flags & FP_GameEntityActionFlag_StateTransition) {
FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result); FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result);
} else if (action_has_finished) { } else if (action_has_finished) {
@ -801,7 +415,23 @@ FP_ActionToAnimationMapping FP_EntityActionStateMachine(FP_Game *game, TELY_Plat
if (we_are_clicked_entity) { if (we_are_clicked_entity) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) || if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) { TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
FP_Game_EntityActionSetState(action, FP_GameTerryState_AttackA); switch (entity->direction) {
case FP_GameDirection_Up: {
FP_Game_EntityActionSetState(action, FP_GameTerryState_AttackUp);
} break;
case FP_GameDirection_Left: {
FP_Game_EntityActionSetState(action, FP_GameTerryState_AttackSide);
} break;
case FP_GameDirection_Right: {
FP_Game_EntityActionSetState(action, FP_GameTerryState_AttackSide);
} break;
case FP_GameDirection_Down: {
FP_Game_EntityActionSetState(action, FP_GameTerryState_AttackDown);
} break;
}
} else if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_LeftShift) || } else if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_LeftShift) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_A)) { TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_A)) {
FP_Game_EntityActionSetState(action, FP_GameTerryState_Dash); FP_Game_EntityActionSetState(action, FP_GameTerryState_Dash);
@ -809,7 +439,7 @@ FP_ActionToAnimationMapping FP_EntityActionStateMachine(FP_Game *game, TELY_Plat
} }
// NOTE: Also handles state transition // NOTE: Also handles state transition
if (action->mapping.action_type != result.action_type) { if (action->mapping.anim.label != result.anim.label) {
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, result); FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, result);
} }
@ -846,9 +476,9 @@ FP_ActionToAnimationMapping FP_EntityActionStateMachine(FP_Game *game, TELY_Plat
} }
} }
if (*state == FP_GameTerryState_AttackA || if (*state == FP_GameTerryState_AttackUp ||
*state == FP_GameTerryState_AttackB || *state == FP_GameTerryState_AttackDown ||
*state == FP_GameTerryState_AttackC) { *state == FP_GameTerryState_AttackSide) {
entity->attack_box_size = entity->local_hit_box_size; entity->attack_box_size = entity->local_hit_box_size;
// NOTE: Position the attack box // NOTE: Position the attack box
@ -877,16 +507,26 @@ FP_ActionToAnimationMapping FP_EntityActionStateMachine(FP_Game *game, TELY_Plat
} else if (we_are_clicked_entity) { } else if (we_are_clicked_entity) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) || if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) { TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
FP_Game_EntityActionSetState(action, FP_GameSmoochieState_Attack);
switch (entity->direction) {
case FP_GameDirection_Up: /*FALLTHRU*/
case FP_GameDirection_Right: /*FALLTHRU*/
case FP_GameDirection_Left: {
FP_Game_EntityActionSetState(action, FP_GameSmoochieState_AttackSide);
} break;
case FP_GameDirection_Down: {
FP_Game_EntityActionSetState(action, FP_GameSmoochieState_AttackDown);
} break;
}
} else if (dir_vector.x || dir_vector.y) { } else if (dir_vector.x || dir_vector.y) {
FP_Game_EntityActionSetState(action, FP_GameSmoochieState_Run); FP_Game_EntityActionSetState(action, FP_GameSmoochieState_Run);
} }
} }
} }
if (*state == FP_GameSmoochieState_Attack) { if (*state == FP_GameSmoochieState_AttackDown) {
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.smoochie_attack); result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.smoochie_attack_down);
if (action->flags & FP_GameEntityActionFlag_StateTransition) { if (action->flags & FP_GameEntityActionFlag_StateTransition) {
FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result); FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result);
} else if (action_has_finished) { } else if (action_has_finished) {
@ -894,6 +534,17 @@ FP_ActionToAnimationMapping FP_EntityActionStateMachine(FP_Game *game, TELY_Plat
} }
} }
if (*state == FP_GameSmoochieState_AttackSide) {
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.smoochie_attack_side);
action->flip_on_x = entity->direction == FP_GameDirection_Right;
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
FP_Game_EntityActionReset(action, result.anim.count * result.anim.seconds_per_frame, result);
} else if (action_has_finished) {
FP_Game_EntityActionSetState(action, FP_GameSmoochieState_Idle);
action->flip_on_x = false;
}
}
if (*state == FP_GameSmoochieState_Run) { if (*state == FP_GameSmoochieState_Run) {
Dqn_String8 desired_action_name = {}; Dqn_String8 desired_action_name = {};
switch (entity->direction) { switch (entity->direction) {
@ -907,12 +558,23 @@ FP_ActionToAnimationMapping FP_EntityActionStateMachine(FP_Game *game, TELY_Plat
if (we_are_clicked_entity) { if (we_are_clicked_entity) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) || if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) { TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
FP_Game_EntityActionSetState(action, FP_GameSmoochieState_Attack);
switch (entity->direction) {
case FP_GameDirection_Up: /*FALLTHRU*/
case FP_GameDirection_Right: /*FALLTHRU*/
case FP_GameDirection_Left: {
FP_Game_EntityActionSetState(action, FP_GameSmoochieState_AttackSide);
} break;
case FP_GameDirection_Down: {
FP_Game_EntityActionSetState(action, FP_GameSmoochieState_AttackDown);
} break;
}
} }
} }
// NOTE: Also handles state transition // NOTE: Also handles state transition
if (action->mapping.action_type != result.action_type) { if (action->mapping.anim.label != result.anim.label) {
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, result); FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, result);
} }
@ -921,7 +583,7 @@ FP_ActionToAnimationMapping FP_EntityActionStateMachine(FP_Game *game, TELY_Plat
} }
} }
if (*state == FP_GameSmoochieState_Attack) { if (*state == FP_GameSmoochieState_AttackSide || *state == FP_GameSmoochieState_AttackDown) {
entity->attack_box_size = entity->local_hit_box_size; entity->attack_box_size = entity->local_hit_box_size;
// NOTE: Position the attack box // NOTE: Position the attack box
if (entity->direction == FP_GameDirection_Left) { if (entity->direction == FP_GameDirection_Left) {
@ -936,6 +598,19 @@ FP_ActionToAnimationMapping FP_EntityActionStateMachine(FP_Game *game, TELY_Plat
} }
} break; } break;
case FP_GameEntityType_Merchant: {
FP_GameTerryMerchantState *state = DQN_CAST(FP_GameTerryMerchantState *)&action->state;
if (*state == FP_GameTerryMerchantState_Nil)
FP_Game_EntityActionSetState(action, FP_GameTerryMerchantState_Idle);
if (*state == FP_GameTerryMerchantState_Idle) {
result = FP_Game_GetActionAnimMappingWithName(game, entity->handle, g_anim_names.terry_merchant);
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, result);
}
}
} break;
} }
// NOTE: Tick entity action ================================================================ // NOTE: Tick entity action ================================================================
@ -1330,10 +1005,8 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer)
dest_rect.size = src_rect.size * entity->size_scale; dest_rect.size = src_rect.size * entity->size_scale;
dest_rect.pos = world_pos - (dest_rect.size * .5f); dest_rect.pos = world_pos - (dest_rect.size * .5f);
#if 0 if (action->flip_on_x)
if (entity->direction == FP_GameDirection_Left)
dest_rect.size.w *= -1.f; // NOTE: Flip the texture horizontally dest_rect.size.w *= -1.f; // NOTE: Flip the texture horizontally
#endif
TELY_Render_TextureColourV4(renderer, sprite_sheet->tex_handle, src_rect, dest_rect, TELY_COLOUR_WHITE_V4); TELY_Render_TextureColourV4(renderer, sprite_sheet->tex_handle, src_rect, dest_rect, TELY_COLOUR_WHITE_V4);
} }

View File

@ -58,20 +58,8 @@ enum FP_GameEntityActionFlag
FP_GameEntityActionFlag_Failed = 1 << 1, FP_GameEntityActionFlag_Failed = 1 << 1,
}; };
enum FP_ActionType
{
FP_ActionType_Idle,
FP_ActionType_Attack,
FP_ActionType_WalkUp,
FP_ActionType_WalkDown,
FP_ActionType_WalkLeft,
FP_ActionType_WalkRight,
FP_ActionType_Death,
};
struct FP_ActionToAnimationMapping struct FP_ActionToAnimationMapping
{ {
FP_ActionType action_type;
TELY_AssetSpriteSheet *sheet; TELY_AssetSpriteSheet *sheet;
TELY_AssetSpriteAnimation anim; TELY_AssetSpriteAnimation anim;
}; };
@ -79,6 +67,7 @@ struct FP_ActionToAnimationMapping
Dqn_f32 const FP_GAME_ENTITY_ACTION_INFINITE_TIMER = -1.f; Dqn_f32 const FP_GAME_ENTITY_ACTION_INFINITE_TIMER = -1.f;
struct FP_GameEntityAction struct FP_GameEntityAction
{ {
bool flip_on_x;
uint32_t state; uint32_t state;
uint32_t flags; // Bit flags corresponding with `FP_GameEntityActionFlag` uint32_t flags; // Bit flags corresponding with `FP_GameEntityActionFlag`
FP_ActionToAnimationMapping mapping; FP_ActionToAnimationMapping mapping;
@ -98,15 +87,16 @@ enum FP_GameEntityType
{ {
FP_GameEntityType_Terry, FP_GameEntityType_Terry,
FP_GameEntityType_Smoochie, FP_GameEntityType_Smoochie,
FP_GameEntityType_Merchant,
}; };
enum FP_GameTerryState enum FP_GameTerryState
{ {
FP_GameTerryState_Nil, FP_GameTerryState_Nil,
FP_GameTerryState_Idle, FP_GameTerryState_Idle,
FP_GameTerryState_AttackA, FP_GameTerryState_AttackUp,
FP_GameTerryState_AttackB, FP_GameTerryState_AttackDown,
FP_GameTerryState_AttackC, FP_GameTerryState_AttackSide,
FP_GameTerryState_Run, FP_GameTerryState_Run,
FP_GameTerryState_Dash, FP_GameTerryState_Dash,
}; };
@ -115,10 +105,18 @@ enum FP_GameSmoochieState
{ {
FP_GameSmoochieState_Nil, FP_GameSmoochieState_Nil,
FP_GameSmoochieState_Idle, FP_GameSmoochieState_Idle,
FP_GameSmoochieState_Attack, FP_GameSmoochieState_AttackDown,
FP_GameSmoochieState_AttackSide,
FP_GameSmoochieState_AttackHeart,
FP_GameSmoochieState_Run, FP_GameSmoochieState_Run,
}; };
enum FP_GameTerryMerchantState
{
FP_GameTerryMerchantState_Nil,
FP_GameTerryMerchantState_Idle,
};
struct FP_GameEntity struct FP_GameEntity
{ {
FP_GameEntity *next; FP_GameEntity *next;
@ -199,6 +197,9 @@ struct FP_Game
TELY_AssetSpriteSheet smoochie_sprite_sheet; TELY_AssetSpriteSheet smoochie_sprite_sheet;
Dqn_Slice<FP_ActionToAnimationMapping> smoochie_action_mappings; Dqn_Slice<FP_ActionToAnimationMapping> smoochie_action_mappings;
TELY_AssetSpriteSheet terry_merchant_sprite_sheet;
Dqn_Slice<FP_ActionToAnimationMapping> terry_merchant_action_mappings;
FP_GameEntity *root_entity; FP_GameEntity *root_entity;
FP_GameEntity *entity_free_list; FP_GameEntity *entity_free_list;

431
feely_pona_misc.cpp Normal file
View File

@ -0,0 +1,431 @@
#if defined(__clang__)
#pragma once
#include "feely_pona_unity.h"
#endif
void FP_UnitTests(TELY_Platform *platform)
{
{
uint32_t array[] = {1};
Dqn_BinarySearchResult result = {};
// NOTE: Match =============================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 1);
// NOTE: Lower bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 1);
// NOTE: Upper bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 1);
}
{
uint32_t array[] = {1, 2};
// NOTE: Match =============================================================================
Dqn_BinarySearchResult result = {};
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 2);
// NOTE: Lower bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 2);
// NOTE: Upper bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 2);
}
{
uint32_t array[] = {1, 2, 3};
Dqn_BinarySearchResult result = {};
// NOTE: Match =============================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 4U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 3);
// NOTE: Lower bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 4U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 3);
// NOTE: Upper bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 3);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 4U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 3);
}
{
uint32_t array[] = {1, 2, 3, 4};
Dqn_BinarySearchResult result = {};
// NOTE: Match =============================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 4U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 3);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 5U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 4);
// NOTE: Lower bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 4U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 3);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 5U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 4);
// NOTE: Upper bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 1);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 3);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 4U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 4);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 5U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 4);
}
{
uint32_t array[] = {1, 1, 2, 2, 3};
Dqn_BinarySearchResult result = {};
// NOTE: Match =============================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 4);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 4U /*find*/, Dqn_BinarySearchType_Match);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 5);
// NOTE: Lower bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 4);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 4U /*find*/, Dqn_BinarySearchType_LowerBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 5);
// NOTE: Upper bound =======================================================================
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 0U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 0);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 1U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 2);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 2U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(result.found);
DQN_ASSERT(result.index == 4);
result = Dqn_BinarySearch<uint32_t>(array, DQN_ARRAY_UCOUNT(array), 3U /*find*/, Dqn_BinarySearchType_UpperBound);
DQN_ASSERT(!result.found);
DQN_ASSERT(result.index == 5);
}
{
Dqn_Arena_TempMemoryScope(&platform->arena);
TELY_ChunkPool pool = {};
pool.arena = &platform->arena;
void *bytes16 = TELY_ChunkPool_Alloc(&pool, 16);
TELY_ChunkPool_Dealloc(&pool, bytes16);
DQN_ASSERT(pool.slots[TELY_ChunkPoolSlotSize_16b] == DQN_CAST(void *)(DQN_CAST(char *)bytes16 - sizeof(TELY_ChunkPoolSlot)));
DQN_ASSERT(pool.slots[TELY_ChunkPoolSlotSize_16b]->next == nullptr);
void *bytes17 = TELY_ChunkPool_Alloc(&pool, 17);
TELY_ChunkPool_Dealloc(&pool, bytes17);
DQN_ASSERT(pool.slots[TELY_ChunkPoolSlotSize_32b] == DQN_CAST(void *)(DQN_CAST(char *)bytes17 - sizeof(TELY_ChunkPoolSlot)));
DQN_ASSERT(pool.slots[TELY_ChunkPoolSlotSize_32b]->next == nullptr);
void *bytes1 = TELY_ChunkPool_Alloc(&pool, 1);
void *bytes2 = TELY_ChunkPool_Alloc(&pool, 1);
TELY_ChunkPool_Dealloc(&pool, bytes1);
TELY_ChunkPool_Dealloc(&pool, bytes2);
DQN_ASSERT(pool.slots[TELY_ChunkPoolSlotSize_16b] == DQN_CAST(void *)(DQN_CAST(char *)bytes2 - sizeof(TELY_ChunkPoolSlot)));
DQN_ASSERT(pool.slots[TELY_ChunkPoolSlotSize_16b]->next == DQN_CAST(void *)(DQN_CAST(char *)bytes1 - sizeof(TELY_ChunkPoolSlot)));
void *bytes128k = TELY_ChunkPool_Alloc(&pool, DQN_KILOBYTES(128));
TELY_ChunkPool_Dealloc(&pool, bytes128k);
DQN_ASSERT(pool.slots[TELY_ChunkPoolSlotSize_128k] == DQN_CAST(void *)(DQN_CAST(char *)bytes128k - sizeof(TELY_ChunkPoolSlot)));
DQN_ASSERT(pool.slots[TELY_ChunkPoolSlotSize_128k]->next == nullptr);
}
// NOTE: Unit test DFS pre-order and post-order walk
Dqn_Arena_TempMemoryScope(&platform->arena);
TELY_ChunkPool chunk_pool = {};
chunk_pool.arena = &platform->arena;
FP_Game *game = Dqn_Arena_New(&platform->arena, FP_Game, Dqn_ZeroMem_Yes);
game->chunk_pool = &chunk_pool;
game->entities = Dqn_VArray_Init<FP_GameEntity>(&platform->arena, 1024 * 8);
game->root_entity = Dqn_VArray_Make(&game->entities, Dqn_ZeroMem_No);
Dqn_FArray_Add(&game->parent_entity_stack, game->root_entity->handle);
{
// NOTE: Setup entity-tree =================================================================
FP_GameEntity *f = FP_Game_MakeEntityPointerF(game, "F");
FP_Game_PushParentEntity(game, f->handle);
FP_GameEntity *b = FP_Game_MakeEntityPointerF(game, "B");
FP_GameEntity *g = FP_Game_MakeEntityPointerF(game, "G");
FP_Game_PushParentEntity(game, b->handle);
FP_GameEntity *a = FP_Game_MakeEntityPointerF(game, "A");
FP_GameEntity *d = FP_Game_MakeEntityPointerF(game, "D");
FP_Game_PushParentEntity(game, d->handle);
FP_GameEntity *c = FP_Game_MakeEntityPointerF(game, "C");
FP_GameEntity *e = FP_Game_MakeEntityPointerF(game, "E");
FP_Game_PopParentEntity(game);
FP_Game_PopParentEntity(game);
FP_Game_PushParentEntity(game, g->handle);
FP_GameEntity *i = FP_Game_MakeEntityPointerF(game, "I");
FP_Game_PushParentEntity(game, i->handle);
FP_GameEntity *h = FP_Game_MakeEntityPointerF(game, "H");
FP_Game_PopParentEntity(game);
FP_Game_PopParentEntity(game);
FP_Game_PopParentEntity(game);
// NOTE: Pre order test ====================================================================
FP_GameEntity *pre_order_walk[9] = {};
Dqn_usize pre_order_walk_count = 0;
for (FP_GameEntityIterator it = {}; FP_Game_DFSPreOrderWalkEntityTree(game, &it, game->root_entity);) {
DQN_ASSERT(pre_order_walk_count < DQN_ARRAY_UCOUNT(pre_order_walk));
pre_order_walk[pre_order_walk_count++] = it.entity;
}
DQN_ASSERT(pre_order_walk_count == DQN_ARRAY_UCOUNT(pre_order_walk));
DQN_ASSERT(pre_order_walk[0] == f);
DQN_ASSERT(pre_order_walk[1] == b);
DQN_ASSERT(pre_order_walk[2] == a);
DQN_ASSERT(pre_order_walk[3] == d);
DQN_ASSERT(pre_order_walk[4] == c);
DQN_ASSERT(pre_order_walk[5] == e);
DQN_ASSERT(pre_order_walk[6] == g);
DQN_ASSERT(pre_order_walk[7] == i);
DQN_ASSERT(pre_order_walk[8] == h);
// NOTE: Post order test ===================================================================
FP_GameEntity *post_order_walk[9] = {};
Dqn_usize post_order_walk_count = 0;
for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity);) {
DQN_ASSERT(post_order_walk_count < DQN_ARRAY_UCOUNT(post_order_walk));
post_order_walk[post_order_walk_count++] = it.entity;
}
DQN_ASSERT(post_order_walk_count == DQN_ARRAY_UCOUNT(post_order_walk));
DQN_ASSERT(post_order_walk[0] == a);
DQN_ASSERT(post_order_walk[1] == c);
DQN_ASSERT(post_order_walk[2] == e);
DQN_ASSERT(post_order_walk[3] == d);
DQN_ASSERT(post_order_walk[4] == b);
DQN_ASSERT(post_order_walk[5] == h);
DQN_ASSERT(post_order_walk[6] == i);
DQN_ASSERT(post_order_walk[7] == g);
DQN_ASSERT(post_order_walk[8] == f);
// NOTE: Cleanup ===========================================================================
FP_Game_DeleteEntity(game, game->root_entity->handle);
DQN_ASSERT(game->root_entity->first_child == nullptr);
DQN_ASSERT(game->root_entity->last_child == nullptr);
DQN_ASSERT(game->root_entity->next == nullptr);
DQN_ASSERT(game->root_entity->prev == nullptr);
DQN_ASSERT(game->root_entity->parent == nullptr);
}
}

View File

@ -65,4 +65,5 @@ DQN_MSVC_WARNING_DISABLE(4505) // warning C4505: unreferenced function with inte
#include "feely_pona.h" #include "feely_pona.h"
#include "feely_pona_game.cpp" #include "feely_pona_game.cpp"
#include "feely_pona_misc.cpp"
#include "feely_pona.cpp" #include "feely_pona.cpp"