Compare commits

..

1 Commits

16 changed files with 141 additions and 357 deletions

BIN
Data/Textures/atlas.txt (Stored with Git LFS)

Binary file not shown.

BIN
Data/Textures/atlas/church_terry_dark.png (Stored with Git LFS)

Binary file not shown.

BIN
Data/Textures/atlas/kennel_terry_2.png (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Data/Textures/sprite_spec.txt (Stored with Git LFS)

Binary file not shown.

2
External/tely vendored

@ -1 +1 @@
Subproject commit 8576ce00dc74f817b346994efca8610001a8eafb Subproject commit 4ccbde6fecb8ea17f9cde73df7c06da466311f3c

View File

@ -5,40 +5,39 @@
Dqn_f32 const PHYSICS_STEP = 1 / 60.f; 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 = {}; Dqn_Rect result = {};
FP_GameEntity *entity = FP_Game_GetEntity(game, handle); FP_GameEntity *entity = FP_Game_GetEntity(game, handle);
if (FP_Game_IsNilEntity(entity)) if (FP_Game_IsNilEntity(entity))
return result; return result;
FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, placeable_building.type, placeable_building.state, entity->direction); FP_EntityRenderData club_terry_render_data = FP_Entity_GetRenderData(game, FP_EntityType_ClubTerry, FP_EntityClubTerryState_Idle, entity->direction);
Dqn_Rect box = FP_Game_CalcEntityWorldHitBox(game, entity->handle); Dqn_Rect box = FP_Game_CalcEntityWorldHitBox(game, entity->handle);
Dqn_V2 build_p = {}; Dqn_V2 build_p = {};
switch (entity->direction) { switch (entity->direction) {
case FP_GameDirection_Up: { case FP_GameDirection_Up: {
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); 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);
} break; } break;
case FP_GameDirection_Down: { case FP_GameDirection_Down: {
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); 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);
} break; } break;
case FP_GameDirection_Left: { case FP_GameDirection_Left: {
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); 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);
} break; } break;
case FP_GameDirection_Right: { case FP_GameDirection_Right: {
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); 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);
} break; } break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break; case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
} }
result.size = render_data.render_size; result.size = club_terry_render_data.render_size;
result.pos = build_p - (render_data.render_size * .5f); result.pos = build_p - (club_terry_render_data.render_size * .5f);
return result; return result;
} }
@ -208,7 +207,6 @@ static void FP_Game_MoveEntity(FP_Game *game, FP_GameEntityHandle entity_handle,
case FP_EntityType_AirportTerry: break; case FP_EntityType_AirportTerry: break;
case FP_EntityType_ChurchTerry: break; case FP_EntityType_ChurchTerry: break;
case FP_EntityType_KennelTerry: break; case FP_EntityType_KennelTerry: break;
case FP_EntityType_PhoneMessageProjectile: break;
} }
if (!entity_collides_with_collider) if (!entity_collides_with_collider)
@ -216,9 +214,6 @@ static void FP_Game_MoveEntity(FP_Game *game, FP_GameEntityHandle entity_handle,
// NOTE: Sweep collider with half the radius of the source entity // NOTE: Sweep collider with half the radius of the source entity
Dqn_Rect collider_world_hit_box = FP_Game_CalcEntityWorldHitBox(game, collider->handle); 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; 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.pos -= (entity_world_hit_box.size * .5f);
swept_collider_world_hit_box.size += entity_world_hit_box.size; swept_collider_world_hit_box.size += entity_world_hit_box.size;
@ -529,9 +524,6 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) || if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) { TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Attack); 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) { } else if (acceleration_meters_per_s->x || acceleration_meters_per_s->y) {
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Run); FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Run);
} }
@ -549,7 +541,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
} }
} break; } break;
case FP_EntityTerryState_RangeAttack: { case FP_EntityTerryState_AttackPhone: {
if (entering_new_state) { if (entering_new_state) {
uint64_t duration_ms = render_data.sprite.anim->count * render_data.sprite.anim->ms_per_frame; 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); FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite);
@ -570,9 +562,6 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) || if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) { TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_X)) {
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Attack); 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) || } else if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_LeftControl) ||
TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_A)) { TELY_Platform_InputGamepadButtonCodeIsPressed(input, 0, TELY_PlatformInputGamepadButtonCode_A)) {
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Dash); FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Dash);
@ -596,7 +585,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
} break; } break;
} }
if (*state == FP_EntityTerryState_Attack || *state == FP_EntityTerryState_RangeAttack) { if (*state == FP_EntityTerryState_Attack || *state == FP_EntityTerryState_AttackPhone) {
DQN_ASSERT(action->sprite.anim); DQN_ASSERT(action->sprite.anim);
uint64_t duration_ms = action->sprite.anim->count * action->sprite.anim->ms_per_frame; uint64_t duration_ms = action->sprite.anim->count * action->sprite.anim->ms_per_frame;
@ -605,46 +594,33 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
// NOTE: Adding an attack_processed bool to make sure things only fire once // NOTE: Adding an attack_processed bool to make sure things only fire once
if (!entity->attack_processed && game->clock_ms >= midpoint_clock_ms) { 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 // NOTE: Position the attack box
Dqn_V2 dir_vector = {};
switch (entity->direction) { switch (entity->direction) {
case FP_GameDirection_Left: { 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->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x - entity->attack_box_size.w,
entity->local_hit_box_offset.y); entity->local_hit_box_offset.y);
} break; } break;
case FP_GameDirection_Right: { 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->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x + entity->attack_box_size.w,
entity->local_hit_box_offset.y); entity->local_hit_box_offset.y);
} break; } break;
case FP_GameDirection_Up: { case FP_GameDirection_Up: {
dir_vector.y = -1.f;
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x, entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x,
entity->local_hit_box_offset.y - entity->attack_box_size.h); entity->local_hit_box_offset.y - entity->attack_box_size.h);
} break; } break;
case FP_GameDirection_Down: { case FP_GameDirection_Down: {
dir_vector.y = +1.f;
entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x, entity->attack_box_offset = Dqn_V2_InitNx2(entity->local_hit_box_offset.x,
entity->local_hit_box_offset.y + entity->attack_box_size.h); entity->local_hit_box_offset.y + entity->attack_box_size.h);
} break; } break;
case FP_GameDirection_Count: 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; entity->attack_processed = true;
} else { } else {
entity->attack_box_size = {}; entity->attack_box_size = {};
@ -747,7 +723,6 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
if (entering_new_state) { if (entering_new_state) {
uint64_t duration_ms = render_data.sprite.anim->count * render_data.sprite.anim->ms_per_frame; 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); FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite);
entity->local_hit_box_size = {};
} }
if (action_has_finished) if (action_has_finished)
@ -852,7 +827,6 @@ 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); 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; uint64_t duration_ms = sprite.anim->count * sprite.anim->ms_per_frame;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
entity->local_hit_box_size = {};
} }
if (action_has_finished) if (action_has_finished)
@ -1108,7 +1082,6 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
if (entering_new_state) { if (entering_new_state) {
uint64_t duration_ms = render_data.sprite.anim->count * render_data.sprite.anim->ms_per_frame; 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); FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite);
entity->local_hit_box_size = {};
} }
if (action_has_finished) if (action_has_finished)
@ -1249,36 +1222,14 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
if (game->clicked_entity.id) { if (game->clicked_entity.id) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_Delete)) if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_Delete))
FP_Game_DeleteEntity(game, game->clicked_entity); 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 { } else {
Dqn_f32 pan_speed = 5.f; Dqn_f32 pan_speed = 5.f;
if (TELY_Platform_InputScanCodeIsDown(input, TELY_PlatformInputScanCode_Space)) if (TELY_Platform_InputScanCodeIsDown(input, TELY_PlatformInputScanCode_Space))
pan_speed *= 2.5f; pan_speed *= 2.5f;
game->camera.world_pos += dir_vector * pan_speed; 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); Dqn_ProfilerZone update_zone = Dqn_Profiler_BeginZoneWithIndex(DQN_STRING8("FP_Update: Entity loop"), FP_ProfileZone_FPUpdate_EntityLoop);
// NOTE: Handle input ========================================================================== // NOTE: Handle input ==========================================================================
@ -1290,7 +1241,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
continue; continue;
// NOTE: Move entity by keyboard and gamepad =============================================== // NOTE: Move entity by keyboard and gamepad ===============================================
Dqn_V2 acceleration_meters_per_s = entity->constant_acceleration_per_s; Dqn_V2 acceleration_meters_per_s = {};
if (game->clicked_entity == entity->handle) { if (game->clicked_entity == entity->handle) {
if (entity->flags & (FP_GameEntityFlag_MoveByKeyboard | FP_GameEntityFlag_MoveByGamepad)) { if (entity->flags & (FP_GameEntityFlag_MoveByKeyboard | FP_GameEntityFlag_MoveByGamepad)) {
bool move_entity = true; bool move_entity = true;
@ -1319,11 +1270,6 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
case FP_EntityType_MerchantPhoneCompany: break; case FP_EntityType_MerchantPhoneCompany: break;
case FP_EntityType_Heart: break; case FP_EntityType_Heart: break;
case FP_EntityType_MerchantGym: 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) { if (move_entity) {
@ -1594,59 +1540,45 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
} }
if (game->clicked_entity == entity->handle) { if (game->clicked_entity == entity->handle) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_H)) if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F))
game->build_mode = !game->build_mode; 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) 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->camera.world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle) - Dqn_V2_InitV2I(platform->core.window_size) * .5f;
game->build_mode_can_place_building = false; game->build_mode_can_place_building = false;
if (game->build_mode) { if (game->build_mode) {
FP_GamePlaceableBuilding placeable_building = PLACEABLE_BUILDINGS[game->build_mode_building_index]; Dqn_Rect dest_rect = FP_Game_GetBuildingPlacementRectForEntity(game, entity->handle);
Dqn_Rect dest_rect = FP_Game_GetBuildingPlacementRectForEntity(game, placeable_building, entity->handle);
Dqn_V2 placement_pos = Dqn_Rect_Center(dest_rect); Dqn_V2 placement_pos = Dqn_Rect_Center(dest_rect);
for (FP_GameEntityIterator zone_it = {}; for (FP_GameEntityIterator zone_it = {};
FP_Game_DFSPreOrderWalkEntityTree(game, &zone_it, game->root_entity); !game->build_mode_can_place_building && FP_Game_DFSPostOrderWalkEntityTree(game, &zone_it, game->root_entity);
) { ) {
FP_GameEntity *zone = zone_it.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) if ((zone->flags & FP_GameEntityFlag_BuildZone) == 0)
continue; continue;
Dqn_Rect zone_hit_box = FP_Game_CalcEntityWorldHitBox(game, zone->handle);
zone_hit_box.pos += dest_rect.size * .5f; zone_hit_box.pos += dest_rect.size * .5f;
zone_hit_box.size -= dest_rect.size; zone_hit_box.size -= dest_rect.size;
zone_hit_box.size = Dqn_V2_Max(zone_hit_box.size, Dqn_V2_Zero); 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); game->build_mode_can_place_building = Dqn_Rect_ContainsPoint(zone_hit_box, placement_pos);
} }
if (game->build_mode_can_place_building && if (game->build_mode_can_place_building &&
TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F)) { TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_E)) {
if (placeable_building.type == FP_EntityType_ClubTerry) {
FP_Entity_CreateClubTerry(game, placement_pos, "Club Terry"); 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");
}
} }
} }
} }
@ -1664,13 +1596,6 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) { for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->root_entity); ) {
FP_GameEntity *entity = it.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 ==================================================== // NOTE: Derive dynmamic bounding boxes ====================================================
if (entity->flags & FP_GameEntityFlag_DeriveHitBoxFromChildrenBoundingBox) { if (entity->flags & FP_GameEntityFlag_DeriveHitBoxFromChildrenBoundingBox) {
Dqn_Rect children_bbox = {}; Dqn_Rect children_bbox = {};
@ -1804,7 +1729,6 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
case FP_EntityType_AirportTerry: case FP_EntityType_AirportTerry:
case FP_EntityType_ChurchTerry: case FP_EntityType_ChurchTerry:
case FP_EntityType_KennelTerry: break; case FP_EntityType_KennelTerry: break;
case FP_EntityType_PhoneMessageProjectile: break;
} }
if (!permit_attack) if (!permit_attack)
@ -1820,7 +1744,6 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
defender->is_dying = true; defender->is_dying = true;
// NOTE: Kickback ====================================================================== // NOTE: Kickback ======================================================================
#if 0
Dqn_V2 defender_world_pos = Dqn_Rect_Center(defender_box); Dqn_V2 defender_world_pos = Dqn_Rect_Center(defender_box);
Dqn_V2 attack_dir_vector = {}; Dqn_V2 attack_dir_vector = {};
if (attacker_world_pos.x < defender_world_pos.x) if (attacker_world_pos.x < defender_world_pos.x)
@ -1830,7 +1753,6 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
Dqn_V2 attack_acceleration_meters_per_s = attack_dir_vector * 60.f; Dqn_V2 attack_acceleration_meters_per_s = attack_dir_vector * 60.f;
FP_Game_MoveEntity(game, defender->handle, attack_acceleration_meters_per_s); FP_Game_MoveEntity(game, defender->handle, attack_acceleration_meters_per_s);
#endif
} }
} }
} }
@ -2023,13 +1945,7 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer)
} }
} }
if (game->build_mode) { // NOTE: Render waypoint entities ==========================================================
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));
}
if (game->debug_ui) {
// NOTE: Render waypoint entities ======================================================
if (entity->flags & FP_GameEntityFlag_MobSpawner) { if (entity->flags & FP_GameEntityFlag_MobSpawner) {
Dqn_V2 start = world_pos; Dqn_V2 start = world_pos;
for (FP_GameEntity *waypoint_entity = entity->first_child; waypoint_entity; waypoint_entity = waypoint_entity->next) { for (FP_GameEntity *waypoint_entity = entity->first_child; waypoint_entity; waypoint_entity = waypoint_entity->next) {
@ -2042,25 +1958,6 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer)
} }
} }
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 ================================================================= // NOTE: Render attack box =================================================================
{ {
Dqn_Rect attack_box = FP_Game_CalcEntityAttackWorldHitBox(game, entity->handle); Dqn_Rect attack_box = FP_Game_CalcEntityAttackWorldHitBox(game, entity->handle);
@ -2070,6 +1967,31 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer)
// NOTE: Render world position ============================================================= // NOTE: Render world position =============================================================
TELY_Render_CircleColourV4(renderer, world_pos, 4.f, TELY_RenderShapeMode_Fill, TELY_COLOUR_RED_TOMATO_V4); TELY_Render_CircleColourV4(renderer, world_pos, 4.f, TELY_RenderShapeMode_Fill, TELY_COLOUR_RED_TOMATO_V4);
// NOTE: Render building blueprint =========================================================
if (game->clicked_entity == entity->handle && game->build_mode) {
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);
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,
club_terry_render_data.sheet->tex_handle,
club_terry_render_data.sheet_rect,
dest_rect,
Dqn_V2_Zero /*rotate origin*/,
0.f /*rotation*/,
colour);
}
// NOTE: Render hot/active entity ========================================================== // NOTE: Render hot/active entity ==========================================================
if (game->clicked_entity == entity->handle) { if (game->clicked_entity == entity->handle) {
TELY_Render_RectColourV4(renderer, world_hit_box, TELY_RenderShapeMode_Line, TELY_COLOUR_WHITE_PALE_GOLDENROD_V4); TELY_Render_RectColourV4(renderer, world_hit_box, TELY_RenderShapeMode_Line, TELY_COLOUR_WHITE_PALE_GOLDENROD_V4);
@ -2100,79 +2022,6 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer)
} }
} }
}
if (!FP_Game_IsNilEntityHandle(game, game->clicked_entity)) {
// NOTE: Render building blueprint =========================================================
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_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,
club_terry_render_data.sheet->tex_handle,
club_terry_render_data.sheet_rect,
dest_rect,
Dqn_V2_Zero /*rotate origin*/,
0.f /*rotation*/,
colour);
}
// NOTE: Render the building selector UI ===================================================
{
TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity());
DQN_DEFER { TELY_Render_PopTransform(renderer); };
game->build_mode_building_index = DQN_CLAMP(game->build_mode_building_index, 0, DQN_ARRAY_UCOUNT(PLACEABLE_BUILDINGS) - 1);
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 // 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_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_gap = 4.0f;
@ -2258,7 +2107,7 @@ void TELY_DLL_FrameUpdate(void *user_data)
// NOTE: UI ==================================================================================== // NOTE: UI ====================================================================================
TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity()); TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity());
DQN_DEFER { TELY_Render_PopTransform(renderer); }; DQN_DEFER { TELY_Render_PopTransform(renderer); };
if (game->debug_ui) { {
// NOTE: Info bar ========================================================================== // NOTE: Info bar ==========================================================================
{ {
TELY_RFuiResult info_bar = TELY_RFui_Row(rfui, DQN_STRING8("Info Bar")); TELY_RFuiResult info_bar = TELY_RFui_Row(rfui, DQN_STRING8("Info Bar"));

View File

@ -23,8 +23,8 @@ struct FP_Meters
struct FP_GlobalAnimations struct FP_GlobalAnimations
{ {
Dqn_String8 airport_terry = DQN_STRING8("airport_terry"); Dqn_String8 airport_terry_alive = DQN_STRING8("airport_terry_alive");
Dqn_String8 airport_terry_plane = DQN_STRING8("airport_terry_plane"); Dqn_String8 airport_terry_dark = DQN_STRING8("airport_terry_dark");
Dqn_String8 catfish_attack_down = DQN_STRING8("catfish_attack_down"); Dqn_String8 catfish_attack_down = DQN_STRING8("catfish_attack_down");
Dqn_String8 catfish_attack_side = DQN_STRING8("catfish_attack_side"); Dqn_String8 catfish_attack_side = DQN_STRING8("catfish_attack_side");

View File

@ -20,7 +20,6 @@ enum FP_EntityType
FP_EntityType_MerchantTerry, FP_EntityType_MerchantTerry,
FP_EntityType_Smoochie, FP_EntityType_Smoochie,
FP_EntityType_Terry, FP_EntityType_Terry,
FP_EntityType_PhoneMessageProjectile,
FP_EntityType_Count, FP_EntityType_Count,
}; };
@ -29,7 +28,7 @@ enum FP_EntityTerryState
FP_EntityTerryState_Nil, FP_EntityTerryState_Nil,
FP_EntityTerryState_Idle, FP_EntityTerryState_Idle,
FP_EntityTerryState_Attack, FP_EntityTerryState_Attack,
FP_EntityTerryState_RangeAttack, FP_EntityTerryState_AttackPhone,
FP_EntityTerryState_Run, FP_EntityTerryState_Run,
FP_EntityTerryState_Dash, FP_EntityTerryState_Dash,
}; };

View File

@ -39,12 +39,12 @@ FP_EntityRenderData FP_Entity_GetRenderData(FP_Game *game, FP_EntityType type, u
} }
} break; } break;
case FP_EntityTerryState_RangeAttack: { case FP_EntityTerryState_AttackPhone: {
switch (direction) { switch (direction) {
case FP_GameDirection_Up: result.anim_name = g_anim_names.terry_attack_phone_up; break; 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_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_Left: result.anim_name = g_anim_names.terry_attack_phone_side; break;
case FP_GameDirection_Right: result.anim_name = g_anim_names.terry_attack_phone_side; break; case FP_GameDirection_Right: result.anim_name = g_anim_names.terry_attack_phone_side; result.flip = TELY_AssetFlip_X; break;
case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break; case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break;
} }
} break; } break;
@ -175,8 +175,8 @@ FP_EntityRenderData FP_Entity_GetRenderData(FP_Game *game, FP_EntityType type, u
FP_EntityAirportTerryState state = DQN_CAST(FP_EntityAirportTerryState)raw_state; FP_EntityAirportTerryState state = DQN_CAST(FP_EntityAirportTerryState)raw_state;
switch (state) { switch (state) {
case FP_EntityAirportTerryState_Nil: break; case FP_EntityAirportTerryState_Nil: break;
case FP_EntityAirportTerryState_Idle: result.anim_name = g_anim_names.airport_terry; break; case FP_EntityAirportTerryState_Idle: result.anim_name = g_anim_names.airport_terry_dark; break;
case FP_EntityAirportTerryState_FlyPassenger: result.anim_name = g_anim_names.airport_terry; break; case FP_EntityAirportTerryState_FlyPassenger: result.anim_name = g_anim_names.airport_terry_alive; break;
} }
} break; } break;
@ -219,7 +219,7 @@ FP_EntityRenderData FP_Entity_GetRenderData(FP_Game *game, FP_EntityType type, u
} break; } break;
case FP_EntityType_KennelTerry: { case FP_EntityType_KennelTerry: {
result.height.meters = 3.f; result.height.meters = 4.f;
FP_EntityKennelTerryState state = DQN_CAST(FP_EntityKennelTerryState)raw_state; FP_EntityKennelTerryState state = DQN_CAST(FP_EntityKennelTerryState)raw_state;
switch (state) { switch (state) {
case FP_EntityKennelTerryState_Nil: break; case FP_EntityKennelTerryState_Nil: break;
@ -227,11 +227,6 @@ FP_EntityRenderData FP_Entity_GetRenderData(FP_Game *game, FP_EntityType type, u
} }
} 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; case FP_EntityType_Count: DQN_INVALID_CODE_PATH; break;
} }
@ -270,6 +265,12 @@ static FP_GameEntityHandle FP_Entity_CreateWaypointF(FP_Game *game, Dqn_V2 pos,
entity->local_hit_box_size = Dqn_V2_InitNx1(32); entity->local_hit_box_size = Dqn_V2_InitNx1(32);
FP_Entity_AddDebugEditorFlags(game, entity->handle); FP_Entity_AddDebugEditorFlags(game, entity->handle);
entity->flags |= FP_GameEntityFlag_MobSpawnerWaypoint; 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; return result;
} }
@ -340,28 +341,6 @@ static FP_GameEntityHandle FP_Entity_CreateCatfish(FP_Game *game, Dqn_V2 pos, ui
return result; return result;
} }
static FP_GameEntityHandle FP_Entity_CreateCatfish(FP_Game *game, Dqn_V2 pos, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
FP_GameEntity *entity = FP_Game_MakeEntityPointerFV(game, fmt, args);
FP_GameEntityHandle result = entity->handle;
va_end(args);
entity->type = FP_EntityType_Catfish;
entity->base_acceleration_per_s.meters = 8.f;
entity->hp = 1;
entity->is_dying = false;
entity->local_pos = pos;
entity->sprite_height = FP_Entity_GetRenderData(game, entity->type, 0 /*state*/, FP_GameDirection_Down).height;
entity->attack_cooldown_ms = 1000;
entity->local_hit_box_size = FP_Game_MetersToPixelsNx2(game, 0.4f, entity->sprite_height.meters * .6f);
FP_Entity_AddDebugEditorFlags(game, entity->handle);
entity->flags |= FP_GameEntityFlag_NonTraversable;
entity->flags |= FP_GameEntityFlag_Attackable;
return result;
}
static FP_GameEntityHandle FP_Entity_CreateWallAtPos(FP_Game *game, Dqn_String8 name, Dqn_V2 pos, Dqn_V2 size) static FP_GameEntityHandle FP_Entity_CreateWallAtPos(FP_Game *game, Dqn_String8 name, Dqn_V2 pos, Dqn_V2 size)
{ {
FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, name.data); FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, name.data);
@ -391,6 +370,26 @@ static FP_GameEntityHandle FP_Entity_CreatePermittedBuildZone(FP_Game *game, Dqn
entity->type = FP_EntityType_Nil; entity->type = FP_EntityType_Nil;
entity->flags |= FP_GameEntityFlag_BuildZone; entity->flags |= FP_GameEntityFlag_BuildZone;
FP_Entity_AddDebugEditorFlags(game, entity->handle); 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; return result;
} }
@ -414,6 +413,13 @@ static FP_GameEntityHandle FP_Entity_CreateMobSpawner(FP_Game *game, Dqn_V2 pos,
entity->enemies_per_wave = 5; entity->enemies_per_wave = 5;
entity->enemies_spawned_this_wave = 0; entity->enemies_spawned_this_wave = 0;
entity->wave_cooldown_timestamp_s = 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; return result;
} }
@ -654,32 +660,3 @@ static FP_GameEntityHandle FP_Entity_CreateAirportTerry(FP_Game *game, Dqn_V2 po
entity->local_hit_box_size = Dqn_V2_InitNx2(sprite_rect_scaled.w, sprite_rect_scaled.h - (sprite_rect_scaled.h * .4f)); entity->local_hit_box_size = Dqn_V2_InitNx2(sprite_rect_scaled.w, sprite_rect_scaled.h - (sprite_rect_scaled.h * .4f));
return result; 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;
}

