diff --git a/src/Debug.c b/src/Debug.c index 5678b03..93d4368 100644 --- a/src/Debug.c +++ b/src/Debug.c @@ -44,12 +44,22 @@ void debug_pushString(char *formatString, void *data, char *dataType) } else if (common_strcmp(dataType, "char") == 0) { - char *val = CAST(char *)data; + if (data) + { + char *val = CAST(char *) data; - snprintf(GLOBAL_debug.debugStrings[numDebugStrings], - ARRAY_COUNT(GLOBAL_debug.debugStrings[0]), - formatString, val); + snprintf(GLOBAL_debug.debugStrings[numDebugStrings], + ARRAY_COUNT(GLOBAL_debug.debugStrings[0]), + formatString, val); + } + else + { + snprintf(GLOBAL_debug.debugStrings[numDebugStrings], + ARRAY_COUNT(GLOBAL_debug.debugStrings[0]), + formatString); + } } + else { ASSERT(INVALID_CODE_PATH); @@ -142,9 +152,9 @@ void debug_drawUi(GameState *state, f32 dt) color); } - for (i32 entityId = 0; entityId < world->maxEntities; entityId++) + for (i32 i = 0; i < world->maxEntities; i++) { - Entity *const entity = &world->entities[entityId]; + Entity *const entity = &world->entities[i]; /* Render debug markers on entities */ v4 color = V4(1, 1, 1, 1); char *debugString = NULL; @@ -189,8 +199,8 @@ void debug_drawUi(GameState *state, f32 dt) strPos.y -= GLOBAL_debug.stringLineGap; char entityIDStr[32]; - snprintf(entityIDStr, ARRAY_COUNT(entityIDStr), "ID: %4d/%d", entityId, - world->maxEntities); + snprintf(entityIDStr, ARRAY_COUNT(entityIDStr), "ID: %4d/%d", entity->id, + world->uniqueIdAccumulator-1); renderer_string(&state->renderer, cameraBounds, font, entityIDStr, strPos, 0, color); @@ -210,27 +220,48 @@ void debug_drawUi(GameState *state, f32 dt) renderer_string(&state->renderer, cameraBounds, font, entityTimer, strPos, 0, color); } + + strPos.y -= GLOBAL_debug.stringLineGap; + char *entityStateStr = debug_entitystate_string(entity->state); + renderer_string(&state->renderer, cameraBounds, font, + entityStateStr, strPos, 0, color); } } /* Render debug info stack */ - DEBUG_PUSH_STRING("Hero Pos: %06.2f, %06.2f", hero->pos, "v2"); - DEBUG_PUSH_STRING("Hero dPos: %06.2f, %06.2f", hero->dPos, "v2"); - DEBUG_PUSH_STRING("Hero Busy Duration: %05.3f", hero->stats->busyDuration, "f32"); + DEBUG_PUSH_STRING("== Hero Properties == "); + DEBUG_PUSH_VAR("Hero Pos: %06.2f, %06.2f", hero->pos, "v2"); + DEBUG_PUSH_VAR("Hero dPos: %06.2f, %06.2f", hero->dPos, "v2"); + DEBUG_PUSH_VAR("Hero Busy Duration: %05.3f", hero->stats->busyDuration, "f32"); char *heroStateString = debug_entitystate_string(hero->state); - DEBUG_PUSH_STRING("Hero State: %s", *heroStateString, "char"); + DEBUG_PUSH_VAR("Hero State: %s", *heroStateString, "char"); char *heroQueuedAttackStr = debug_entityattack_string(hero->stats->queuedAttack); - DEBUG_PUSH_STRING("Hero QueuedAttack: %s", *heroQueuedAttackStr, "char"); - - DEBUG_PUSH_STRING("FreeEntityIndex: %d", world->freeEntityIndex, "i32"); - - DEBUG_PUSH_STRING("glDrawArray Calls: %d", - GLOBAL_debug.callCount[debugcallcount_drawArrays], - "i32"); + DEBUG_PUSH_VAR("Hero QueuedAttack: %s", *heroQueuedAttackStr, "char"); + DEBUG_PUSH_STRING("== State Properties == "); + DEBUG_PUSH_VAR("FreeEntityIndex: %d", world->freeEntityIndex, "i32"); + DEBUG_PUSH_VAR("glDrawArray Calls: %d", + GLOBAL_debug.callCount[debugcallcount_drawArrays], "i32"); i32 debug_kbAllocated = GLOBAL_debug.totalMemoryAllocated / 1024; - DEBUG_PUSH_STRING("TotalMemoryAllocated: %dkb", debug_kbAllocated, "i32"); + DEBUG_PUSH_VAR("TotalMemoryAllocated: %dkb", debug_kbAllocated, "i32"); + + DEBUG_PUSH_STRING("== EntityIDs in Battle List == "); + DEBUG_PUSH_VAR("NumEntitiesInBattle: %d", world->numEntitiesInBattle, + "i32"); + if (world->numEntitiesInBattle > 0) + { + for (i32 i = 0; i < world->maxEntities; i++) + { + if (world->entityIdInBattle[i]) + DEBUG_PUSH_VAR("Entity ID: %d", i, "i32"); + } + } + else + { + DEBUG_PUSH_STRING("-none-"); + } + debug_stringUpdateAndRender(&state->renderer, font, dt); debug_clearCallCounter(); } diff --git a/src/WorldTraveller.c b/src/WorldTraveller.c index 09336f3..ba3563c 100644 --- a/src/WorldTraveller.c +++ b/src/WorldTraveller.c @@ -21,6 +21,7 @@ INTERNAL Entity *addEntity(World *world, v2 pos, v2 size, enum EntityType type, #endif Entity entity = {0}; + entity.id = world->uniqueIdAccumulator++; entity.pos = pos; entity.hitboxSize = size; entity.renderSize = size; @@ -215,12 +216,13 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) World *const world = &state->world[i]; world->maxEntities = 16384; world->entities = PLATFORM_MEM_ALLOC(world->maxEntities, Entity); - world->entitiesInBattleIds = PLATFORM_MEM_ALLOC(world->maxEntities, i32); + world->entityIdInBattle = PLATFORM_MEM_ALLOC(world->maxEntities, i32); world->numEntitiesInBattle = 0; world->texType = texlist_terrain; world->bounds = math_getRect(V2(0, 0), v2_scale(worldDimensionInTiles, CAST(f32) state->tileSize)); + world->uniqueIdAccumulator = 0; TexAtlas *const atlas = asset_getTextureAtlas(assetManager, world->texType); @@ -299,7 +301,9 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) /* Populate mob animation references */ addAnim(assetManager, animlist_hero_idle, mob); addAnim(assetManager, animlist_hero_walk, mob); - mob->currAnimId = animlist_hero_idle; + addAnim(assetManager, animlist_hero_battlePose, mob); + addAnim(assetManager, animlist_hero_tackle, mob); + hero->currAnimId = animlist_hero_idle; } INTERNAL inline void setActiveEntityAnim(Entity *entity, @@ -596,97 +600,168 @@ INTERNAL v4 createCameraBounds(World *world, v2 size) return result; } +#define ENTITY_IN_BATTLE TRUE +#define ENTITY_NOT_IN_BATTLE FALSE +INTERNAL inline void updateWorldBattleEntities(World *world, Entity *entity, + b32 isInBattle) +{ + world->entityIdInBattle[entity->id] = isInBattle; + + if (isInBattle) + world->numEntitiesInBattle++; + else + world->numEntitiesInBattle--; +} + +INTERNAL void entityStateSwitch(World *world, Entity *entity, + enum EntityState newState) +{ + if (entity->state == newState) return; + + switch(entity->state) + { + case entitystate_idle: + switch (newState) + { + case entitystate_battle: + updateWorldBattleEntities(world, entity, ENTITY_IN_BATTLE); + case entitystate_attack: + case entitystate_dead: + break; + default: + ASSERT(INVALID_CODE_PATH); + } + break; + case entitystate_battle: + switch (newState) + { + case entitystate_idle: + updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE); + entity->stats->actionTimer = entity->stats->actionRate; + entity->stats->queuedAttack = entityattack_invalid; + setActiveEntityAnim(entity, animlist_hero_idle); + break; + case entitystate_attack: + case entitystate_dead: + break; + default: + ASSERT(INVALID_CODE_PATH); + } + case entitystate_attack: + switch (newState) + { + case entitystate_idle: + case entitystate_battle: + case entitystate_dead: + break; + default: + ASSERT(INVALID_CODE_PATH); + } + case entitystate_dead: + switch (newState) + { + case entitystate_idle: + case entitystate_battle: + case entitystate_attack: + break; + default: + ASSERT(INVALID_CODE_PATH); + } + } + + entity->state = newState; +} + INTERNAL void updateEntityAndRender(Renderer *renderer, World *world, f32 dt) { - for (i32 entityId = 0; entityId < world->freeEntityIndex; entityId++) + for (i32 i = 0; i < world->freeEntityIndex; i++) { - Entity *const entity = &world->entities[entityId]; + Entity *const entity = &world->entities[i]; Entity *hero = &world->entities[world->heroIndex]; - if (entity->type == entitytype_mob) + switch(entity->type) + { + case entitytype_mob: { - f32 distance = v2_magnitude(hero->pos, entity->pos); - // TODO(doyle): Currently calculated in pixels, how about meaningful // game units? f32 battleThreshold = 500.0f; + f32 distance = v2_magnitude(hero->pos, entity->pos); + + enum EntityState newState = entitystate_invalid; if (distance <= battleThreshold) - { - entity->state = entitystate_battle; - if (!world->entitiesInBattleIds[entityId]) - { - world->entitiesInBattleIds[entityId] = TRUE; - world->numEntitiesInBattle++; - } - } + newState = entitystate_battle; else - { - if (world->entitiesInBattleIds[entityId]) - { - world->entitiesInBattleIds[entityId] = FALSE; - world->numEntitiesInBattle--; - } - entity->state = entitystate_idle; - entity->stats->actionTimer = entity->stats->actionRate; - entity->stats->queuedAttack = entityattack_invalid; - } + newState = entitystate_idle; + + entityStateSwitch(world, entity, newState); } - - if ((entity->state == entitystate_battle || - entity->state == entitystate_attack) && - entity->type == entitytype_hero) + // NOTE(doyle): Allow fall through to entitytype_hero here + case entitytype_hero: { - EntityStats *stats = entity->stats; - if (stats->health > 0) + if (entity->state == entitystate_battle || + entity->state == entitystate_attack) { - if (entity->state == entitystate_battle) + EntityStats *stats = entity->stats; + if (stats->health > 0) { - if (stats->actionTimer > 0) - stats->actionTimer -= dt * stats->actionSpdMul; - - if (stats->actionTimer < 0) + if (entity->state == entitystate_battle) { - stats->actionTimer = 0; - if (stats->queuedAttack == entityattack_invalid) - stats->queuedAttack = entityattack_tackle; + if (stats->actionTimer > 0) + stats->actionTimer -= dt * stats->actionSpdMul; - beginAttack(entity); + if (stats->actionTimer < 0) + { + stats->actionTimer = 0; + if (stats->queuedAttack == entityattack_invalid) + stats->queuedAttack = entityattack_tackle; + + beginAttack(entity); + } + } + else + { + stats->busyDuration -= dt; + if (stats->busyDuration <= 0) + endAttack(world, entity); } } else { - stats->busyDuration -= dt; - if (stats->busyDuration <= 0) - endAttack(world, entity); + // TODO(doyle): Generalise for all entities + hero->stats->entityIdToAttack = -1; + hero->state = entitystate_idle; + entity->state = entitystate_dead; } } - else - { - // TODO(doyle): Generalise for all entities - hero->stats->entityIdToAttack = -1; - hero->state = entitystate_idle; - entity->state = entitystate_dead; - } + break; + } + default: + break; } if (world->numEntitiesInBattle > 0) { if (hero->state == entitystate_idle) + { hero->state = entitystate_battle; + world->entityIdInBattle[hero->id] = TRUE; + } if (hero->stats->entityIdToAttack == -1) - hero->stats->entityIdToAttack = entityId; + hero->stats->entityIdToAttack = i; } else { if (hero->state == entitystate_battle) { - hero->state = entitystate_idle; + hero->state = entitystate_idle; + world->entityIdInBattle[hero->id] = FALSE; setActiveEntityAnim(hero, animlist_hero_idle); } hero->stats->entityIdToAttack = -1; - hero->stats->actionTimer = hero->stats->actionRate; - hero->stats->busyDuration = 0; + hero->stats->actionTimer = hero->stats->actionRate; + hero->stats->busyDuration = 0; } updateEntityAnim(entity, dt); diff --git a/src/include/Dengine/Debug.h b/src/include/Dengine/Debug.h index 0793acc..225cec5 100644 --- a/src/include/Dengine/Debug.h +++ b/src/include/Dengine/Debug.h @@ -10,9 +10,6 @@ #include "WorldTraveller/WorldTraveller.h" #define INVALID_CODE_PATH TRUE -#define DEBUG_PUSH_STRING(formatString, data, type) \ - debug_pushString(formatString, CAST(void *)&data, type) - enum DebugCallCount { debugcallcount_drawArrays, @@ -101,7 +98,12 @@ inline char *debug_entityattack_string(i32 val) void debug_init(); + +#define DEBUG_PUSH_STRING(string) debug_pushString(string, NULL, "char") +#define DEBUG_PUSH_VAR(formatString, data, type) \ + debug_pushString(formatString, CAST(void *)&data, type) void debug_pushString(char *formatString, void *data, char *dataType); + void debug_stringUpdateAndRender(Renderer *renderer, Font *font, f32 dt); void debug_drawUi(GameState *state, f32 dt); diff --git a/src/include/Dengine/Entity.h b/src/include/Dengine/Entity.h index 5f9bd0a..c3e24e6 100644 --- a/src/include/Dengine/Entity.h +++ b/src/include/Dengine/Entity.h @@ -65,6 +65,8 @@ typedef struct EntityAnim_ typedef struct Entity { + u32 id; + v2 pos; // Position v2 dPos; // Velocity v2 hitboxSize; diff --git a/src/include/WorldTraveller/WorldTraveller.h b/src/include/WorldTraveller/WorldTraveller.h index 4537f56..92d195e 100644 --- a/src/include/WorldTraveller/WorldTraveller.h +++ b/src/include/WorldTraveller/WorldTraveller.h @@ -16,9 +16,9 @@ typedef struct World { Entity *entities; i32 maxEntities; - b32 *entitiesInBattleIds; + b32 *entityIdInBattle; i32 numEntitiesInBattle; - + enum TexList texType; v2 cameraPos; // In pixels @@ -26,6 +26,7 @@ typedef struct World i32 heroIndex; i32 freeEntityIndex; + u32 uniqueIdAccumulator; } World; typedef struct GameState