diff --git a/Data/Textures/atlas.png b/Data/Textures/atlas.png index 6585fe2..a5651e0 100644 --- a/Data/Textures/atlas.png +++ b/Data/Textures/atlas.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4e15ce1da911241a6492c8c9dd9bf9aca6771549a9aa54c895fdec9a45a1a628 -size 7090684 +oid sha256:5a7814629aaa53c134869cfa1208360edd24eb50db83aad445092d5bc6770dca +size 7090720 diff --git a/Data/Textures/atlas/catfish_attack_side_1.png b/Data/Textures/atlas/catfish_attack_side_1.png index d8168dc..4153414 100644 --- a/Data/Textures/atlas/catfish_attack_side_1.png +++ b/Data/Textures/atlas/catfish_attack_side_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:79e3aa97d5edc31a267350f19c9b6c3262ae919d7339f6d1d4a283c04f734745 -size 18363 +oid sha256:ede8964dc1fdd8df0c18551678687badb3c702bcc5745b5265233b9399bae30b +size 19203 diff --git a/Data/Textures/atlas/catfish_attack_side_2.png b/Data/Textures/atlas/catfish_attack_side_2.png index 4153414..d8168dc 100644 --- a/Data/Textures/atlas/catfish_attack_side_2.png +++ b/Data/Textures/atlas/catfish_attack_side_2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ede8964dc1fdd8df0c18551678687badb3c702bcc5745b5265233b9399bae30b -size 19203 +oid sha256:79e3aa97d5edc31a267350f19c9b6c3262ae919d7339f6d1d4a283c04f734745 +size 18363 diff --git a/feely_pona.cpp b/feely_pona.cpp index b27c792..6ec7d05 100644 --- a/feely_pona.cpp +++ b/feely_pona.cpp @@ -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 *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) diff --git a/feely_pona.h b/feely_pona.h index ee407a3..5c2f9bf 100644 --- a/feely_pona.h +++ b/feely_pona.h @@ -23,30 +23,60 @@ struct FP_Meters struct FP_GlobalAnimations { + Dqn_String8 airport_terry_alive = DQN_STRING8("airport_terry_alive"); + Dqn_String8 airport_terry_dark = DQN_STRING8("airport_terry_dark"); + + Dqn_String8 catfish_attack_down = DQN_STRING8("catfish_attack_down"); + Dqn_String8 catfish_attack_side = DQN_STRING8("catfish_attack_side"); + Dqn_String8 catfish_attack_up = DQN_STRING8("catfish_attack_up"); + Dqn_String8 catfish_death = DQN_STRING8("catfish_death"); + Dqn_String8 catfish_walk_up = DQN_STRING8("catfish_walk_up"); + Dqn_String8 catfish_walk_side = DQN_STRING8("catfish_walk_side"); + Dqn_String8 catfish_walk_down = DQN_STRING8("catfish_walk_down"); + Dqn_String8 clinger_attack_down = DQN_STRING8("clinger_attack_down"); Dqn_String8 clinger_attack_side = DQN_STRING8("clinger_attack_side"); Dqn_String8 clinger_attack_up = DQN_STRING8("clinger_attack_up"); - Dqn_String8 clinger_death = DQN_STRING8("clinger_death"); Dqn_String8 clinger_walk_up = DQN_STRING8("clinger_walk_up"); Dqn_String8 clinger_walk_down = DQN_STRING8("clinger_walk_down"); + Dqn_String8 church_terry_alive = DQN_STRING8("church_terry_alive"); + Dqn_String8 church_terry_dark = DQN_STRING8("church_terry_dark"); + Dqn_String8 club_terry_alive = DQN_STRING8("club_terry_alive"); Dqn_String8 club_terry_dark = DQN_STRING8("club_terry_dark"); Dqn_String8 heart = DQN_STRING8("heart"); Dqn_String8 heart_bleed = DQN_STRING8("heart_bleed"); + Dqn_String8 kennel_terry = DQN_STRING8("kennel_terry"); + Dqn_String8 map = DQN_STRING8("map"); - Dqn_String8 merchant_graveyard = DQN_STRING8("merchant_graveyard"); - Dqn_String8 merchant_gym = DQN_STRING8("merchant_gym"); - Dqn_String8 merchant_phone_company= DQN_STRING8("merchant_phone_company"); - Dqn_String8 merchant_terry = DQN_STRING8("merchant_terry"); + Dqn_String8 merchant_button_a = DQN_STRING8("merchant_button_a"); + Dqn_String8 merchant_button_b = DQN_STRING8("merchant_button_b"); + Dqn_String8 merchant_button_x = DQN_STRING8("merchant_button_x"); + Dqn_String8 merchant_button_y = DQN_STRING8("merchant_button_y"); + + Dqn_String8 merchant_graveyard = DQN_STRING8("merchant_graveyard"); + Dqn_String8 merchant_graveyard_menu = DQN_STRING8("merchant_graveyard"); + Dqn_String8 merchant_gym = DQN_STRING8("merchant_gym"); + Dqn_String8 merchant_gym_menu = DQN_STRING8("merchant_gym_menu"); + Dqn_String8 merchant_phone_company = DQN_STRING8("merchant_phone_company"); + Dqn_String8 merchant_phone_company_menu = DQN_STRING8("merchant_phone_company_menu"); + Dqn_String8 merchant_terry = DQN_STRING8("merchant_terry"); + Dqn_String8 merchant_terry_menu = DQN_STRING8("merchant_terry_menu"); Dqn_String8 shadow_long_circle = DQN_STRING8("shadow_long_circle"); Dqn_String8 shadow_tight_circle = DQN_STRING8("shadow_tight_circle"); + Dqn_String8 shrubbery_bush_1 = DQN_STRING8("shrubbery_bush_1"); + Dqn_String8 shrubbery_bush_2 = DQN_STRING8("shrubbery_bush_2"); + Dqn_String8 shrubbery_island_1 = DQN_STRING8("shrubbery_island_1"); + Dqn_String8 shrubbery_island_2 = DQN_STRING8("shrubbery_island_2"); + Dqn_String8 shrubbery_island_3 = DQN_STRING8("shrubbery_island_3"); + Dqn_String8 smoochie_walk_up = DQN_STRING8("smoochie_walk_up"); Dqn_String8 smoochie_walk_down = DQN_STRING8("smoochie_walk_down"); Dqn_String8 smoochie_walk_left = DQN_STRING8("smoochie_walk_left"); @@ -56,15 +86,18 @@ struct FP_GlobalAnimations Dqn_String8 smoochie_attack_heart = DQN_STRING8("smoochie_attack_heart"); Dqn_String8 smoochie_death = DQN_STRING8("smoochie_death"); - Dqn_String8 terry_attack_up = DQN_STRING8("terry_attack_up"); - Dqn_String8 terry_attack_side = DQN_STRING8("terry_attack_side"); - Dqn_String8 terry_attack_down = DQN_STRING8("terry_attack_down"); - - Dqn_String8 terry_walk_idle = DQN_STRING8("terry_walk_idle"); - Dqn_String8 terry_walk_up = DQN_STRING8("terry_walk_up"); - Dqn_String8 terry_walk_down = DQN_STRING8("terry_walk_down"); - Dqn_String8 terry_walk_left = DQN_STRING8("terry_walk_left"); - Dqn_String8 terry_walk_right = DQN_STRING8("terry_walk_right"); + Dqn_String8 terry_attack_up = DQN_STRING8("terry_attack_up"); + Dqn_String8 terry_attack_side = DQN_STRING8("terry_attack_side"); + Dqn_String8 terry_attack_down = DQN_STRING8("terry_attack_down"); + Dqn_String8 terry_attack_phone_up = DQN_STRING8("terry_attack_phone_up"); + Dqn_String8 terry_attack_phone_side = DQN_STRING8("terry_attack_phone_side"); + Dqn_String8 terry_attack_phone_down = DQN_STRING8("terry_attack_phone_down"); + Dqn_String8 terry_attack_phone_message = DQN_STRING8("terry_attack_phone_message"); + Dqn_String8 terry_walk_idle = DQN_STRING8("terry_walk_idle"); + Dqn_String8 terry_walk_up = DQN_STRING8("terry_walk_up"); + Dqn_String8 terry_walk_down = DQN_STRING8("terry_walk_down"); + Dqn_String8 terry_walk_left = DQN_STRING8("terry_walk_left"); + Dqn_String8 terry_walk_right = DQN_STRING8("terry_walk_right"); } g_anim_names; diff --git a/feely_pona_entity.h b/feely_pona_entity.h index 856cf58..3f5ef5f 100644 --- a/feely_pona_entity.h +++ b/feely_pona_entity.h @@ -6,16 +6,20 @@ enum FP_EntityType { FP_EntityType_Nil, + FP_EntityType_AirportTerry, + FP_EntityType_Catfish, + FP_EntityType_ChurchTerry, + FP_EntityType_Clinger, + FP_EntityType_ClubTerry, + FP_EntityType_Heart, + FP_EntityType_KennelTerry, FP_EntityType_Map, - FP_EntityType_Terry, - FP_EntityType_Smoochie, - FP_EntityType_MerchantTerry, FP_EntityType_MerchantGraveyard, FP_EntityType_MerchantGym, FP_EntityType_MerchantPhoneCompany, - FP_EntityType_ClubTerry, - FP_EntityType_Clinger, - FP_EntityType_Heart, + FP_EntityType_MerchantTerry, + FP_EntityType_Smoochie, + FP_EntityType_Terry, FP_EntityType_Count, }; @@ -24,6 +28,7 @@ enum FP_EntityTerryState FP_EntityTerryState_Nil, FP_EntityTerryState_Idle, FP_EntityTerryState_Attack, + FP_EntityTerryState_AttackPhone, FP_EntityTerryState_Run, FP_EntityTerryState_Dash, }; @@ -38,6 +43,15 @@ enum FP_EntitySmoochieState FP_EntitySmoochieState_Run, }; +enum FP_EntityCatfishState +{ + FP_EntityCatfishState_Nil, + FP_EntityCatfishState_Idle, + FP_EntityCatfishState_Attack, + FP_EntityCatfishState_Death, + FP_EntityCatfishState_Run, +}; + enum FP_EntityClingerState { FP_EntityClingerState_Nil, @@ -78,6 +92,26 @@ enum FP_EntityClubTerryState FP_EntityClubTerryState_PartyTime, }; +enum FP_EntityAirportTerryState +{ + FP_EntityAirportTerryState_Nil, + FP_EntityAirportTerryState_Idle, + FP_EntityAirportTerryState_FlyPassenger, +}; + +enum FP_EntityChurchTerryState +{ + FP_EntityChurchTerryState_Nil, + FP_EntityChurchTerryState_Idle, + FP_EntityChurchTerryState_ConvertPatron, +}; + +enum FP_EntityKennelTerryState +{ + FP_EntityKennelTerryState_Nil, + FP_EntityKennelTerryState_Idle, +}; + enum FP_EntityMapState { FP_EntityMapState_Nil, diff --git a/feely_pona_entity_create.cpp b/feely_pona_entity_create.cpp index 51ebc29..c0e463e 100644 --- a/feely_pona_entity_create.cpp +++ b/feely_pona_entity_create.cpp @@ -39,7 +39,17 @@ FP_EntityRenderData FP_Entity_GetRenderData(FP_Game *game, FP_EntityType type, u } } break; - case FP_EntityTerryState_Run: /*FALLTHRU*/ + case FP_EntityTerryState_AttackPhone: { + switch (direction) { + case FP_GameDirection_Up: result.anim_name = g_anim_names.terry_attack_phone_up; break; + case FP_GameDirection_Down: result.anim_name = g_anim_names.terry_attack_phone_down; break; + case FP_GameDirection_Left: result.anim_name = g_anim_names.terry_attack_phone_side; break; + case FP_GameDirection_Right: result.anim_name = g_anim_names.terry_attack_phone_side; result.flip = TELY_AssetFlip_X; break; + case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break; + } + } break; + + case FP_EntityTerryState_Run: /*FALLTHRU*/ case FP_EntityTerryState_Dash: { switch (direction) { case FP_GameDirection_Up: result.anim_name = g_anim_names.terry_walk_up; break; @@ -160,6 +170,63 @@ FP_EntityRenderData FP_Entity_GetRenderData(FP_Game *game, FP_EntityType type, u } } break; + case FP_EntityType_AirportTerry: { + result.height.meters = 4.f; + FP_EntityAirportTerryState state = DQN_CAST(FP_EntityAirportTerryState)raw_state; + switch (state) { + case FP_EntityAirportTerryState_Nil: break; + case FP_EntityAirportTerryState_Idle: result.anim_name = g_anim_names.airport_terry_dark; break; + case FP_EntityAirportTerryState_FlyPassenger: result.anim_name = g_anim_names.airport_terry_alive; break; + } + } break; + + case FP_EntityType_Catfish: { + result.height.meters = 1.6f; + FP_EntityCatfishState state = DQN_CAST(FP_EntityCatfishState)raw_state; + switch (state) { + case FP_EntityCatfishState_Nil: + case FP_EntityCatfishState_Idle: result.anim_name = g_anim_names.catfish_walk_down; break; + case FP_EntityCatfishState_Attack: { + switch (direction) { + case FP_GameDirection_Up: result.anim_name = g_anim_names.catfish_attack_up; break; + case FP_GameDirection_Down: result.anim_name = g_anim_names.catfish_attack_down; break; + case FP_GameDirection_Left: result.anim_name = g_anim_names.catfish_attack_side; result.flip = TELY_AssetFlip_X; break; + case FP_GameDirection_Right: result.anim_name = g_anim_names.catfish_attack_side; break; + case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break; + } + } break; + case FP_EntityCatfishState_Death: result.anim_name = g_anim_names.catfish_death; break; + case FP_EntityCatfishState_Run: { + switch (direction) { + case FP_GameDirection_Up: result.anim_name = g_anim_names.catfish_walk_up; break; + case FP_GameDirection_Down: result.anim_name = g_anim_names.catfish_walk_down; break; + case FP_GameDirection_Left: result.anim_name = g_anim_names.catfish_walk_side; break; + case FP_GameDirection_Right: result.anim_name = g_anim_names.catfish_walk_side; result.flip = TELY_AssetFlip_X; break; + case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break; + } + } break; + } + } break; + + case FP_EntityType_ChurchTerry: { + result.height.meters = 4.f; + FP_EntityChurchTerryState state = DQN_CAST(FP_EntityChurchTerryState)raw_state; + switch (state) { + case FP_EntityChurchTerryState_Nil: break; + case FP_EntityChurchTerryState_Idle: result.anim_name = g_anim_names.church_terry_dark; break; + case FP_EntityChurchTerryState_ConvertPatron: result.anim_name = g_anim_names.church_terry_alive; break; + } + } break; + + case FP_EntityType_KennelTerry: { + result.height.meters = 4.f; + FP_EntityKennelTerryState state = DQN_CAST(FP_EntityKennelTerryState)raw_state; + switch (state) { + case FP_EntityKennelTerryState_Nil: break; + case FP_EntityKennelTerryState_Idle: result.anim_name = g_anim_names.kennel_terry; break; + } + } break; + case FP_EntityType_Count: DQN_INVALID_CODE_PATH; break; } @@ -252,6 +319,28 @@ static FP_GameEntityHandle FP_Entity_CreateSmoochie(FP_Game *game, Dqn_V2 pos, D return result; } +static FP_GameEntityHandle FP_Entity_CreateCatfish(FP_Game *game, Dqn_V2 pos, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); + FP_GameEntityHandle result = entity->handle; + va_end(args); + + entity->type = FP_EntityType_Catfish; + entity->base_acceleration_per_s.meters = 8.f; + entity->hp = 1; + entity->is_dying = false; + entity->local_pos = pos; + entity->sprite_height = FP_Entity_GetRenderData(game, entity->type, 0 /*state*/, FP_GameDirection_Down).height; + entity->attack_cooldown_ms = 1000; + entity->local_hit_box_size = FP_Game_MetersToPixelsNx2(game, 0.4f, entity->sprite_height.meters * .6f); + FP_Entity_AddDebugEditorFlags(game, entity->handle); + entity->flags |= FP_GameEntityFlag_NonTraversable; + entity->flags |= FP_GameEntityFlag_Attackable; + return result; +} + static FP_GameEntityHandle FP_Entity_CreateWallAtPos(FP_Game *game, Dqn_String8 name, Dqn_V2 pos, Dqn_V2 size) { FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, name.data); @@ -499,3 +588,75 @@ static FP_GameEntityHandle FP_Entity_CreateHeart(FP_Game *game, Dqn_V2 pos, DQN_ entity->local_hit_box_size = Dqn_V2_InitNx2(sprite_rect_scaled.w - (sprite_rect_scaled.w * .3f), sprite_rect_scaled.h - (sprite_rect_scaled.h * .4f)); return result; } + +static FP_GameEntityHandle FP_Entity_CreateChurchTerry(FP_Game *game, Dqn_V2 pos, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); + FP_GameEntityHandle result = entity->handle; + va_end(args); + + entity->type = FP_EntityType_ChurchTerry; + entity->local_pos = pos; + entity->sprite_height = FP_Entity_GetRenderData(game, entity->type, 0 /*state*/, FP_GameDirection_Down).height; + FP_Entity_AddDebugEditorFlags(game, result); + entity->flags |= FP_GameEntityFlag_NonTraversable; + + TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.church_terry_alive); + Dqn_Rect sprite_rect = game->atlas_sprite_sheet.rects.data[sprite_anim->index]; + Dqn_f32 size_scale = FP_Entity_CalcSpriteScaleForDesiredHeight(game, entity->sprite_height, sprite_rect); + Dqn_V2 sprite_rect_scaled = sprite_rect.size * size_scale; + + entity->local_hit_box_offset = Dqn_V2_InitNx2(0, sprite_rect_scaled.h * .1f); + entity->local_hit_box_size = Dqn_V2_InitNx2(sprite_rect_scaled.w, sprite_rect_scaled.h - (sprite_rect_scaled.h * .4f)); + return result; +} + +static FP_GameEntityHandle FP_Entity_CreateKennelTerry(FP_Game *game, Dqn_V2 pos, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); + FP_GameEntityHandle result = entity->handle; + va_end(args); + + entity->type = FP_EntityType_KennelTerry; + entity->local_pos = pos; + entity->sprite_height = FP_Entity_GetRenderData(game, entity->type, 0 /*state*/, FP_GameDirection_Down).height; + FP_Entity_AddDebugEditorFlags(game, result); + entity->flags |= FP_GameEntityFlag_NonTraversable; + + TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.church_terry_alive); + Dqn_Rect sprite_rect = game->atlas_sprite_sheet.rects.data[sprite_anim->index]; + Dqn_f32 size_scale = FP_Entity_CalcSpriteScaleForDesiredHeight(game, entity->sprite_height, sprite_rect); + Dqn_V2 sprite_rect_scaled = sprite_rect.size * size_scale; + + entity->local_hit_box_offset = Dqn_V2_InitNx2(0, sprite_rect_scaled.h * .1f); + entity->local_hit_box_size = Dqn_V2_InitNx2(sprite_rect_scaled.w, sprite_rect_scaled.h - (sprite_rect_scaled.h * .4f)); + return result; +} + +static FP_GameEntityHandle FP_Entity_CreateAirportTerry(FP_Game *game, Dqn_V2 pos, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args); + FP_GameEntityHandle result = entity->handle; + va_end(args); + + entity->type = FP_EntityType_AirportTerry; + entity->local_pos = pos; + entity->sprite_height = FP_Entity_GetRenderData(game, entity->type, 0 /*state*/, FP_GameDirection_Down).height; + FP_Entity_AddDebugEditorFlags(game, result); + entity->flags |= FP_GameEntityFlag_NonTraversable; + + TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.church_terry_alive); + Dqn_Rect sprite_rect = game->atlas_sprite_sheet.rects.data[sprite_anim->index]; + Dqn_f32 size_scale = FP_Entity_CalcSpriteScaleForDesiredHeight(game, entity->sprite_height, sprite_rect); + Dqn_V2 sprite_rect_scaled = sprite_rect.size * size_scale; + + entity->local_hit_box_offset = Dqn_V2_InitNx2(0, sprite_rect_scaled.h * .1f); + entity->local_hit_box_size = Dqn_V2_InitNx2(sprite_rect_scaled.w, sprite_rect_scaled.h - (sprite_rect_scaled.h * .4f)); + return result; +}