View File

@ -778,24 +778,22 @@ static void FP_GameRenderScanlines(TELY_Renderer *renderer, Dqn_f32 scanline_gap
{ {
Dqn_V2 start = Dqn_V2_InitNx2(0, y); Dqn_V2 start = Dqn_V2_InitNx2(0, y);
Dqn_V2 end = Dqn_V2_InitNx2(screen_size.w, 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); TELY_Render_LineColourV4(renderer, start, end, TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, 0.5f), scanline_thickness);
} }
} }
static void FP_GameRenderCameraFollowScanlines(TELY_Renderer *renderer, static void FP_GameRenderCameraFollowScanlines(TELY_Renderer *renderer, Dqn_V2 screen_size, Dqn_V2 camera_offset, Dqn_f32 scanline_gap, Dqn_f32 scanline_thickness)
Dqn_V2 screen_size,
Dqn_V2 camera_offset,
Dqn_f32 scanline_gap,
Dqn_f32 scanline_thickness)
{ {
Dqn_f32 y_offset = camera_offset.y; Dqn_f32 y_offset = camera_offset.y;
// Adjust starting y to be more negative // Adjust starting y to be more negative
Dqn_f32 starting_y = -screen_size.h - 150 - y_offset; 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) { 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 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); 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);
TELY_Render_LineColourV4(renderer, start, end, TELY_Colour_V4Alpha(TELY_COLOUR_BLACK_V4, 0.5f), scanline_thickness);
} }
} }

