Compare commits
8 Commits
7d0fde9a62
...
bfe2fef528
| Author | SHA1 | Date | |
|---|---|---|---|
| bfe2fef528 | |||
| 85603bda2a | |||
| 45d981099c | |||
| 4bcbc61721 | |||
| 5f8344ddda | |||
| aed29a9f50 | |||
| 0e22b49271 | |||
| 760da9d39f |
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Vendored
+1
-1
Submodule External/tely updated: 4ccbde6fec...8576ce00dc
+463
-91
@@ -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,6 +1543,7 @@ 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
|
||||
@@ -1322,6 +1551,8 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
||||
FP_Game_EntityTransitionState(game, entity, FP_EntityTerryState_Attack);
|
||||
} else if (entity->type == FP_EntityType_Smoochie) {
|
||||
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);
|
||||
@@ -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"));
|
||||
|
||||
+47
-14
@@ -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;
|
||||
|
||||
|
||||
+41
-6
@@ -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,
|
||||
|
||||
+221
-37
@@ -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;
|
||||
}
|
||||
|
||||
+33
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+20
-1
@@ -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},
|
||||
};
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user