fp: Spawn catfish

This commit is contained in:
2023-10-04 23:50:31 +11:00
parent 0e22b49271
commit aed29a9f50
7 changed files with 458 additions and 39 deletions
+203 -12
View File
@@ -172,12 +172,17 @@ static void FP_Game_MoveEntity(FP_Game *game, FP_GameEntityHandle entity_handle,
bool entity_collides_with_collider = true;
switch (entity->type) {
case FP_EntityType_Smoochie: {
if (collider->type == FP_EntityType_Smoochie || collider->type == FP_EntityType_Clinger)
if (collider->type == FP_EntityType_Smoochie || collider->type == FP_EntityType_Clinger || collider->type == FP_EntityType_Catfish)
entity_collides_with_collider = false;
} break;
case FP_EntityType_Clinger: {
if (collider->type == FP_EntityType_Smoochie || collider->type == FP_EntityType_Clinger)
if (collider->type == FP_EntityType_Smoochie || collider->type == FP_EntityType_Clinger || collider->type == FP_EntityType_Catfish)
entity_collides_with_collider = false;
} break;
case FP_EntityType_Catfish: {
if (collider->type == FP_EntityType_Smoochie || collider->type == FP_EntityType_Clinger || collider->type == FP_EntityType_Catfish)
entity_collides_with_collider = false;
} break;
@@ -199,6 +204,9 @@ static void FP_Game_MoveEntity(FP_Game *game, FP_GameEntityHandle entity_handle,
case FP_EntityType_MerchantGym: break;
case FP_EntityType_MerchantPhoneCompany: break;
case FP_EntityType_Heart: break;
case FP_EntityType_AirportTerry: break;
case FP_EntityType_ChurchTerry: break;
case FP_EntityType_KennelTerry: break;
}
if (!entity_collides_with_collider)
@@ -533,6 +541,17 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
}
} break;
case FP_EntityTerryState_AttackPhone: {
if (entering_new_state) {
uint64_t duration_ms = render_data.sprite.anim->count * render_data.sprite.anim->ms_per_frame;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite);
}
if (action_has_finished) {
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Idle);
}
} break;
case FP_EntityTerryState_Run: {
if (entering_new_state || action->sprite.anim->label != render_data.anim_name) {
uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER;
@@ -566,7 +585,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
} break;
}
if (*state == FP_EntityTerryState_Attack) {
if (*state == FP_EntityTerryState_Attack || *state == FP_EntityTerryState_AttackPhone) {
DQN_ASSERT(action->sprite.anim);
uint64_t duration_ms = action->sprite.anim->count * action->sprite.anim->ms_per_frame;
@@ -971,7 +990,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
} break;
case FP_EntityType_Map: {
FP_EntityMapState *state = DQN_CAST(FP_EntityMapState *) & action->state;
FP_EntityMapState *state = DQN_CAST(FP_EntityMapState *) & action->state;
switch (*state) {
case FP_EntityMapState_Nil: {
FP_Game_EntityTransitionState(game, entity, FP_EntityMapState_Idle);
@@ -988,7 +1007,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
} break;
case FP_EntityType_Heart: {
FP_EntityHeartState *state = DQN_CAST(FP_EntityHeartState *) & action->state;
FP_EntityHeartState *state = DQN_CAST(FP_EntityHeartState *) & action->state;
switch (*state) {
case FP_EntityHeartState_Nil: {
FP_Game_EntityTransitionState(game, entity, FP_EntityHeartState_Idle);
@@ -1003,7 +1022,162 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
}
} break;
case FP_EntityType_AirportTerry: {
FP_EntityAirportTerryState *state = DQN_CAST(FP_EntityAirportTerryState *)&action->state;
switch (*state) {
case FP_EntityAirportTerryState_Nil: {
FP_Game_EntityTransitionState(game, entity, FP_EntityAirportTerryState_Idle);
} break;
case FP_EntityAirportTerryState_Idle: {
if (entering_new_state) {
uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite);
}
} break;
case FP_EntityAirportTerryState_FlyPassenger: {
} break;
}
} break;
case FP_EntityType_Catfish: {
FP_EntityCatfishState *state = DQN_CAST(FP_EntityCatfishState *) & action->state;
switch (*state) {
case FP_EntityCatfishState_Nil: {
FP_Game_EntityTransitionState(game, entity, FP_EntityCatfishState_Idle);
} break;
case FP_EntityCatfishState_Idle: {
if (entering_new_state) {
uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite);
}
if (we_are_clicked_entity) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
FP_Game_EntityTransitionState(game, entity, FP_EntityCatfishState_Attack);
} else if (acceleration_meters_per_s->x || acceleration_meters_per_s->y) {
FP_Game_EntityTransitionState(game, entity, FP_EntityCatfishState_Run);
}
}
if (entity_has_velocity) {
FP_Game_EntityTransitionState(game, entity, FP_EntityCatfishState_Run);
}
} break;
case FP_EntityCatfishState_Attack: {
if (entering_new_state) {
uint64_t duration_ms = render_data.sprite.anim->count * render_data.sprite.anim->ms_per_frame;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite);
}
if (action_has_finished)
FP_Game_EntityTransitionState(game, entity, FP_EntityCatfishState_Idle);
} break;
case FP_EntityCatfishState_Death: {
if (entering_new_state) {
uint64_t duration_ms = render_data.sprite.anim->count * render_data.sprite.anim->ms_per_frame;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite);
}
if (action_has_finished)
FP_Game_DeleteEntity(game, entity->handle);
} break;
case FP_EntityCatfishState_Run: {
if (entering_new_state || action->sprite.anim->label != render_data.anim_name) {
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, render_data.anim_name, render_data.flip);
uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
}
if (we_are_clicked_entity) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
FP_Game_EntityTransitionState(game, entity, FP_EntityCatfishState_Attack);
}
}
if (!entity_has_velocity) {
FP_Game_EntityTransitionState(game, entity, FP_EntityCatfishState_Idle);
}
} break;
}
if (entity->is_dying && *state != FP_EntityCatfishState_Death) {
FP_Game_EntityTransitionState(game, entity, FP_EntityCatfishState_Death);
}
if (*state == FP_EntityCatfishState_Attack) { // NOTE: Position the attack box
entity->attack_box_size = entity->local_hit_box_size;
switch (entity->direction) {
case FP_GameDirection_Left: {
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x - entity->attack_box_size.w,
entity->local_hit_box_offset.y);
} break;
case FP_GameDirection_Right: {
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x + entity->attack_box_size.w,
entity->local_hit_box_offset.y);
} break;
case FP_GameDirection_Up: {
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x,
entity->local_hit_box_offset.y - entity->attack_box_size.h);
} break;
case FP_GameDirection_Down: {
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x,
entity->local_hit_box_offset.y + entity->attack_box_size.h);
} break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
}
} else {
entity->attack_box_size = {};
}
} break;
case FP_EntityType_ChurchTerry: {
FP_EntityChurchTerryState *state = DQN_CAST(FP_EntityChurchTerryState *)&action->state;
switch (*state) {
case FP_EntityChurchTerryState_Nil: {
FP_Game_EntityTransitionState(game, entity, FP_EntityChurchTerryState_Idle);
} break;
case FP_EntityChurchTerryState_Idle: {
if (entering_new_state) {
uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite);
}
} break;
case FP_EntityChurchTerryState_ConvertPatron: break;
}
} break;
case FP_EntityType_KennelTerry: {
FP_EntityKennelTerryState *state = DQN_CAST(FP_EntityKennelTerryState *)&action->state;
switch (*state) {
case FP_EntityKennelTerryState_Nil: {
FP_Game_EntityTransitionState(game, entity, FP_EntityKennelTerryState_Idle);
} break;
case FP_EntityKennelTerryState_Idle: {
if (entering_new_state) {
uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite);
}
} break;
}
} break;
case FP_EntityType_Nil: break;
case FP_EntityType_Count: DQN_INVALID_CODE_PATH; break;
}
}
@@ -1315,16 +1489,19 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
switch (entity->type) {
case FP_EntityType_Terry: /*FALLTHRU*/
case FP_EntityType_Smoochie: /*FALLTHRU*/
case FP_EntityType_Catfish: /*FALLTHRU*/
case FP_EntityType_Clinger: {
// TODO(doyle): We should check if it's valid to enter this new state
// from the entity's current state
if (entity->type == FP_EntityType_Terry) {
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Attack);
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Attack);
} else if (entity->type == FP_EntityType_Smoochie) {
FP_Game_EntityTransitionState(game, entity, FP_EntitySmoochieState_Attack);
FP_Game_EntityTransitionState(game, entity, FP_EntitySmoochieState_Attack);
} else if (entity->type == FP_EntityType_Catfish) {
FP_Game_EntityTransitionState(game, entity, FP_EntityCatfishState_Attack);
} else {
DQN_ASSERT(entity->type == FP_EntityType_Clinger);
FP_Game_EntityTransitionState(game, entity, FP_EntityClingerState_Attack);
FP_Game_EntityTransitionState(game, entity, FP_EntityClingerState_Attack);
}
entity->direction = best_attack_dir;
@@ -1340,6 +1517,9 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
case FP_EntityType_MerchantGraveyard: break;
case FP_EntityType_MerchantGym: break;
case FP_EntityType_MerchantPhoneCompany: break;
case FP_EntityType_AirportTerry:
case FP_EntityType_ChurchTerry:
case FP_EntityType_KennelTerry: break;
}
}
@@ -1463,10 +1643,13 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
Dqn_V2 entity_world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle);
FP_SentinelListLink<FP_GameEntityHandle> *link = FP_SentinelList_Make(&entity->spawn_list, game->chunk_pool);
if (Dqn_PCG32_NextF32(&game->rng) >= 0.5f)
Dqn_f32 mob_choice = Dqn_PCG32_NextF32(&game->rng);
if (mob_choice <= 0.33f)
link->data = FP_Entity_CreateClinger(game, entity_world_pos, "Clinger");
else
else if (mob_choice <= 0.66f)
link->data = FP_Entity_CreateSmoochie(game, entity_world_pos, "Smoochie");
else
link->data = FP_Entity_CreateCatfish(game, entity_world_pos, "Catfish");
// NOTE: Setup the mob with waypoints
FP_GameEntity *mob = FP_Game_GetEntity(game, link->data);
@@ -1518,12 +1701,17 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
bool permit_attack = true;
switch (attacker->type) {
case FP_EntityType_Smoochie: {
if (defender->type == FP_EntityType_Smoochie || defender->type == FP_EntityType_Clinger)
if (defender->type == FP_EntityType_Smoochie || defender->type == FP_EntityType_Clinger || defender->type == FP_EntityType_Catfish)
permit_attack = false;
} break;
case FP_EntityType_Catfish: {
if (defender->type == FP_EntityType_Smoochie || defender->type == FP_EntityType_Clinger || defender->type == FP_EntityType_Catfish)
permit_attack = false;
} break;
case FP_EntityType_Clinger: {
if (defender->type == FP_EntityType_Smoochie || defender->type == FP_EntityType_Clinger)
if (defender->type == FP_EntityType_Smoochie || defender->type == FP_EntityType_Clinger || defender->type == FP_EntityType_Catfish)
permit_attack = false;
} break;
@@ -1537,6 +1725,9 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
case FP_EntityType_MerchantGym: break;
case FP_EntityType_MerchantPhoneCompany: break;
case FP_EntityType_Heart: break;
case FP_EntityType_AirportTerry:
case FP_EntityType_ChurchTerry:
case FP_EntityType_KennelTerry: break;
}
if (!permit_attack)