fp: Add mobbing behaviour to surround club terry

This commit is contained in:
2023-09-29 21:42:27 +10:00
parent 378ef2959b
commit 158fcb12fe
5 changed files with 133 additions and 80 deletions
+39 -69
View File
@@ -4,38 +4,6 @@
#endif
Dqn_f32 const PHYSICS_STEP = 1 / 60.f;
struct FP_GlobalAnimations
{
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_merchant = DQN_STRING8("terry_merchant");
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");
Dqn_String8 smoochie_walk_right = DQN_STRING8("smoochie_walk_right");
Dqn_String8 smoochie_attack_down = DQN_STRING8("smoochie_attack_down");
Dqn_String8 smoochie_hurt_side = DQN_STRING8("smoochie_hurt_side");
Dqn_String8 smoochie_attack_heart = DQN_STRING8("smoochie_attack_heart");
Dqn_String8 smoochie_death = DQN_STRING8("smoochie_death");
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 club_terry_alive = DQN_STRING8("club_terry_alive");
Dqn_String8 club_terry_dark = DQN_STRING8("club_terry_dark");
}
g_anim_names;
TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_Platform *platform, TELY_Assets *assets, Dqn_Arena *arena, Dqn_String8 sheet_name)
{
@@ -964,8 +932,10 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
move_entity = *state == FP_EntityClingerState_Run || *state == FP_EntityClingerState_Idle;
} break;
case FP_EntityType_Merchant: break;
case FP_EntityType_Nil: break;
case FP_EntityType_Merchant: break;
case FP_EntityType_Nil: break;
case FP_EntityType_ClubTerry: break;
case FP_EntityType_Count: break;
}
if (move_entity) {
@@ -988,30 +958,14 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
Dqn_V2 entity_pos = FP_Game_CalcEntityWorldPos(game, entity->handle);
if (entity->flags & FP_GameEntityFlag_AggrosWhenNearTerry) {
Dqn_f32 closest_terry_dist = DQN_F32_MAX;
Dqn_V2 closest_terry_pos = Dqn_V2_InitNx1(DQN_F32_MAX);
FP_GameEntity *closest_terry = nullptr;
for (FP_GameEntityIterator terry_it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &terry_it, game->root_entity); ) {
FP_GameEntity *terry = terry_it.entity;
if (terry->type != FP_EntityType_Terry)
continue;
Dqn_V2 terry_pos = FP_Game_CalcEntityWorldPos(game, terry->handle);
Dqn_f32 dist_to_terry = Dqn_V2_LengthSq_V2x2(terry_pos, entity_pos);
if (dist_to_terry < closest_terry_dist) {
closest_terry_pos = terry_pos;
closest_terry_dist = dist_to_terry;
closest_terry = terry;
}
}
if (closest_terry_dist < DQN_SQUARED(FP_Game_MetersToPixelsNx1(game, 4.f))) {
FP_GameFindClosestEntityResult closest_result = FP_Game_FindClosestEntityWithType(game, entity->handle, FP_EntityType_Terry);
if (closest_result.dist_squared < DQN_SQUARED(FP_Game_MetersToPixelsNx1(game, 4.f))) {
FP_SentinelListLink<FP_GameWaypoint> *first_waypoint = FP_SentinelList_Front(&entity->waypoints);
if (first_waypoint->data.entity != closest_terry->handle) {
if (first_waypoint->data.entity != closest_result.entity) {
FP_GameEntity *terry = FP_Game_GetEntity(game, closest_result.entity);
FP_GameDirection aggro_direction = FP_GameDirection_Count;
DQN_FOR_UINDEX(dir_index, FP_GameDirection_Count) {
FP_GameEntityHandle slot_entity_handle = closest_terry->aggro_slot[dir_index];
FP_GameEntityHandle slot_entity_handle = terry->aggro_slot[dir_index];
FP_GameEntity *slot_entity = FP_Game_GetEntity(game, slot_entity_handle);
if (FP_Game_IsNilEntity(slot_entity)) {
aggro_direction = DQN_CAST(FP_GameDirection)dir_index;
@@ -1021,17 +975,33 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
FP_SentinelListLink<FP_GameWaypoint> *link = FP_SentinelList_MakeBefore(&entity->waypoints, first_waypoint, game->chunk_pool);
FP_GameWaypoint *waypoint = &link->data;
waypoint->entity = closest_terry->handle;
waypoint->entity = terry->handle;
if (aggro_direction != FP_GameDirection_Count) {
waypoint->type = FP_GameWaypointType_Side;
waypoint->type_direction = aggro_direction;
closest_terry->aggro_slot[aggro_direction] = entity->handle;
waypoint->type = FP_GameWaypointType_Side;
waypoint->type_direction = aggro_direction;
terry->aggro_slot[aggro_direction] = entity->handle;
}
}
}
}
if (entity->flags & FP_GameEntityFlag_RespondsToClubTerry) {
FP_GameFindClosestEntityResult closest_result = FP_Game_FindClosestEntityWithType(game, entity->handle, FP_EntityType_ClubTerry);
if (closest_result.dist_squared < DQN_SQUARED(FP_Game_MetersToPixelsNx1(game, 4.f))) {
FP_SentinelListLink<FP_GameWaypoint> *first_waypoint = FP_SentinelList_Front(&entity->waypoints);
if (first_waypoint->data.entity != closest_result.entity) {
FP_GameEntity *club_terry = FP_Game_GetEntity(game, closest_result.entity);
FP_SentinelListLink<FP_GameWaypoint> *link = FP_SentinelList_MakeBefore(&entity->waypoints, first_waypoint, game->chunk_pool);
FP_GameWaypoint *waypoint = &link->data;
waypoint->entity = club_terry->handle;
waypoint->type = FP_GameWaypointType_Side;
waypoint->type_direction = FP_GameDirection_Down;
}
}
}
while (entity->waypoints.size) {
FP_SentinelListLink<FP_GameWaypoint> *waypoint_link = entity->waypoints.sentinel->next;
FP_GameWaypoint const *waypoint = &waypoint_link->data;
@@ -1051,7 +1021,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
Dqn_f32 arrival_threshold = {};
switch (waypoint->arrive) {
case FP_GameWaypointArrive_Default: {
arrival_threshold = FP_Game_MetersToPixelsNx1(game, 1.f);
arrival_threshold = FP_Game_MetersToPixelsNx1(game, 0.5f);
} break;
case FP_GameWaypointArrive_WhenWithinEntitySize: {
@@ -1067,14 +1037,11 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
}
// NOTE: We have arrived at the waypoint
if ((entity->flags & FP_GameEntityFlag_AggrosWhenNearTerry) && waypoint_entity->type == FP_EntityType_Terry) {
// NOTE: We had a waypoint to move to Terry because he has
// drawn our aggro and we've arrived at Terry
bool can_attack = !entity->is_dying;
bool aggro_on_terry = (entity->flags & FP_GameEntityFlag_AggrosWhenNearTerry) && waypoint_entity->type == FP_EntityType_Terry;
bool club_terry_response = (entity->flags & FP_GameEntityFlag_RespondsToClubTerry) && waypoint_entity->type == FP_EntityType_ClubTerry;
if (aggro_on_terry || club_terry_response) {
bool can_attack = !entity->is_dying; // TODO(doyle): State transition needs to check if it's valid to move to making this not necessary
if (can_attack) {
Dqn_V2 attack_dir_vectors[FP_GameDirection_Count] = {};
attack_dir_vectors[FP_GameDirection_Up] = Dqn_V2_InitNx2(+0, -1);
attack_dir_vectors[FP_GameDirection_Down] = Dqn_V2_InitNx2(+0, +1);
@@ -1117,7 +1084,8 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
entity->direction = best_attack_dir;
} break;
case FP_EntityType_Count: DQN_INVALID_CODE_PATH; break;
case FP_EntityType_Count: DQN_INVALID_CODE_PATH; break;
case FP_EntityType_ClubTerry: break;
}
}
@@ -1195,6 +1163,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
FP_GameEntity *mob = FP_Game_GetEntity(game, link->data);
mob->waypoints = FP_SentinelList_Init<FP_GameWaypoint>(game->chunk_pool);
mob->flags |= FP_GameEntityFlag_AggrosWhenNearTerry;
mob->flags |= FP_GameEntityFlag_RespondsToClubTerry;
for (FP_GameEntity *waypoint_entity = entity->first_child; waypoint_entity; waypoint_entity = waypoint_entity->next) {
if ((waypoint_entity->flags & FP_GameEntityFlag_MobSpawnerWaypoint) == 0)
@@ -1245,7 +1214,8 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
case FP_EntityType_Nil: /*FALLTRHU*/
case FP_EntityType_Terry: /*FALLTRHU*/
case FP_EntityType_Merchant: /*FALLTRHU*/
case FP_EntityType_Count: break;
case FP_EntityType_Count: break;
case FP_EntityType_ClubTerry: break;
}
if (!permit_attack)