More corner case checks for battle interaction
This commit is contained in:
parent
2707c46df1
commit
7b13615614
@ -330,6 +330,8 @@ void debug_drawUi(GameState *state, f32 dt)
|
|||||||
DEBUG_PUSH_VAR("glDrawArray Calls: %d",
|
DEBUG_PUSH_VAR("glDrawArray Calls: %d",
|
||||||
GLOBAL_debug.callCount[debugcallcount_drawArrays], "i32");
|
GLOBAL_debug.callCount[debugcallcount_drawArrays], "i32");
|
||||||
|
|
||||||
|
i32 debug_bAllocated = state->arena.bytesAllocated;
|
||||||
|
DEBUG_PUSH_VAR("TotalMemoryAllocated: %db", debug_bAllocated, "i32");
|
||||||
i32 debug_kbAllocated = state->arena.bytesAllocated / 1024;
|
i32 debug_kbAllocated = state->arena.bytesAllocated / 1024;
|
||||||
DEBUG_PUSH_VAR("TotalMemoryAllocated: %dkb", debug_kbAllocated, "i32");
|
DEBUG_PUSH_VAR("TotalMemoryAllocated: %dkb", debug_kbAllocated, "i32");
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ INTERNAL Entity *addEntity(MemoryArena *arena, World *world, v2 pos, v2 size,
|
|||||||
entity.stats->health = entity.stats->maxHealth;
|
entity.stats->health = entity.stats->maxHealth;
|
||||||
entity.stats->actionRate = 100;
|
entity.stats->actionRate = 100;
|
||||||
entity.stats->actionTimer = entity.stats->actionRate;
|
entity.stats->actionTimer = entity.stats->actionRate;
|
||||||
entity.stats->actionSpdMul = 100;
|
entity.stats->actionSpdMul = 1000;
|
||||||
entity.stats->entityIdToAttack = -1;
|
entity.stats->entityIdToAttack = -1;
|
||||||
entity.stats->queuedAttack = entityattack_invalid;
|
entity.stats->queuedAttack = entityattack_invalid;
|
||||||
entity.state = entitystate_idle;
|
entity.state = entitystate_idle;
|
||||||
@ -450,7 +450,7 @@ INTERNAL void parseInput(GameState *state, const f32 dt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO(doyle): Revisit key input with state checking for last ended down
|
// TODO(doyle): Revisit key input with state checking for last ended down
|
||||||
if (state->keys[GLFW_KEY_SPACE] && !spaceBarWasDown)
|
if (state->keys[GLFW_KEY_SPACE])
|
||||||
{
|
{
|
||||||
Renderer *renderer = &state->renderer;
|
Renderer *renderer = &state->renderer;
|
||||||
f32 yPos = CAST(f32)(rand() % CAST(i32)renderer->size.h);
|
f32 yPos = CAST(f32)(rand() % CAST(i32)renderer->size.h);
|
||||||
@ -460,10 +460,6 @@ INTERNAL void parseInput(GameState *state, const f32 dt)
|
|||||||
addGenericMob(&state->arena, &state->assetManager, world, pos);
|
addGenericMob(&state->arena, &state->assetManager, world, pos);
|
||||||
spaceBarWasDown = TRUE;
|
spaceBarWasDown = TRUE;
|
||||||
}
|
}
|
||||||
else if (!state->keys[GLFW_KEY_SPACE])
|
|
||||||
{
|
|
||||||
spaceBarWasDown = FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(doyle): Clipping threshold for snapping velocity to 0
|
// NOTE(doyle): Clipping threshold for snapping velocity to 0
|
||||||
@ -507,10 +503,13 @@ INTERNAL void parseInput(GameState *state, const f32 dt)
|
|||||||
b32 heroCollided = FALSE;
|
b32 heroCollided = FALSE;
|
||||||
if (hero->collides == TRUE)
|
if (hero->collides == TRUE)
|
||||||
{
|
{
|
||||||
for (i32 i = 0; i < world->freeEntityIndex; i++)
|
for (i32 i = 0; i < world->maxEntities; i++)
|
||||||
{
|
{
|
||||||
if (i == world->heroIndex) continue;
|
if (i == world->heroIndex) continue;
|
||||||
|
|
||||||
Entity entity = world->entities[i];
|
Entity entity = world->entities[i];
|
||||||
|
if (entity.state == entitystate_dead) continue;
|
||||||
|
|
||||||
if (entity.collides)
|
if (entity.collides)
|
||||||
{
|
{
|
||||||
v4 heroRect =
|
v4 heroRect =
|
||||||
@ -623,7 +622,10 @@ INTERNAL i32 findBestEntityToAttack(World *world, Entity attacker)
|
|||||||
if (attacker.type == entitytype_mob)
|
if (attacker.type == entitytype_mob)
|
||||||
{
|
{
|
||||||
Entity hero = world->entities[world->heroIndex];
|
Entity hero = world->entities[world->heroIndex];
|
||||||
result = hero.id;
|
|
||||||
|
if (hero.state == entitystate_dead) result = ENTITY_NULL_ID;
|
||||||
|
else result = hero.id;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,6 +668,16 @@ INTERNAL inline void updateWorldBattleEntities(World *world, Entity *entity,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INTERNAL inline void resetEntityState(World *world, Entity *entity)
|
||||||
|
{
|
||||||
|
updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE);
|
||||||
|
setActiveEntityAnim(entity, animlist_hero_idle);
|
||||||
|
entity->stats->busyDuration = 0;
|
||||||
|
entity->stats->actionTimer = entity->stats->actionRate;
|
||||||
|
entity->stats->queuedAttack = entityattack_invalid;
|
||||||
|
entity->stats->entityIdToAttack = ENTITY_NULL_ID;
|
||||||
|
}
|
||||||
|
|
||||||
INTERNAL void entityStateSwitch(World *world, Entity *entity,
|
INTERNAL void entityStateSwitch(World *world, Entity *entity,
|
||||||
enum EntityState newState)
|
enum EntityState newState)
|
||||||
{
|
{
|
||||||
@ -691,8 +703,8 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity,
|
|||||||
// attacking it since there's no check before attack if entity is idle
|
// attacking it since there's no check before attack if entity is idle
|
||||||
// or not (i.e. has moved out of frame last frame).
|
// or not (i.e. has moved out of frame last frame).
|
||||||
case entitystate_dead:
|
case entitystate_dead:
|
||||||
updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE);
|
|
||||||
setActiveEntityAnim(entity, animlist_hero_idle);
|
setActiveEntityAnim(entity, animlist_hero_idle);
|
||||||
|
entity->stats->busyDuration = 0;
|
||||||
entity->stats->actionTimer = entity->stats->actionRate;
|
entity->stats->actionTimer = entity->stats->actionRate;
|
||||||
entity->stats->queuedAttack = entityattack_invalid;
|
entity->stats->queuedAttack = entityattack_invalid;
|
||||||
entity->stats->entityIdToAttack = ENTITY_NULL_ID;
|
entity->stats->entityIdToAttack = ENTITY_NULL_ID;
|
||||||
@ -709,14 +721,16 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity,
|
|||||||
switch (newState)
|
switch (newState)
|
||||||
{
|
{
|
||||||
case entitystate_attack:
|
case entitystate_attack:
|
||||||
|
{
|
||||||
|
EntityAnim_ attackAnim = entity->anim[entity->stats->queuedAttack];
|
||||||
|
f32 busyDuration = attackAnim.anim->frameDuration *
|
||||||
|
CAST(f32) attackAnim.anim->numFrames;
|
||||||
|
entity->stats->busyDuration = busyDuration;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case entitystate_idle:
|
case entitystate_idle:
|
||||||
case entitystate_dead:
|
case entitystate_dead:
|
||||||
updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE);
|
resetEntityState(world, entity);
|
||||||
setActiveEntityAnim(entity, animlist_hero_idle);
|
|
||||||
entity->stats->actionTimer = entity->stats->actionRate;
|
|
||||||
entity->stats->queuedAttack = entityattack_invalid;
|
|
||||||
entity->stats->entityIdToAttack = ENTITY_NULL_ID;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
#ifdef DENGINE_DEBUG
|
#ifdef DENGINE_DEBUG
|
||||||
@ -728,27 +742,14 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity,
|
|||||||
switch (newState)
|
switch (newState)
|
||||||
{
|
{
|
||||||
case entitystate_battle:
|
case entitystate_battle:
|
||||||
|
setActiveEntityAnim(entity, animlist_hero_battlePose);
|
||||||
entity->stats->actionTimer = entity->stats->actionRate;
|
entity->stats->actionTimer = entity->stats->actionRate;
|
||||||
entity->stats->busyDuration = 0;
|
entity->stats->busyDuration = 0;
|
||||||
setActiveEntityAnim(entity, animlist_hero_battlePose);
|
|
||||||
break;
|
break;
|
||||||
case entitystate_dead:
|
|
||||||
// TODO(doyle): Repeated logic with battle -> dead
|
|
||||||
updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE);
|
|
||||||
setActiveEntityAnim(entity, animlist_hero_wave);
|
|
||||||
entity->stats->actionTimer = entity->stats->actionRate;
|
|
||||||
entity->stats->queuedAttack = entityattack_invalid;
|
|
||||||
entity->stats->entityIdToAttack = ENTITY_NULL_ID;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// NOTE(doyle): Entity has been forced out of an attack (out of range)
|
// NOTE(doyle): Entity has been forced out of an attack (out of range)
|
||||||
case entitystate_idle:
|
case entitystate_idle:
|
||||||
updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE);
|
case entitystate_dead:
|
||||||
setActiveEntityAnim(entity, animlist_hero_idle);
|
resetEntityState(world, entity);
|
||||||
entity->stats->busyDuration = 0;
|
|
||||||
entity->stats->actionTimer = entity->stats->actionRate;
|
|
||||||
entity->stats->queuedAttack = entityattack_invalid;
|
|
||||||
entity->stats->entityIdToAttack = ENTITY_NULL_ID;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
#ifdef DENGINE_DEBUG
|
#ifdef DENGINE_DEBUG
|
||||||
@ -777,24 +778,18 @@ INTERNAL void entityStateSwitch(World *world, Entity *entity,
|
|||||||
entity->state = newState;
|
entity->state = newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void beginAttack(Entity *attacker)
|
INTERNAL void beginAttack(World *world, Entity *attacker)
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef DENGINE_DEBUG
|
#ifdef DENGINE_DEBUG
|
||||||
ASSERT(attacker->stats->entityIdToAttack != ENTITY_NULL_ID);
|
ASSERT(attacker->stats->entityIdToAttack != ENTITY_NULL_ID);
|
||||||
#endif
|
#endif
|
||||||
|
entityStateSwitch(world, attacker, entitystate_attack);
|
||||||
|
|
||||||
attacker->state = entitystate_attack;
|
|
||||||
switch (attacker->stats->queuedAttack)
|
switch (attacker->stats->queuedAttack)
|
||||||
{
|
{
|
||||||
case entityattack_tackle:
|
case entityattack_tackle:
|
||||||
EntityAnim_ attackAnim = attacker->anim[animlist_hero_tackle];
|
|
||||||
f32 busyDuration = attackAnim.anim->frameDuration *
|
|
||||||
CAST(f32) attackAnim.anim->numFrames;
|
|
||||||
|
|
||||||
attacker->stats->busyDuration = busyDuration;
|
|
||||||
setActiveEntityAnim(attacker, animlist_hero_tackle);
|
setActiveEntityAnim(attacker, animlist_hero_tackle);
|
||||||
|
|
||||||
if (attacker->direction == direction_east)
|
if (attacker->direction == direction_east)
|
||||||
attacker->dPos.x += (1.0f * METERS_TO_PIXEL);
|
attacker->dPos.x += (1.0f * METERS_TO_PIXEL);
|
||||||
else
|
else
|
||||||
@ -836,6 +831,7 @@ INTERNAL void endAttack(World *world, Entity *attacker)
|
|||||||
Entity *defender = NULL;
|
Entity *defender = NULL;
|
||||||
|
|
||||||
// TODO(doyle): Implement faster lookup for entity id in entity table
|
// TODO(doyle): Implement faster lookup for entity id in entity table
|
||||||
|
b32 noMoreValidTargets = FALSE;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
/* Get target entity to attack */
|
/* Get target entity to attack */
|
||||||
@ -845,31 +841,32 @@ INTERNAL void endAttack(World *world, Entity *attacker)
|
|||||||
if (world->entities[i].id == entityIdToAttack)
|
if (world->entities[i].id == entityIdToAttack)
|
||||||
{
|
{
|
||||||
defender = &world->entities[i];
|
defender = &world->entities[i];
|
||||||
|
#ifdef DENGINE_DEBUG
|
||||||
|
ASSERT(defender->type == entitytype_mob ||
|
||||||
|
defender->type == entitytype_hero);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If no longer exists, find next best */
|
/* If no longer exists, find next best */
|
||||||
if (!defender)
|
if (!defender)
|
||||||
{
|
{
|
||||||
if (world->numEntitiesInBattle > 1)
|
i32 entityIdToAttack = findBestEntityToAttack(world, *attacker);
|
||||||
|
if (entityIdToAttack == ENTITY_NULL_ID)
|
||||||
|
{
|
||||||
|
noMoreValidTargets = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
attacker->stats->entityIdToAttack =
|
attacker->stats->entityIdToAttack =
|
||||||
findBestEntityToAttack(world, *attacker);
|
findBestEntityToAttack(world, *attacker);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
#ifdef DENGINE_DEBUG
|
|
||||||
ASSERT(INVALID_CODE_PATH);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
} while (!defender && noMoreValidTargets == TRUE);
|
||||||
} while (!defender);
|
|
||||||
|
|
||||||
// TODO(doyle): Very susceptible to bugs- ensure if defender is dead the
|
enum EntityState newAttackerState = entitystate_invalid;
|
||||||
// attacker immediately locates a new target or exits battle mode. But this
|
if (!noMoreValidTargets)
|
||||||
// is necessary since it's possible that by the time the hero is ready to
|
|
||||||
// apply attack damage another person may of killed it (i.e. party member)
|
|
||||||
if (defender)
|
|
||||||
{
|
{
|
||||||
// TODO(doyle): Use attacker stats in battle equations
|
// TODO(doyle): Use attacker stats in battle equations
|
||||||
if (attacker->type == entitytype_hero)
|
if (attacker->type == entitytype_hero)
|
||||||
@ -888,10 +885,16 @@ INTERNAL void endAttack(World *world, Entity *attacker)
|
|||||||
attacker->stats->entityIdToAttack =
|
attacker->stats->entityIdToAttack =
|
||||||
findBestEntityToAttack(world, *attacker);
|
findBestEntityToAttack(world, *attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newAttackerState = entitystate_battle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newAttackerState = entitystate_idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return attacker back to non-attacking state */
|
/* Return attacker back to non-attacking state */
|
||||||
entityStateSwitch(world, attacker, entitystate_battle);
|
entityStateSwitch(world, attacker, newAttackerState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -933,7 +936,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
|||||||
// TODO(doyle): Accumulate all dead entities and delete at the
|
// TODO(doyle): Accumulate all dead entities and delete at the
|
||||||
// end. Hence resort/organise entity array once, not every time
|
// end. Hence resort/organise entity array once, not every time
|
||||||
// an entity dies
|
// an entity dies
|
||||||
#if 0
|
#if 1
|
||||||
i32 entityIndexInArray = i;
|
i32 entityIndexInArray = i;
|
||||||
deleteEntity(&state->arena, world, entityIndexInArray);
|
deleteEntity(&state->arena, world, entityIndexInArray);
|
||||||
|
|
||||||
@ -996,7 +999,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
|||||||
if (stats->queuedAttack == entityattack_invalid)
|
if (stats->queuedAttack == entityattack_invalid)
|
||||||
stats->queuedAttack = entityattack_tackle;
|
stats->queuedAttack = entityattack_tackle;
|
||||||
|
|
||||||
beginAttack(entity);
|
beginAttack(world, entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (entity->state == entitystate_attack)
|
else if (entity->state == entitystate_attack)
|
||||||
|
Loading…
Reference in New Issue
Block a user