Compare commits
8 Commits
7d0fde9a62
...
bfe2fef528
Author | SHA1 | Date | |
---|---|---|---|
bfe2fef528 | |||
85603bda2a | |||
45d981099c | |||
4bcbc61721 | |||
5f8344ddda | |||
aed29a9f50 | |||
0e22b49271 | |||
760da9d39f |
BIN
Data/Textures/atlas.png
(Stored with Git LFS)
BIN
Data/Textures/atlas.png
(Stored with Git LFS)
Binary file not shown.
BIN
Data/Textures/atlas.txt
(Stored with Git LFS)
BIN
Data/Textures/atlas.txt
(Stored with Git LFS)
Binary file not shown.
BIN
Data/Textures/atlas/airport_terry_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/airport_terry_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/airport_terry_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/airport_terry_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/airport_terry_plane_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/airport_terry_plane_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/airport_terry_plane_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/airport_terry_plane_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/catfish_attack_down_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/catfish_attack_down_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/catfish_attack_down_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/catfish_attack_down_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/catfish_attack_side_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/catfish_attack_side_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/catfish_attack_side_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/catfish_attack_side_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/catfish_attack_up_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/catfish_attack_up_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/catfish_attack_up_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/catfish_attack_up_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/catfish_death_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/catfish_death_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/catfish_death_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/catfish_death_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/catfish_death_3.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/catfish_death_3.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/catfish_death_4.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/catfish_death_4.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/catfish_walk_down_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/catfish_walk_down_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/catfish_walk_down_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/catfish_walk_down_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/catfish_walk_side_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/catfish_walk_side_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/catfish_walk_side_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/catfish_walk_side_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/catfish_walk_up_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/catfish_walk_up_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/catfish_walk_up_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/catfish_walk_up_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/church_terry_alive.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/church_terry_alive.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/church_terry_dark.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/church_terry_dark.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/kennel_terry_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/kennel_terry_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/kennel_terry_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/kennel_terry_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/merchant_button_a.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/merchant_button_a.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/merchant_button_b.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/merchant_button_b.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/merchant_button_x.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/merchant_button_x.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/merchant_button_y.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/merchant_button_y.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/merchant_graveyard_menu_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/merchant_graveyard_menu_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/merchant_graveyard_menu_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/merchant_graveyard_menu_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/merchant_gym_menu_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/merchant_gym_menu_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/merchant_gym_menu_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/merchant_gym_menu_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/merchant_phone_company_menu_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/merchant_phone_company_menu_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/merchant_phone_company_menu_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/merchant_phone_company_menu_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/merchant_terry_menu_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/merchant_terry_menu_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/merchant_terry_menu_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/merchant_terry_menu_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/shrubbery_bush_1_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/shrubbery_bush_1_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/shrubbery_bush_2_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/shrubbery_bush_2_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/shrubbery_island_1_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/shrubbery_island_1_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/shrubbery_island_2_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/shrubbery_island_2_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/shrubbery_island_3_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/shrubbery_island_3_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/terry_attack_phone_down_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/terry_attack_phone_down_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/terry_attack_phone_down_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/terry_attack_phone_down_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/terry_attack_phone_message_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/terry_attack_phone_message_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/terry_attack_phone_message_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/terry_attack_phone_message_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/terry_attack_phone_message_3.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/terry_attack_phone_message_3.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/terry_attack_phone_side_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/terry_attack_phone_side_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/terry_attack_phone_side_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/terry_attack_phone_side_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/terry_attack_phone_up_1.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/terry_attack_phone_up_1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/terry_attack_phone_up_2.png
(Stored with Git LFS)
Normal file
BIN
Data/Textures/atlas/terry_attack_phone_up_2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Data/Textures/atlas/terry_walk_left_1.png
(Stored with Git LFS)
BIN
Data/Textures/atlas/terry_walk_left_1.png
(Stored with Git LFS)
Binary file not shown.
BIN
Data/Textures/atlas/terry_walk_left_2.png
(Stored with Git LFS)
BIN
Data/Textures/atlas/terry_walk_left_2.png
(Stored with Git LFS)
Binary file not shown.
BIN
Data/Textures/atlas/terry_walk_left_3.png
(Stored with Git LFS)
BIN
Data/Textures/atlas/terry_walk_left_3.png
(Stored with Git LFS)
Binary file not shown.
BIN
Data/Textures/atlas/terry_walk_left_5.png
(Stored with Git LFS)
BIN
Data/Textures/atlas/terry_walk_left_5.png
(Stored with Git LFS)
Binary file not shown.
BIN
Data/Textures/atlas/terry_walk_left_6.png
(Stored with Git LFS)
BIN
Data/Textures/atlas/terry_walk_left_6.png
(Stored with Git LFS)
Binary file not shown.
BIN
Data/Textures/atlas/terry_walk_left_7.png
(Stored with Git LFS)
BIN
Data/Textures/atlas/terry_walk_left_7.png
(Stored with Git LFS)
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.
2
External/tely
vendored
2
External/tely
vendored
@ -1 +1 @@
|
||||
Subproject commit 4ccbde6fecb8ea17f9cde73df7c06da466311f3c
|
||||
Subproject commit 8576ce00dc74f817b346994efca8610001a8eafb
|
560
feely_pona.cpp
560
feely_pona.cpp
@ -5,39 +5,40 @@
|
||||
|
||||
Dqn_f32 const PHYSICS_STEP = 1 / 60.f;
|
||||
|
||||
Dqn_Rect FP_Game_GetBuildingPlacementRectForEntity(FP_Game *game, FP_GameEntityHandle handle)
|
||||
|
||||
Dqn_Rect FP_Game_GetBuildingPlacementRectForEntity(FP_Game *game, FP_GamePlaceableBuilding placeable_building, FP_GameEntityHandle handle)
|
||||
{
|
||||
Dqn_Rect result = {};
|
||||
FP_GameEntity *entity = FP_Game_GetEntity(game, handle);
|
||||
if (FP_Game_IsNilEntity(entity))
|
||||
return result;
|
||||
|
||||
FP_EntityRenderData club_terry_render_data = FP_Entity_GetRenderData(game, FP_EntityType_ClubTerry, FP_EntityClubTerryState_Idle, entity->direction);
|
||||
FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, placeable_building.type, placeable_building.state, entity->direction);
|
||||
|
||||
Dqn_Rect box = FP_Game_CalcEntityWorldHitBox(game, entity->handle);
|
||||
Dqn_V2 build_p = {};
|
||||
switch (entity->direction) {
|
||||
case FP_GameDirection_Up: {
|
||||
build_p = Dqn_Rect_InterpolatedPoint(box, Dqn_V2_InitNx2(0.5f, 0.f)) - Dqn_V2_InitNx2(0.f, club_terry_render_data.render_size.h * .5f + 10.f);
|
||||
build_p = Dqn_Rect_InterpolatedPoint(box, Dqn_V2_InitNx2(0.5f, 0.f)) - Dqn_V2_InitNx2(0.f, render_data.render_size.h * .5f + 10.f);
|
||||
} break;
|
||||
|
||||
case FP_GameDirection_Down: {
|
||||
build_p = Dqn_Rect_InterpolatedPoint(box, Dqn_V2_InitNx2(0.5f, 1.f)) + Dqn_V2_InitNx2(0.f, club_terry_render_data.render_size.h * .5f + 10.f);
|
||||
build_p = Dqn_Rect_InterpolatedPoint(box, Dqn_V2_InitNx2(0.5f, 1.f)) + Dqn_V2_InitNx2(0.f, render_data.render_size.h * .5f + 10.f);
|
||||
} break;
|
||||
|
||||
case FP_GameDirection_Left: {
|
||||
build_p = Dqn_Rect_InterpolatedPoint(box, Dqn_V2_InitNx2(0.0f, 0.5f)) - Dqn_V2_InitNx2(club_terry_render_data.render_size.w * .5f + 10.f, 0);
|
||||
build_p = Dqn_Rect_InterpolatedPoint(box, Dqn_V2_InitNx2(0.0f, 0.5f)) - Dqn_V2_InitNx2(render_data.render_size.w * .5f + 10.f, 0);
|
||||
} break;
|
||||
|
||||
case FP_GameDirection_Right: {
|
||||
build_p = Dqn_Rect_InterpolatedPoint(box, Dqn_V2_InitNx2(1.f, 0.5f)) + Dqn_V2_InitNx2(club_terry_render_data.render_size.w * .5f + 10.f, 0);
|
||||
build_p = Dqn_Rect_InterpolatedPoint(box, Dqn_V2_InitNx2(1.f, 0.5f)) + Dqn_V2_InitNx2(render_data.render_size.w * .5f + 10.f, 0);
|
||||
} break;
|
||||
|
||||
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
|
||||
}
|
||||
|
||||
result.size = club_terry_render_data.render_size;
|
||||
result.pos = build_p - (club_terry_render_data.render_size * .5f);
|
||||
result.size = render_data.render_size;
|
||||
result.pos = build_p - (render_data.render_size * .5f);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -172,12 +173,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 +205,10 @@ 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;
|
||||
case FP_EntityType_PhoneMessageProjectile: break;
|
||||
}
|
||||
|
||||
if (!entity_collides_with_collider)
|
||||
@ -206,6 +216,9 @@ static void FP_Game_MoveEntity(FP_Game *game, FP_GameEntityHandle entity_handle,
|
||||
|
||||
// NOTE: Sweep collider with half the radius of the source entity
|
||||
Dqn_Rect collider_world_hit_box = FP_Game_CalcEntityWorldHitBox(game, collider->handle);
|
||||
if (Dqn_V2_Area(collider_world_hit_box.size) <= 0)
|
||||
continue;
|
||||
|
||||
Dqn_Rect swept_collider_world_hit_box = collider_world_hit_box;
|
||||
swept_collider_world_hit_box.pos -= (entity_world_hit_box.size * .5f);
|
||||
swept_collider_world_hit_box.size += entity_world_hit_box.size;
|
||||
@ -516,6 +529,9 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
|
||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
||||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
|
||||
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Attack);
|
||||
} else if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_K) ||
|
||||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_Y)) {
|
||||
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_RangeAttack);
|
||||
} else if (acceleration_meters_per_s->x || acceleration_meters_per_s->y) {
|
||||
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Run);
|
||||
}
|
||||
@ -533,6 +549,17 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
|
||||
}
|
||||
} break;
|
||||
|
||||
case FP_EntityTerryState_RangeAttack: {
|
||||
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;
|
||||
@ -543,6 +570,9 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
|
||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
|
||||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
|
||||
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Attack);
|
||||
} else if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_K) ||
|
||||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_Y)) {
|
||||
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_RangeAttack);
|
||||
} else if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_LeftControl) ||
|
||||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_A)) {
|
||||
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Dash);
|
||||
@ -566,7 +596,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_RangeAttack) {
|
||||
DQN_ASSERT(action->sprite.anim);
|
||||
|
||||
uint64_t duration_ms = action->sprite.anim->count * action->sprite.anim->ms_per_frame;
|
||||
@ -575,33 +605,46 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
|
||||
|
||||
// NOTE: Adding an attack_processed bool to make sure things only fire once
|
||||
if (!entity->attack_processed && game->clock_ms >= midpoint_clock_ms) {
|
||||
entity->attack_box_size = entity->local_hit_box_size;
|
||||
TELY_Audio_Play(audio, game->audio[FP_GameAudio_TerryHit], 1.f);
|
||||
|
||||
// NOTE: Position the attack box
|
||||
Dqn_V2 dir_vector = {};
|
||||
switch (entity->direction) {
|
||||
case FP_GameDirection_Left: {
|
||||
dir_vector.x = -1.f;
|
||||
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: {
|
||||
dir_vector.x = +1.f;
|
||||
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: {
|
||||
dir_vector.y = -1.f;
|
||||
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: {
|
||||
dir_vector.y = +1.f;
|
||||
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: break;
|
||||
}
|
||||
|
||||
if (*state == FP_EntityTerryState_RangeAttack) {
|
||||
Dqn_Rect entity_hit_box = FP_Game_CalcEntityWorldHitBox(game, entity->handle);
|
||||
Dqn_V2 projectile_pos = entity_hit_box.pos + entity->attack_box_offset;
|
||||
Dqn_V2 projectile_acceleration = FP_Game_MetersToPixelsV2(game, dir_vector * 0.25f);
|
||||
FP_Entity_CreatePhoneMessageProjectile(game, projectile_pos, projectile_acceleration, "Phone Message Projectile");
|
||||
} else {
|
||||
entity->attack_box_size = entity->local_hit_box_size;
|
||||
TELY_Audio_Play(audio, game->audio[FP_GameAudio_TerryHit], 1.f);
|
||||
}
|
||||
entity->attack_processed = true;
|
||||
} else {
|
||||
entity->attack_box_size = {};
|
||||
@ -704,6 +747,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
|
||||
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);
|
||||
entity->local_hit_box_size = {};
|
||||
}
|
||||
|
||||
if (action_has_finished)
|
||||
@ -808,6 +852,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
|
||||
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.clinger_death, TELY_AssetFlip_No);
|
||||
uint64_t duration_ms = sprite.anim->count * sprite.anim->ms_per_frame;
|
||||
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
|
||||
entity->local_hit_box_size = {};
|
||||
}
|
||||
|
||||
if (action_has_finished)
|
||||
@ -971,7 +1016,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 +1033,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 +1048,163 @@ 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);
|
||||
entity->local_hit_box_size = {};
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -1048,14 +1249,36 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
||||
if (game->clicked_entity.id) {
|
||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_Delete))
|
||||
FP_Game_DeleteEntity(game, game->clicked_entity);
|
||||
|
||||
// NOTE: Building selector
|
||||
Dqn_usize last_building_index = DQN_ARRAY_UCOUNT(PLACEABLE_BUILDINGS) - 1;
|
||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_Q)) {
|
||||
if (game->build_mode_building_index <= 0) {
|
||||
game->build_mode_building_index = last_building_index;
|
||||
} else {
|
||||
game->build_mode_building_index -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_E)) {
|
||||
if (game->build_mode_building_index >= last_building_index) {
|
||||
game->build_mode_building_index = 0;
|
||||
} else {
|
||||
game->build_mode_building_index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
Dqn_f32 pan_speed = 5.f;
|
||||
if (TELY_Platform_InputScanCodeIsDown(input, TELY_PlatformInputScanCode_Space))
|
||||
pan_speed *= 2.5f;
|
||||
|
||||
game->camera.world_pos += dir_vector * pan_speed;
|
||||
|
||||
}
|
||||
|
||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F1))
|
||||
game->debug_ui = !game->debug_ui;
|
||||
|
||||
Dqn_ProfilerZone update_zone = Dqn_Profiler_BeginZoneWithIndex(DQN_STRING8("FP_Update: Entity loop"), FP_ProfileZone_FPUpdate_EntityLoop);
|
||||
|
||||
// NOTE: Handle input ==========================================================================
|
||||
@ -1067,7 +1290,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
||||
continue;
|
||||
|
||||
// NOTE: Move entity by keyboard and gamepad ===============================================
|
||||
Dqn_V2 acceleration_meters_per_s = {};
|
||||
Dqn_V2 acceleration_meters_per_s = entity->constant_acceleration_per_s;
|
||||
if (game->clicked_entity == entity->handle) {
|
||||
if (entity->flags & (FP_GameEntityFlag_MoveByKeyboard | FP_GameEntityFlag_MoveByGamepad)) {
|
||||
bool move_entity = true;
|
||||
@ -1087,15 +1310,20 @@ 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_Nil: break;
|
||||
case FP_EntityType_ClubTerry: break;
|
||||
case FP_EntityType_Count: break;
|
||||
case FP_EntityType_Map: break;
|
||||
case FP_EntityType_MerchantTerry: break;
|
||||
case FP_EntityType_MerchantGraveyard: break;
|
||||
case FP_EntityType_MerchantPhoneCompany: break;
|
||||
case FP_EntityType_Heart: break;
|
||||
case FP_EntityType_MerchantGym: break;
|
||||
case FP_EntityType_Nil: break;
|
||||
case FP_EntityType_ClubTerry: break;
|
||||
case FP_EntityType_Count: break;
|
||||
case FP_EntityType_Map: break;
|
||||
case FP_EntityType_MerchantTerry: break;
|
||||
case FP_EntityType_MerchantGraveyard: break;
|
||||
case FP_EntityType_MerchantPhoneCompany: break;
|
||||
case FP_EntityType_Heart: break;
|
||||
case FP_EntityType_MerchantGym: break;
|
||||
case FP_EntityType_AirportTerry: break;
|
||||
case FP_EntityType_Catfish: break;
|
||||
case FP_EntityType_ChurchTerry: break;
|
||||
case FP_EntityType_KennelTerry: break;
|
||||
case FP_EntityType_PhoneMessageProjectile: break;
|
||||
}
|
||||
|
||||
if (move_entity) {
|
||||
@ -1315,16 +1543,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 +1571,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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1356,30 +1590,63 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
||||
if (game->active_entity == entity->handle && entity->flags & FP_GameEntityFlag_MoveByMouse) {
|
||||
entity->velocity = {};
|
||||
acceleration_meters_per_s = {};
|
||||
entity->local_pos += input->mouse_p_delta;
|
||||
entity->local_pos += input->mouse_p_delta;
|
||||
}
|
||||
|
||||
if (game->clicked_entity == entity->handle) {
|
||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F))
|
||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_H))
|
||||
game->build_mode = !game->build_mode;
|
||||
|
||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F1)) {
|
||||
entity->sprite_height.meters += 1;
|
||||
Dqn_Log_InfoF("Height: %.1f", entity->sprite_height.meters);
|
||||
}
|
||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F2)) {
|
||||
entity->sprite_height.meters -= 1;
|
||||
Dqn_Log_InfoF("Height: %.1f", entity->sprite_height.meters);
|
||||
}
|
||||
|
||||
if (entity->flags & FP_GameEntityFlag_CameraTracking)
|
||||
game->camera.world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle) - Dqn_V2_InitV2I(platform->core.window_size) * .5f;
|
||||
|
||||
game->build_mode_can_place_building = false;
|
||||
if (game->build_mode) {
|
||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_E)) {
|
||||
Dqn_Rect dest_rect = FP_Game_GetBuildingPlacementRectForEntity(game, entity->handle);
|
||||
Dqn_V2 placement_pos = Dqn_Rect_Center(dest_rect);
|
||||
FP_Entity_CreateClubTerry(game, placement_pos, "Club Terry");
|
||||
|
||||
FP_GamePlaceableBuilding placeable_building = PLACEABLE_BUILDINGS[game->build_mode_building_index];
|
||||
Dqn_Rect dest_rect = FP_Game_GetBuildingPlacementRectForEntity(game, placeable_building, entity->handle);
|
||||
Dqn_V2 placement_pos = Dqn_Rect_Center(dest_rect);
|
||||
|
||||
for (FP_GameEntityIterator zone_it = {};
|
||||
FP_Game_DFSPreOrderWalkEntityTree(game, &zone_it, game->root_entity);
|
||||
) {
|
||||
|
||||
FP_GameEntity *zone = zone_it.entity;
|
||||
bool is_building = zone->type == FP_EntityType_KennelTerry ||
|
||||
zone->type == FP_EntityType_AirportTerry ||
|
||||
zone->type == FP_EntityType_ChurchTerry ||
|
||||
zone->type == FP_EntityType_ClubTerry;
|
||||
|
||||
Dqn_Rect zone_hit_box = FP_Game_CalcEntityWorldHitBox(game, zone->handle);
|
||||
if (is_building) {
|
||||
if (Dqn_Rect_Intersects(zone_hit_box, dest_rect)) {
|
||||
game->build_mode_can_place_building = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((zone->flags & FP_GameEntityFlag_BuildZone) == 0)
|
||||
continue;
|
||||
|
||||
zone_hit_box.pos += dest_rect.size * .5f;
|
||||
zone_hit_box.size -= dest_rect.size;
|
||||
zone_hit_box.size = Dqn_V2_Max(zone_hit_box.size, Dqn_V2_Zero);
|
||||
|
||||
game->build_mode_can_place_building |= Dqn_Rect_ContainsPoint(zone_hit_box, placement_pos);
|
||||
}
|
||||
|
||||
if (game->build_mode_can_place_building &&
|
||||
TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F)) {
|
||||
if (placeable_building.type == FP_EntityType_ClubTerry) {
|
||||
FP_Entity_CreateClubTerry(game, placement_pos, "Club Terry");
|
||||
} else if (placeable_building.type == FP_EntityType_ChurchTerry) {
|
||||
FP_Entity_CreateChurchTerry(game, placement_pos, "Church Terry");
|
||||
} else if (placeable_building.type == FP_EntityType_AirportTerry) {
|
||||
FP_Entity_CreateAirportTerry(game, placement_pos, "Airport Terry");
|
||||
} else {
|
||||
DQN_ASSERT(placeable_building.type == FP_EntityType_KennelTerry);
|
||||
FP_Entity_CreateKennelTerry(game, placement_pos, "Kennel Terry");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1397,6 +1664,13 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
||||
for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) {
|
||||
FP_GameEntity *entity = it.entity;
|
||||
|
||||
if (entity->flags & FP_GameEntityFlag_TTL) {
|
||||
if (game->clock_ms >= entity->ttl_end_timestamp) {
|
||||
FP_Game_DeleteEntity(game, entity->handle);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Derive dynmamic bounding boxes ====================================================
|
||||
if (entity->flags & FP_GameEntityFlag_DeriveHitBoxFromChildrenBoundingBox) {
|
||||
Dqn_Rect children_bbox = {};
|
||||
@ -1439,15 +1713,19 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
||||
}
|
||||
} else if (entity->spawn_list.size < entity->spawn_cap) { // NOTE: Spawn new entities
|
||||
if (input->timer_s >= entity->next_spawn_timestamp_s) {
|
||||
uint64_t hp_adjustment = entity->current_wave - 1;
|
||||
entity->next_spawn_timestamp_s = DQN_CAST(uint64_t)(input->timer_s + 5.f);
|
||||
|
||||
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)
|
||||
link->data = FP_Entity_CreateClinger(game, entity_world_pos, "Clinger");
|
||||
Dqn_f32 mob_choice = Dqn_PCG32_NextF32(&game->rng);
|
||||
if (mob_choice <= 0.33f)
|
||||
link->data = FP_Entity_CreateClinger(game, entity_world_pos, hp_adjustment, "Clinger");
|
||||
else if (mob_choice <= 0.66f)
|
||||
link->data = FP_Entity_CreateSmoochie(game, entity_world_pos, hp_adjustment, "Smoochie");
|
||||
else
|
||||
link->data = FP_Entity_CreateSmoochie(game, entity_world_pos, "Smoochie");
|
||||
link->data = FP_Entity_CreateCatfish(game, entity_world_pos, hp_adjustment, "Catfish");
|
||||
|
||||
// NOTE: Setup the mob with waypoints
|
||||
FP_GameEntity *mob = FP_Game_GetEntity(game, link->data);
|
||||
@ -1499,12 +1777,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;
|
||||
|
||||
@ -1518,6 +1801,10 @@ 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;
|
||||
case FP_EntityType_PhoneMessageProjectile: break;
|
||||
}
|
||||
|
||||
if (!permit_attack)
|
||||
@ -1533,6 +1820,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
||||
defender->is_dying = true;
|
||||
|
||||
// NOTE: Kickback ======================================================================
|
||||
#if 0
|
||||
Dqn_V2 defender_world_pos = Dqn_Rect_Center(defender_box);
|
||||
Dqn_V2 attack_dir_vector = {};
|
||||
if (attacker_world_pos.x < defender_world_pos.x)
|
||||
@ -1542,6 +1830,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
||||
|
||||
Dqn_V2 attack_acceleration_meters_per_s = attack_dir_vector * 60.f;
|
||||
FP_Game_MoveEntity(game, defender->handle, attack_acceleration_meters_per_s);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1734,38 +2023,103 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer)
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Render waypoint entities ==========================================================
|
||||
if (entity->flags & FP_GameEntityFlag_MobSpawner) {
|
||||
Dqn_V2 start = world_pos;
|
||||
for (FP_GameEntity *waypoint_entity = entity->first_child; waypoint_entity; waypoint_entity = waypoint_entity->next) {
|
||||
if ((waypoint_entity->flags & FP_GameEntityFlag_MobSpawnerWaypoint) == 0)
|
||||
continue;
|
||||
if (game->build_mode) {
|
||||
if (entity->flags & FP_GameEntityFlag_BuildZone)
|
||||
TELY_Render_RectColourV4(renderer, world_hit_box, TELY_RenderShapeMode_Fill, TELY_Colour_V4Alpha(TELY_COLOUR_BLUE_CADET_V4, 0.5f));
|
||||
}
|
||||
|
||||
Dqn_V2 end = FP_Game_CalcEntityWorldPos(game, waypoint_entity->handle);
|
||||
TELY_Render_LineColourV4(renderer, start, end, TELY_COLOUR_BLUE_CADET_V4, 2.f);
|
||||
start = end;
|
||||
if (game->debug_ui) {
|
||||
// NOTE: Render waypoint entities ======================================================
|
||||
if (entity->flags & FP_GameEntityFlag_MobSpawner) {
|
||||
Dqn_V2 start = world_pos;
|
||||
for (FP_GameEntity *waypoint_entity = entity->first_child; waypoint_entity; waypoint_entity = waypoint_entity->next) {
|
||||
if ((waypoint_entity->flags & FP_GameEntityFlag_MobSpawnerWaypoint) == 0)
|
||||
continue;
|
||||
|
||||
Dqn_V2 end = FP_Game_CalcEntityWorldPos(game, waypoint_entity->handle);
|
||||
TELY_Render_LineColourV4(renderer, start, end, TELY_COLOUR_BLUE_CADET_V4, 2.f);
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
|
||||
if (entity->flags & FP_GameEntityFlag_MobSpawner)
|
||||
TELY_Render_RectColourV4(renderer, world_hit_box, TELY_RenderShapeMode_Line, TELY_COLOUR_BLUE_CADET_V4);
|
||||
|
||||
if (entity->flags & FP_GameEntityFlag_MobSpawnerWaypoint)
|
||||
TELY_Render_CircleColourV4(renderer, world_pos, 16.f /*radius*/, TELY_RenderShapeMode_Line, TELY_COLOUR_BLUE_CADET_V4);
|
||||
|
||||
if (entity->flags & FP_GameEntityFlag_BuildZone) {
|
||||
{
|
||||
Dqn_V2 line_p1 = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0, 0));
|
||||
Dqn_V2 line_p2 = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(1, 1));
|
||||
TELY_Render_LineColourV4(renderer, line_p1, line_p2, TELY_COLOUR_BLACK_V4, 2.f);
|
||||
}
|
||||
{
|
||||
Dqn_V2 line_p1 = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0, 1));
|
||||
Dqn_V2 line_p2 = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(1, 0));
|
||||
TELY_Render_LineColourV4(renderer, line_p1, line_p2, TELY_COLOUR_BLACK_V4, 2.f);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Render attack box =================================================================
|
||||
{
|
||||
Dqn_Rect attack_box = FP_Game_CalcEntityAttackWorldHitBox(game, entity->handle);
|
||||
TELY_Render_RectColourV4(renderer, attack_box, TELY_RenderShapeMode_Line, TELY_COLOUR_RED_TOMATO_V4);
|
||||
}
|
||||
|
||||
// NOTE: Render world position =============================================================
|
||||
TELY_Render_CircleColourV4(renderer, world_pos, 4.f, TELY_RenderShapeMode_Fill, TELY_COLOUR_RED_TOMATO_V4);
|
||||
|
||||
// NOTE: Render hot/active entity ==========================================================
|
||||
if (game->clicked_entity == entity->handle) {
|
||||
TELY_Render_RectColourV4(renderer, world_hit_box, TELY_RenderShapeMode_Line, TELY_COLOUR_WHITE_PALE_GOLDENROD_V4);
|
||||
|
||||
// NOTE: Draw the waypoints that the entity is moving along
|
||||
Dqn_V2 start = world_pos;
|
||||
for (FP_SentinelListLink<FP_GameWaypoint> *link = nullptr; FP_SentinelList_Iterate(&entity->waypoints, &link); ) {
|
||||
Dqn_V2 end = FP_Game_CalcWaypointWorldPos(game, &link->data);
|
||||
TELY_Render_LineColourV4(renderer, start, end, TELY_COLOUR_WHITE_PALE_GOLDENROD_V4, 2.f);
|
||||
start = end;
|
||||
}
|
||||
} else if (game->hot_entity == entity->handle || (entity->flags & FP_GameEntityFlag_DrawHitBox)) {
|
||||
Dqn_V4 hot_colour = game->hot_entity == entity->handle ? TELY_COLOUR_RED_TOMATO_V4 : TELY_Colour_V4Alpha(TELY_COLOUR_YELLOW_SANDY_V4, .5f);
|
||||
TELY_Render_RectColourV4(renderer, world_hit_box, TELY_RenderShapeMode_Line, hot_colour);
|
||||
}
|
||||
|
||||
if (game->hot_entity == entity->handle) {
|
||||
if (entity->name.size) {
|
||||
Dqn_V2I player_tile = Dqn_V2I_InitNx2(world_pos.x / game->tile_size, world_pos.y / game->tile_size);
|
||||
Dqn_f32 line_height = TELY_Render_FontHeight(renderer, &platform->assets);
|
||||
Dqn_V2 draw_p = world_mouse_p;
|
||||
TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0.f, 1), "%.*s", DQN_STRING_FMT(entity->name)); draw_p.y += line_height;
|
||||
TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0.f, 1), "World Pos: (%.1f, %.1f)", world_pos.x, world_pos.y); draw_p.y += line_height;
|
||||
TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0.f, 1), "Hit Box Size: %.1fx%.1f", world_hit_box.size.x, world_hit_box.size.y); draw_p.y += line_height;
|
||||
TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0.f, 1), "Tile: %I32dx%I32d", player_tile.x, player_tile.y); draw_p.y += line_height;
|
||||
TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0.f, 1), "World Mouse Pos: (%.1f, %.1f)", world_mouse_p.x, world_mouse_p.y); draw_p.y += line_height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Render attack box =================================================================
|
||||
{
|
||||
Dqn_Rect attack_box = FP_Game_CalcEntityAttackWorldHitBox(game, entity->handle);
|
||||
TELY_Render_RectColourV4(renderer, attack_box, TELY_RenderShapeMode_Line, TELY_COLOUR_RED_TOMATO_V4);
|
||||
}
|
||||
|
||||
// NOTE: Render world position =============================================================
|
||||
TELY_Render_CircleColourV4(renderer, world_pos, 4.f, TELY_RenderShapeMode_Fill, TELY_COLOUR_RED_TOMATO_V4);
|
||||
}
|
||||
|
||||
if (!FP_Game_IsNilEntityHandle(game, game->clicked_entity)) {
|
||||
// NOTE: Render building blueprint =========================================================
|
||||
if (game->clicked_entity == entity->handle && game->build_mode) {
|
||||
if (game->build_mode) {
|
||||
FP_GameEntity *entity = FP_Game_GetEntity(game, game->clicked_entity);
|
||||
|
||||
TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity());
|
||||
Dqn_V2 label_p = Dqn_V2_InitNx2(platform->core.window_size.x * .5f, platform->core.window_size.y * .1f);
|
||||
TELY_Render_Text(renderer, label_p, Dqn_V2_InitNx2(0.5f, 0.5f), DQN_STRING8("Build Mode"));
|
||||
TELY_Render_PopTransform(renderer);
|
||||
|
||||
FP_EntityRenderData club_terry_render_data = FP_Entity_GetRenderData(game, FP_EntityType_ClubTerry, FP_EntityClubTerryState_Idle, entity->direction);
|
||||
Dqn_Rect dest_rect = FP_Game_GetBuildingPlacementRectForEntity(game, entity->handle);
|
||||
FP_GamePlaceableBuilding placeable_building = PLACEABLE_BUILDINGS[game->build_mode_building_index];
|
||||
FP_EntityRenderData club_terry_render_data = FP_Entity_GetRenderData(game, placeable_building.type, placeable_building.state, entity->direction);
|
||||
Dqn_Rect dest_rect = FP_Game_GetBuildingPlacementRectForEntity(game, placeable_building, entity->handle);
|
||||
|
||||
Dqn_V4 colour = game->build_mode_can_place_building ?
|
||||
TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, 0.5f) :
|
||||
TELY_Colour_V4Alpha(TELY_COLOUR_RED_V4, 0.5f);
|
||||
|
||||
TELY_Render_RectColourV4(renderer, dest_rect, TELY_RenderShapeMode_Fill, TELY_Colour_V4Alpha(TELY_COLOUR_BLUE_CADET_V4, 0.5f));
|
||||
TELY_Render_TextureColourV4(renderer,
|
||||
@ -1774,38 +2128,56 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer)
|
||||
dest_rect,
|
||||
Dqn_V2_Zero /*rotate origin*/,
|
||||
0.f /*rotation*/,
|
||||
TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, 0.5f));
|
||||
colour);
|
||||
}
|
||||
|
||||
// NOTE: Render hot/active entity ==========================================================
|
||||
if (game->clicked_entity == entity->handle) {
|
||||
TELY_Render_RectColourV4(renderer, world_hit_box, TELY_RenderShapeMode_Line, TELY_COLOUR_WHITE_PALE_GOLDENROD_V4);
|
||||
// NOTE: Render the building selector UI ===================================================
|
||||
{
|
||||
TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity());
|
||||
DQN_DEFER { TELY_Render_PopTransform(renderer); };
|
||||
|
||||
// NOTE: Draw the waypoints that the entity is moving along
|
||||
Dqn_V2 start = world_pos;
|
||||
for (FP_SentinelListLink<FP_GameWaypoint> *link = nullptr; FP_SentinelList_Iterate(&entity->waypoints, &link); ) {
|
||||
Dqn_V2 end = FP_Game_CalcWaypointWorldPos(game, &link->data);
|
||||
TELY_Render_LineColourV4(renderer, start, end, TELY_COLOUR_WHITE_PALE_GOLDENROD_V4, 2.f);
|
||||
start = end;
|
||||
}
|
||||
} else if (game->hot_entity == entity->handle || (entity->flags & FP_GameEntityFlag_DrawHitBox)) {
|
||||
Dqn_V4 hot_colour = game->hot_entity == entity->handle ? TELY_COLOUR_RED_TOMATO_V4 : TELY_Colour_V4Alpha(TELY_COLOUR_YELLOW_SANDY_V4, .5f);
|
||||
TELY_Render_RectColourV4(renderer, world_hit_box, TELY_RenderShapeMode_Line, hot_colour);
|
||||
}
|
||||
game->build_mode_building_index = DQN_CLAMP(game->build_mode_building_index, 0, DQN_ARRAY_UCOUNT(PLACEABLE_BUILDINGS) - 1);
|
||||
|
||||
if (game->hot_entity == entity->handle) {
|
||||
if (entity->name.size) {
|
||||
Dqn_V2I player_tile = Dqn_V2I_InitNx2(world_pos.x / game->tile_size, world_pos.y / game->tile_size);
|
||||
Dqn_f32 line_height = TELY_Render_FontHeight(renderer, &platform->assets);
|
||||
Dqn_V2 draw_p = world_mouse_p;
|
||||
TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0.f, 1), "%.*s", DQN_STRING_FMT(entity->name)); draw_p.y += line_height;
|
||||
TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0.f, 1), "World Pos: (%.1f, %.1f)", world_pos.x, world_pos.y); draw_p.y += line_height;
|
||||
TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0.f, 1), "Hit Box Size: %.1fx%.1f", world_hit_box.size.x, world_hit_box.size.y); draw_p.y += line_height;
|
||||
TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0.f, 1), "Tile: %I32dx%I32d", player_tile.x, player_tile.y); draw_p.y += line_height;
|
||||
TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0.f, 1), "World Mouse Pos: (%.1f, %.1f)", world_mouse_p.x, world_mouse_p.y); draw_p.y += line_height;
|
||||
Dqn_f32 building_ui_size = 150.f;
|
||||
Dqn_f32 padding = 10.f;
|
||||
Dqn_f32 total_size = DQN_ARRAY_UCOUNT(PLACEABLE_BUILDINGS) * building_ui_size + ((DQN_ARRAY_UCOUNT(PLACEABLE_BUILDINGS) - 1) * padding);
|
||||
Dqn_f32 start_x = (platform->core.window_size.x * .5f) - (total_size * .5f);
|
||||
DQN_FOR_UINDEX (building_index, DQN_ARRAY_UCOUNT(PLACEABLE_BUILDINGS)) {
|
||||
FP_GamePlaceableBuilding building = PLACEABLE_BUILDINGS[building_index];
|
||||
FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, building.type, building.state, FP_GameDirection_Down);
|
||||
Dqn_Rect rect = Dqn_Rect_InitNx4(start_x + (building_index * building_ui_size) + (padding * building_index),
|
||||
32.f,
|
||||
building_ui_size,
|
||||
building_ui_size);
|
||||
|
||||
Dqn_V4 texture_colour = TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, .5f);
|
||||
Dqn_V4 outline_colour = TELY_COLOUR_WHITE_PALE_GOLDENROD_V4;
|
||||
if (game->build_mode_building_index == building_index) {
|
||||
outline_colour = TELY_COLOUR_RED_TOMATO_V4;
|
||||
texture_colour.a = 1.f;
|
||||
}
|
||||
|
||||
TELY_Render_RectColourV4(renderer, rect, TELY_RenderShapeMode_Fill, TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, 0.5f));
|
||||
TELY_Render_TextureColourV4(renderer,
|
||||
render_data.sheet->tex_handle,
|
||||
render_data.sheet_rect,
|
||||
rect,
|
||||
Dqn_V2_Zero /*rotate origin*/,
|
||||
0.f /*rotation*/,
|
||||
texture_colour);
|
||||
|
||||
|
||||
TELY_RenderCommandRect *cmd = TELY_Render_RectColourV4(renderer, rect, TELY_RenderShapeMode_Line, outline_colour);
|
||||
cmd->thickness = 2.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Add scanlines into the game for A E S T H E T I C S
|
||||
Dqn_V2 screen_size = Dqn_V2_InitNx2(platform->core.window_size.w, platform->core.window_size.h);
|
||||
Dqn_f32 scanline_gap = 4.0f;
|
||||
Dqn_f32 scanline_thickness = 3.0f;
|
||||
FP_GameRenderCameraFollowScanlines(renderer, screen_size, game->camera.world_pos, scanline_gap, scanline_thickness);
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport)
|
||||
@ -1886,7 +2258,7 @@ void TELY_DLL_FrameUpdate(void *user_data)
|
||||
// NOTE: UI ====================================================================================
|
||||
TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity());
|
||||
DQN_DEFER { TELY_Render_PopTransform(renderer); };
|
||||
{
|
||||
if (game->debug_ui) {
|
||||
// NOTE: Info bar ==========================================================================
|
||||
{
|
||||
TELY_RFuiResult info_bar = TELY_RFui_Row(rfui, DQN_STRING8("Info Bar"));
|
||||
|
61
feely_pona.h
61
feely_pona.h
@ -23,30 +23,60 @@ struct FP_Meters
|
||||
|
||||
struct FP_GlobalAnimations
|
||||
{
|
||||
Dqn_String8 airport_terry = DQN_STRING8("airport_terry");
|
||||
Dqn_String8 airport_terry_plane = DQN_STRING8("airport_terry_plane");
|
||||
|
||||
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;
|
||||
|
||||
|
@ -6,16 +6,21 @@
|
||||
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_PhoneMessageProjectile,
|
||||
FP_EntityType_Count,
|
||||
};
|
||||
|
||||
@ -24,6 +29,7 @@ enum FP_EntityTerryState
|
||||
FP_EntityTerryState_Nil,
|
||||
FP_EntityTerryState_Idle,
|
||||
FP_EntityTerryState_Attack,
|
||||
FP_EntityTerryState_RangeAttack,
|
||||
FP_EntityTerryState_Run,
|
||||
FP_EntityTerryState_Dash,
|
||||
};
|
||||
@ -38,6 +44,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 +93,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,
|
||||
|
@ -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_RangeAttack: {
|
||||
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; result.flip = TELY_AssetFlip_X; break;
|
||||
case FP_GameDirection_Right: result.anim_name = g_anim_names.terry_attack_phone_side; 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,68 @@ 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; break;
|
||||
case FP_EntityAirportTerryState_FlyPassenger: result.anim_name = g_anim_names.airport_terry; 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 = 3.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_PhoneMessageProjectile: {
|
||||
result.height.meters = 1.f;
|
||||
result.anim_name = g_anim_names.terry_attack_phone_message;
|
||||
} break;
|
||||
|
||||
case FP_EntityType_Count: DQN_INVALID_CODE_PATH; break;
|
||||
}
|
||||
|
||||
@ -198,16 +270,10 @@ static FP_GameEntityHandle FP_Entity_CreateWaypointF(FP_Game *game, Dqn_V2 pos,
|
||||
entity->local_hit_box_size = Dqn_V2_InitNx1(32);
|
||||
FP_Entity_AddDebugEditorFlags(game, entity->handle);
|
||||
entity->flags |= FP_GameEntityFlag_MobSpawnerWaypoint;
|
||||
|
||||
FP_GameShape *shape = Dqn_FArray_Make(&entity->shapes, Dqn_ZeroMem_Yes);
|
||||
shape->type = FP_GameShapeType_Circle;
|
||||
shape->circle_radius = 16.f;
|
||||
shape->render_mode = TELY_RenderShapeMode_Line;
|
||||
shape->colour = TELY_COLOUR_BLUE_CADET_V4;
|
||||
return result;
|
||||
}
|
||||
|
||||
static FP_GameEntityHandle FP_Entity_CreateClinger(FP_Game *game, Dqn_V2 pos, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
||||
static FP_GameEntityHandle FP_Entity_CreateClinger(FP_Game *game, Dqn_V2 pos, uint64_t hp_adjustment, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
@ -216,7 +282,7 @@ static FP_GameEntityHandle FP_Entity_CreateClinger(FP_Game *game, Dqn_V2 pos, DQ
|
||||
va_end(args);
|
||||
|
||||
entity->type = FP_EntityType_Clinger;
|
||||
entity->hp = 1;
|
||||
entity->hp = 1 + hp_adjustment;
|
||||
entity->is_dying = false;
|
||||
entity->base_acceleration_per_s.meters = 8.f;
|
||||
entity->local_pos = pos;
|
||||
@ -230,7 +296,7 @@ static FP_GameEntityHandle FP_Entity_CreateClinger(FP_Game *game, Dqn_V2 pos, DQ
|
||||
return result;
|
||||
}
|
||||
|
||||
static FP_GameEntityHandle FP_Entity_CreateSmoochie(FP_Game *game, Dqn_V2 pos, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
||||
static FP_GameEntityHandle FP_Entity_CreateSmoochie(FP_Game *game, Dqn_V2 pos, uint64_t hp_adjustment, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
@ -240,6 +306,50 @@ static FP_GameEntityHandle FP_Entity_CreateSmoochie(FP_Game *game, Dqn_V2 pos, D
|
||||
|
||||
entity->type = FP_EntityType_Smoochie;
|
||||
entity->base_acceleration_per_s.meters = 8.f;
|
||||
entity->hp = 1 + hp_adjustment;
|
||||
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_CreateCatfish(FP_Game *game, Dqn_V2 pos, uint64_t hp_adjustment, 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 + hp_adjustment;
|
||||
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_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;
|
||||
@ -281,26 +391,6 @@ static FP_GameEntityHandle FP_Entity_CreatePermittedBuildZone(FP_Game *game, Dqn
|
||||
entity->type = FP_EntityType_Nil;
|
||||
entity->flags |= FP_GameEntityFlag_BuildZone;
|
||||
FP_Entity_AddDebugEditorFlags(game, entity->handle);
|
||||
|
||||
FP_GameShape *wall = Dqn_FArray_Make(&entity->shapes, Dqn_ZeroMem_Yes);
|
||||
wall->type = FP_GameShapeType_Rect;
|
||||
wall->p2 = entity->local_hit_box_size;
|
||||
wall->colour = TELY_COLOUR_BLACK_V4;
|
||||
|
||||
Dqn_Rect local_hit_box = Dqn_Rect_InitV2x2(Dqn_V2_Zero, entity->local_hit_box_size);
|
||||
FP_GameShape *line_1 = Dqn_FArray_Make(&entity->shapes, Dqn_ZeroMem_Yes);
|
||||
line_1->type = FP_GameShapeType_Line;
|
||||
line_1->p1 = Dqn_Rect_InterpolatedPoint(local_hit_box, Dqn_V2_InitNx2(0.f, 0.f)) - size * .5f;
|
||||
line_1->p2 = Dqn_Rect_InterpolatedPoint(local_hit_box, Dqn_V2_InitNx2(1.f, 1.f)) - size * .5f;
|
||||
line_1->line_thickness = 1.f;
|
||||
line_1->colour = TELY_COLOUR_BLACK_V4;
|
||||
|
||||
FP_GameShape *line_2 = Dqn_FArray_Make(&entity->shapes, Dqn_ZeroMem_Yes);
|
||||
line_2->type = FP_GameShapeType_Line;
|
||||
line_2->p1 = Dqn_Rect_InterpolatedPoint(local_hit_box, Dqn_V2_InitNx2(0.f, 1.f)) - size * .5f;
|
||||
line_2->p2 = Dqn_Rect_InterpolatedPoint(local_hit_box, Dqn_V2_InitNx2(1.f, 0.f)) - size * .5f;
|
||||
line_2->line_thickness = 1.f;
|
||||
line_2->colour = TELY_COLOUR_BLACK_V4;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -324,13 +414,6 @@ static FP_GameEntityHandle FP_Entity_CreateMobSpawner(FP_Game *game, Dqn_V2 pos,
|
||||
entity->enemies_per_wave = 5;
|
||||
entity->enemies_spawned_this_wave = 0;
|
||||
entity->wave_cooldown_timestamp_s = 0;
|
||||
|
||||
FP_GameShape *shape = Dqn_FArray_Make(&entity->shapes, Dqn_ZeroMem_Yes);
|
||||
shape->type = FP_GameShapeType_Rect;
|
||||
shape->p1 = {};
|
||||
shape->p2 = entity->local_hit_box_size;
|
||||
shape->render_mode = TELY_RenderShapeMode_Line;
|
||||
shape->colour = TELY_COLOUR_BLUE_CADET_V4;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -499,3 +582,104 @@ 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;
|
||||
}
|
||||
|
||||
static FP_GameEntityHandle FP_Entity_CreatePhoneMessageProjectile(FP_Game *game, Dqn_V2 pos, Dqn_V2 velocity, 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_PhoneMessageProjectile;
|
||||
FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, entity->type, 0, FP_GameDirection_Down);
|
||||
|
||||
entity->constant_acceleration_per_s = velocity;
|
||||
entity->local_pos = pos;
|
||||
entity->sprite_height = render_data.height;
|
||||
FP_Entity_AddDebugEditorFlags(game, result);
|
||||
entity->flags |= FP_GameEntityFlag_TTL;
|
||||
|
||||
entity->local_hit_box_offset = Dqn_V2_InitNx2(0, render_data.render_size.h * .1f);
|
||||
entity->local_hit_box_size = Dqn_V2_InitNx2(render_data.render_size.w, render_data.render_size.h - (render_data.render_size.h * .4f));
|
||||
entity->attack_box_offset = entity->local_hit_box_offset;
|
||||
entity->attack_box_size = entity->local_hit_box_size;
|
||||
entity->ttl_end_timestamp = game->clock_ms + 1000;
|
||||
|
||||
uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER;
|
||||
FP_Game_EntityActionReset(game, result, duration_ms, render_data.sprite);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -388,7 +388,7 @@ static Dqn_Rect FP_Game_CalcEntityWorldHitBox(FP_Game const *game, FP_GameEntity
|
||||
|
||||
static Dqn_Rect FP_Game_CalcEntityAttackWorldHitBox(FP_Game const *game, FP_GameEntityHandle handle)
|
||||
{
|
||||
FP_GameEntity *entity = FP_Game_GetEntity(DQN_CAST(FP_Game *) game, handle);
|
||||
FP_GameEntity *entity = FP_Game_GetEntity(DQN_CAST(FP_Game *) game, handle);
|
||||
Dqn_V2 world_pos = FP_Game_CalcEntityWorldPos(game, handle);
|
||||
Dqn_V2 half_hit_box_size = entity->attack_box_size * .5f;
|
||||
Dqn_Rect result = Dqn_Rect_InitV2x2(world_pos + entity->attack_box_offset - half_hit_box_size, entity->attack_box_size);
|
||||
@ -767,3 +767,35 @@ static void FP_Game_EntityTransitionState(FP_Game *game, FP_GameEntity *entity,
|
||||
// NOTE: If no returns are hit above we proceed with the state change
|
||||
entity->action.next_state = desired_state;
|
||||
}
|
||||
|
||||
static void FP_GameRenderScanlines(TELY_Renderer *renderer, Dqn_f32 scanline_gap, Dqn_f32 scanline_thickness,
|
||||
Dqn_V2 screen_size, Dqn_V2 camera_offset)
|
||||
{
|
||||
Dqn_f32 scanline_interval = scanline_gap + scanline_thickness;
|
||||
Dqn_f32 y_offset = fmodf(camera_offset.y, scanline_interval);
|
||||
|
||||
for (Dqn_f32 y = -y_offset; y < screen_size.h; y += scanline_interval)
|
||||
{
|
||||
Dqn_V2 start = Dqn_V2_InitNx2(0, y);
|
||||
Dqn_V2 end = Dqn_V2_InitNx2(screen_size.w, y);
|
||||
TELY_Render_LineColourV4(renderer, start, end, TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, 0.1f), scanline_thickness);
|
||||
}
|
||||
}
|
||||
|
||||
static void FP_GameRenderCameraFollowScanlines(TELY_Renderer *renderer,
|
||||
Dqn_V2 screen_size,
|
||||
Dqn_V2 camera_offset,
|
||||
Dqn_f32 scanline_gap,
|
||||
Dqn_f32 scanline_thickness)
|
||||
{
|
||||
Dqn_f32 y_offset = camera_offset.y;
|
||||
|
||||
// Adjust starting y to be more negative
|
||||
Dqn_f32 starting_y = -screen_size.h - 150 - y_offset;
|
||||
|
||||
for (Dqn_f32 y = starting_y; y < screen_size.h; y += scanline_gap + scanline_thickness) {
|
||||
Dqn_V2 start = Dqn_V2_InitNx2(camera_offset.x, y + camera_offset.y);
|
||||
Dqn_V2 end = Dqn_V2_InitNx2(screen_size.w + camera_offset.x, y + camera_offset.y);
|
||||
TELY_Render_LineColourV4(renderer, start, end, TELY_Colour_V4Alpha(TELY_COLOUR_BLACK_V4, 0.1f), scanline_thickness);
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ enum FP_GameEntityFlag
|
||||
FP_GameEntityFlag_PointOfInterestHeart = 1 << 11,
|
||||
FP_GameEntityFlag_CameraTracking = 1 << 14,
|
||||
FP_GameEntityFlag_BuildZone = 1 << 15,
|
||||
FP_GameEntityFlag_TTL = 1 << 16,
|
||||
};
|
||||
|
||||
enum FP_GameShapeType
|
||||
@ -150,6 +151,7 @@ struct FP_GameEntity
|
||||
FP_Meters sprite_height;
|
||||
FP_GameEntityAction action;
|
||||
FP_Meters base_acceleration_per_s;
|
||||
Dqn_V2 constant_acceleration_per_s;
|
||||
Dqn_V2 velocity;
|
||||
|
||||
// Extra animations that are to be executed, but, don't affect the state
|
||||
@ -189,6 +191,8 @@ struct FP_GameEntity
|
||||
Dqn_V2 local_pos;
|
||||
Dqn_f64 alive_time_s;
|
||||
Dqn_FArray<FP_GameShape, 4> shapes;
|
||||
Dqn_FArray<FP_GameEntityHandle, 4> projectiles;
|
||||
uint64_t ttl_end_timestamp;
|
||||
};
|
||||
|
||||
struct FP_GameEntityIterator
|
||||
@ -256,7 +260,10 @@ struct FP_Game
|
||||
uint64_t clock_ms;
|
||||
Dqn_PCG32 rng;
|
||||
|
||||
bool build_mode;
|
||||
bool build_mode;
|
||||
bool build_mode_can_place_building;
|
||||
bool debug_ui;
|
||||
Dqn_usize build_mode_building_index;
|
||||
};
|
||||
|
||||
struct FP_GameAStarNode
|
||||
@ -275,3 +282,15 @@ struct FP_GameFindClosestEntityResult
|
||||
Dqn_V2 pos;
|
||||
};
|
||||
|
||||
struct FP_GamePlaceableBuilding
|
||||
{
|
||||
FP_EntityType type;
|
||||
uint32_t state;
|
||||
};
|
||||
|
||||
FP_GamePlaceableBuilding const PLACEABLE_BUILDINGS[] = {
|
||||
{FP_EntityType_AirportTerry, FP_EntityAirportTerryState_Idle},
|
||||
{FP_EntityType_ChurchTerry, FP_EntityChurchTerryState_Idle},
|
||||
{FP_EntityType_ClubTerry, FP_EntityClubTerryState_Idle},
|
||||
{FP_EntityType_KennelTerry, FP_EntityKennelTerryState_Idle},
|
||||
};
|
||||
|
BIN
project.rdbg
BIN
project.rdbg
Binary file not shown.
Loading…
Reference in New Issue
Block a user