fp: Load heart & remove aggro when terry distances himself
This commit is contained in:
parent
f258886d68
commit
0234d34673
BIN
Data/Textures/heart_resized_25%.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/heart_resized_25%.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/heart_resized_25%.txt
(Stored with Git LFS)
Normal file
BIN
Data/Textures/heart_resized_25%.txt
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/heart_resized_25%/heart_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/heart_resized_25%/heart_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/heart_resized_25%/heart_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/heart_resized_25%/heart_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/heart_resized_25%/heart_3.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/heart_resized_25%/heart_3.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/heart_resized_25%/heart_bleed_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/heart_resized_25%/heart_bleed_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/heart_resized_25%/heart_bleed_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/heart_resized_25%/heart_bleed_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/heart_resized_25%/heart_bleed_3.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/heart_resized_25%/heart_bleed_3.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/heart_resized_25%/heart_bleed_4.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/heart_resized_25%/heart_bleed_4.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/heart_resized_25%/heart_bleed_5.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/heart_resized_25%/heart_bleed_5.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/heart_resized_25%/heart_bleed_6.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/heart_resized_25%/heart_bleed_6.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/sprite_spec.txt
(Stored with Git LFS)
BIN
Data/Textures/sprite_spec.txt
(Stored with Git LFS)
Binary file not shown.
@ -16,3 +16,4 @@ if not exist "%sprite_packer%" (
|
|||||||
%sprite_packer% 4096x2048 %script_dir%\Data\Textures\sprite_spec.txt %script_dir%\Data\Textures\clinger_resized_25%% || exit /b 1
|
%sprite_packer% 4096x2048 %script_dir%\Data\Textures\sprite_spec.txt %script_dir%\Data\Textures\clinger_resized_25%% || exit /b 1
|
||||||
%sprite_packer% 4096x2048 %script_dir%\Data\Textures\sprite_spec.txt %script_dir%\Data\Textures\club_terry_resized_25%% || exit /b 1
|
%sprite_packer% 4096x2048 %script_dir%\Data\Textures\sprite_spec.txt %script_dir%\Data\Textures\club_terry_resized_25%% || exit /b 1
|
||||||
%sprite_packer% 4096x2048 %script_dir%\Data\Textures\sprite_spec.txt %script_dir%\Data\Textures\map_resized_25%% || exit /b 1
|
%sprite_packer% 4096x2048 %script_dir%\Data\Textures\sprite_spec.txt %script_dir%\Data\Textures\map_resized_25%% || exit /b 1
|
||||||
|
%sprite_packer% 8192x8192 %script_dir%\Data\Textures\sprite_spec.txt %script_dir%\Data\Textures\heart_resized_25%% || exit /b 1
|
||||||
|
@ -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->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->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->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);
|
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_Game_PopParentEntity(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FP_Entity_CreateHeart(game, base_mid_p, "Heart");
|
||||||
|
|
||||||
uint16_t font_size = 18;
|
uint16_t font_size = 18;
|
||||||
game->camera.scale = Dqn_V2_InitNx1(1);
|
game->camera.scale = Dqn_V2_InitNx1(1);
|
||||||
@ -943,9 +945,27 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
|
|||||||
|
|
||||||
} break;
|
} 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_Nil: break;
|
||||||
case FP_EntityType_Count: DQN_INVALID_CODE_PATH; 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);
|
Dqn_V2 entity_pos = FP_Game_CalcEntityWorldPos(game, entity->handle);
|
||||||
|
|
||||||
if (entity->flags & FP_GameEntityFlag_AggrosWhenNearTerry) {
|
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;
|
bool has_waypoint_to_terry = false;
|
||||||
for (FP_SentinelListLink<FP_GameWaypoint> *link = nullptr;
|
for (FP_SentinelListLink<FP_GameWaypoint> *link = nullptr;
|
||||||
!has_waypoint_to_terry && FP_SentinelList_Iterate<FP_GameWaypoint>(&entity->waypoints, &link); ) {
|
!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;
|
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) {
|
while (entity->waypoints.size) {
|
||||||
FP_SentinelListLink<FP_GameWaypoint> *waypoint_link = entity->waypoints.sentinel->next;
|
FP_SentinelListLink<FP_GameWaypoint> *waypoint_link = entity->waypoints.sentinel->next;
|
||||||
FP_GameWaypoint const *waypoint = &waypoint_link->data;
|
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
|
// NOTE: We have arrived at the waypoint
|
||||||
bool aggro_on_terry = (entity->flags & FP_GameEntityFlag_AggrosWhenNearTerry) && waypoint_entity->type == FP_EntityType_Terry;
|
bool aggro_on_terry = (entity->flags & FP_GameEntityFlag_AggrosWhenNearTerry) && waypoint_entity->type == FP_EntityType_Terry;
|
||||||
|
|
||||||
bool club_terry_response = (entity->flags & FP_GameEntityFlag_RespondsToClubTerry) &&
|
bool club_terry_response = (entity->flags & FP_GameEntityFlag_RespondsToClubTerry) &&
|
||||||
((entity->flags & FP_GameEntityFlag_ExperiencedClubTerry) == 0) &&
|
((entity->flags & FP_GameEntityFlag_ExperiencedClubTerry) == 0) &&
|
||||||
waypoint_entity->type == FP_EntityType_ClubTerry;
|
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
|
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) {
|
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_Count: DQN_INVALID_CODE_PATH; break;
|
||||||
case FP_EntityType_ClubTerry: break;
|
case FP_EntityType_ClubTerry: break;
|
||||||
case FP_EntityType_Map: break;
|
case FP_EntityType_Map: break;
|
||||||
|
case FP_EntityType_Heart: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
feely_pona.h
21
feely_pona.h
@ -42,17 +42,20 @@ struct FP_GlobalAnimations
|
|||||||
Dqn_String8 smoochie_attack_heart = DQN_STRING8("smoochie_attack_heart");
|
Dqn_String8 smoochie_attack_heart = DQN_STRING8("smoochie_attack_heart");
|
||||||
Dqn_String8 smoochie_death = DQN_STRING8("smoochie_death");
|
Dqn_String8 smoochie_death = DQN_STRING8("smoochie_death");
|
||||||
|
|
||||||
Dqn_String8 clinger_attack_down = DQN_STRING8("clinger_attack_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_side = DQN_STRING8("clinger_attack_side");
|
||||||
Dqn_String8 clinger_attack_up = DQN_STRING8("clinger_attack_up");
|
Dqn_String8 clinger_attack_up = DQN_STRING8("clinger_attack_up");
|
||||||
Dqn_String8 clinger_death = DQN_STRING8("clinger_death");
|
Dqn_String8 clinger_death = DQN_STRING8("clinger_death");
|
||||||
Dqn_String8 clinger_walk_up = DQN_STRING8("clinger_walk_up");
|
Dqn_String8 clinger_walk_up = DQN_STRING8("clinger_walk_up");
|
||||||
Dqn_String8 clinger_walk_down = DQN_STRING8("clinger_walk_down");
|
Dqn_String8 clinger_walk_down = DQN_STRING8("clinger_walk_down");
|
||||||
|
|
||||||
Dqn_String8 club_terry_alive = DQN_STRING8("club_terry_alive");
|
Dqn_String8 club_terry_alive = DQN_STRING8("club_terry_alive");
|
||||||
Dqn_String8 club_terry_dark = DQN_STRING8("club_terry_dark");
|
Dqn_String8 club_terry_dark = DQN_STRING8("club_terry_dark");
|
||||||
|
|
||||||
Dqn_String8 map = DQN_STRING8("map");
|
Dqn_String8 heart = DQN_STRING8("heart");
|
||||||
|
Dqn_String8 heart_bleed = DQN_STRING8("heart_bleed");
|
||||||
|
|
||||||
|
Dqn_String8 map = DQN_STRING8("map");
|
||||||
}
|
}
|
||||||
g_anim_names;
|
g_anim_names;
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ enum FP_EntityType
|
|||||||
FP_EntityType_Merchant,
|
FP_EntityType_Merchant,
|
||||||
FP_EntityType_ClubTerry,
|
FP_EntityType_ClubTerry,
|
||||||
FP_EntityType_Clinger,
|
FP_EntityType_Clinger,
|
||||||
|
FP_EntityType_Heart,
|
||||||
FP_EntityType_Count,
|
FP_EntityType_Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -62,3 +63,9 @@ enum FP_EntityMapState
|
|||||||
FP_EntityMapState_Nil,
|
FP_EntityMapState_Nil,
|
||||||
FP_EntityMapState_Idle,
|
FP_EntityMapState_Idle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum FP_EntityHeartState
|
||||||
|
{
|
||||||
|
FP_EntityHeartState_Nil,
|
||||||
|
FP_EntityHeartState_Idle,
|
||||||
|
};
|
||||||
|
@ -191,3 +191,27 @@ static FP_GameEntityHandle FP_Entity_CreateClubTerry(FP_Game *game, Dqn_V2 pos,
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FP_GameEntityHandle FP_Entity_CreateHeart(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_Heart;
|
||||||
|
entity->local_pos = pos;
|
||||||
|
entity->sprite_height.meters = 4.f;
|
||||||
|
|
||||||
|
TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(&game->heart_sprite_sheet, g_anim_names.heart);
|
||||||
|
Dqn_Rect sprite_rect = game->heart_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_size = Dqn_V2_InitNx2(sprite_rect_scaled.w - (sprite_rect_scaled.w * .1f), sprite_rect_scaled.h);
|
||||||
|
FP_Entity_AddDebugEditorFlags(game, result);
|
||||||
|
entity->flags |= FP_GameEntityFlag_NonTraversable;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
@ -19,6 +19,7 @@ enum FP_GameEntityFlag
|
|||||||
FP_GameEntityFlag_RespondsToClubTerry = 1 << 11,
|
FP_GameEntityFlag_RespondsToClubTerry = 1 << 11,
|
||||||
FP_GameEntityFlag_PartyingAtClubTerry = 1 << 12,
|
FP_GameEntityFlag_PartyingAtClubTerry = 1 << 12,
|
||||||
FP_GameEntityFlag_ExperiencedClubTerry = 1 << 13,
|
FP_GameEntityFlag_ExperiencedClubTerry = 1 << 13,
|
||||||
|
FP_GameEntityFlag_PointOfInterestHeart = 1 << 11,
|
||||||
FP_GameEntityFlag_CameraTracking = 1 << 14,
|
FP_GameEntityFlag_CameraTracking = 1 << 14,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -230,6 +231,7 @@ struct FP_Game
|
|||||||
TELY_AssetSpriteSheet clinger_sprite_sheet;
|
TELY_AssetSpriteSheet clinger_sprite_sheet;
|
||||||
TELY_AssetSpriteSheet club_terry_sprite_sheet;
|
TELY_AssetSpriteSheet club_terry_sprite_sheet;
|
||||||
TELY_AssetSpriteSheet map_sprite_sheet;
|
TELY_AssetSpriteSheet map_sprite_sheet;
|
||||||
|
TELY_AssetSpriteSheet heart_sprite_sheet;
|
||||||
|
|
||||||
FP_GameEntity *root_entity;
|
FP_GameEntity *root_entity;
|
||||||
FP_GameEntity *entity_free_list;
|
FP_GameEntity *entity_free_list;
|
||||||
|
Loading…
Reference in New Issue
Block a user