fp: Load heart & remove aggro when terry distances himself

This commit is contained in:
2023-10-01 16:11:08 +11:00
parent f258886d68
commit 0234d34673
18 changed files with 154 additions and 15 deletions
+73 -4
View File
@@ -277,6 +277,7 @@ void TELY_DLL_Init(void *user_data)
game->clinger_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("clinger_resized_25%"));
game->club_terry_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("club_terry_resized_25%"));
game->map_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("map_resized_25%"));
game->heart_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("heart_resized_25%"));
}
game->entities = Dqn_VArray_Init<FP_GameEntity>(&platform->arena, 1024 * 8);
@@ -388,6 +389,7 @@ void TELY_DLL_Init(void *user_data)
FP_Game_PopParentEntity(game);
}
FP_Entity_CreateHeart(game, base_mid_p, "Heart");
uint16_t font_size = 18;
game->camera.scale = Dqn_V2_InitNx1(1);
@@ -943,9 +945,27 @@ 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;
TELY_AssetSpriteSheet *sheet = &game->heart_sprite_sheet;
switch (*state) {
case FP_EntityHeartState_Nil: {
action->next_state = FP_EntityHeartState_Idle;
} break;
case FP_EntityHeartState_Idle: {
if (entering_new_state) {
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.heart, TELY_AssetFlip_No);
uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
}
} break;
}
} break;
case FP_EntityType_Nil: break;
case FP_EntityType_Count: DQN_INVALID_CODE_PATH; break;
}
}
@@ -1058,9 +1078,11 @@ 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) {
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_GameFindClosestEntityResult closest_result = FP_Game_FindClosestEntityWithType(game, entity->handle, FP_EntityType_Terry);
Dqn_f32 aggro_dist_threshold = FP_Game_MetersToPixelsNx1(game, 4.f);
if (closest_result.dist_squared < DQN_SQUARED(aggro_dist_threshold)) {
bool has_waypoint_to_terry = false;
for (FP_SentinelListLink<FP_GameWaypoint> *link = nullptr;
!has_waypoint_to_terry && FP_SentinelList_Iterate<FP_GameWaypoint>(&entity->waypoints, &link); ) {
@@ -1091,6 +1113,15 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
terry->aggro_slot[aggro_direction] = entity->handle;
}
}
} else {
if (closest_result.dist_squared > DQN_SQUARED(aggro_dist_threshold * 2.f)) {
for (FP_SentinelListLink<FP_GameWaypoint> *link = nullptr; FP_SentinelList_Iterate<FP_GameWaypoint>(&entity->waypoints, &link); ) {
FP_GameEntity *maybe_terry = FP_Game_GetEntity(game, link->data.entity);
if (maybe_terry->type == FP_EntityType_Terry) {
link = FP_SentinelList_Erase(&entity->waypoints, link, game->chunk_pool);
}
}
}
}
}
@@ -1127,6 +1158,39 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
}
}
if (entity->flags & FP_GameEntityFlag_PointOfInterestHeart) {
FP_GameFindClosestEntityResult closest_heart = FP_Game_FindClosestEntityWithType(game, entity->handle, FP_EntityType_Heart);
if (closest_heart.dist_squared < DQN_SQUARED(FP_Game_MetersToPixelsNx1(game, 4.f))) {
bool has_waypoint_to = false;
for (FP_SentinelListLink<FP_GameWaypoint> *link = nullptr;
!has_waypoint_to && FP_SentinelList_Iterate<FP_GameWaypoint>(&entity->waypoints, &link); ) {
has_waypoint_to = link->data.entity == closest_heart.entity;
}
if (!has_waypoint_to) {
Dqn_Rect club_hit_box = FP_Game_CalcEntityWorldHitBox(game, closest_heart.entity);
Dqn_V2 club_top_left = Dqn_Rect_TopLeft(club_hit_box);
Dqn_V2 club_top_right = Dqn_Rect_TopRight(club_hit_box);
FP_SentinelListLink<FP_GameWaypoint> *link = FP_SentinelList_MakeBefore(&entity->waypoints, FP_SentinelList_Front(&entity->waypoints), game->chunk_pool);
FP_GameWaypoint *waypoint = &link->data;
waypoint->entity = closest_heart.entity;
waypoint->type = FP_GameWaypointType_Side;
if (entity_pos.x <= club_top_left.x) {
waypoint->type_direction = FP_GameDirection_Left;
} else if (entity_pos.x >= club_top_right.x) {
waypoint->type_direction = FP_GameDirection_Right;
} else if (entity_pos.y <= club_top_left.y) {
waypoint->type_direction = FP_GameDirection_Up;
} else {
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;
@@ -1163,10 +1227,14 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
// NOTE: We have arrived at the waypoint
bool aggro_on_terry = (entity->flags & FP_GameEntityFlag_AggrosWhenNearTerry) && waypoint_entity->type == FP_EntityType_Terry;
bool club_terry_response = (entity->flags & FP_GameEntityFlag_RespondsToClubTerry) &&
((entity->flags & FP_GameEntityFlag_ExperiencedClubTerry) == 0) &&
waypoint_entity->type == FP_EntityType_ClubTerry;
if (((waypoint->flags & FP_GameWaypointFlag_NonInterruptible) == 0) && (aggro_on_terry || club_terry_response)) {
bool heart_response = (entity->flags & FP_GameEntityFlag_PointOfInterestHeart) && waypoint_entity->type == FP_EntityType_Heart;
if (((waypoint->flags & FP_GameWaypointFlag_NonInterruptible) == 0) && (aggro_on_terry || club_terry_response || heart_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 (club_terry_response) {
@@ -1230,6 +1298,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
case FP_EntityType_Count: DQN_INVALID_CODE_PATH; break;
case FP_EntityType_ClubTerry: break;
case FP_EntityType_Map: break;
case FP_EntityType_Heart: break;
}
}