View File

@ -22,7 +22,6 @@ enum FP_GameEntityFlag
FP_GameEntityFlag_PointOfInterestHeart = 1 << 11, FP_GameEntityFlag_PointOfInterestHeart = 1 << 11,
FP_GameEntityFlag_CameraTracking = 1 << 14, FP_GameEntityFlag_CameraTracking = 1 << 14,
FP_GameEntityFlag_BuildZone = 1 << 15, FP_GameEntityFlag_BuildZone = 1 << 15,
FP_GameEntityFlag_TTL = 1 << 16,
}; };
enum FP_GameShapeType enum FP_GameShapeType
@ -151,7 +150,6 @@ struct FP_GameEntity
FP_Meters sprite_height; FP_Meters sprite_height;
FP_GameEntityAction action; FP_GameEntityAction action;
FP_Meters base_acceleration_per_s; FP_Meters base_acceleration_per_s;
Dqn_V2 constant_acceleration_per_s;
Dqn_V2 velocity; Dqn_V2 velocity;
// Extra animations that are to be executed, but, don't affect the state // Extra animations that are to be executed, but, don't affect the state
@ -191,8 +189,6 @@ struct FP_GameEntity
Dqn_V2 local_pos; Dqn_V2 local_pos;
Dqn_f64 alive_time_s; Dqn_f64 alive_time_s;
Dqn_FArray<FP_GameShape, 4> shapes; Dqn_FArray<FP_GameShape, 4> shapes;
Dqn_FArray<FP_GameEntityHandle, 4> projectiles;
uint64_t ttl_end_timestamp;
}; };
struct FP_GameEntityIterator struct FP_GameEntityIterator
@ -262,8 +258,6 @@ struct FP_Game
bool build_mode; bool build_mode;
bool build_mode_can_place_building; bool build_mode_can_place_building;
bool debug_ui;
Dqn_usize build_mode_building_index;
}; };
struct FP_GameAStarNode struct FP_GameAStarNode
@ -282,15 +276,3 @@ struct FP_GameFindClosestEntityResult
Dqn_V2 pos; 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},
};