fp: Add rudimentary build mode
This commit is contained in:
		
							parent
							
								
									20da505f2e
								
							
						
					
					
						commit
						3efa397d1d
					
				
							
								
								
									
										2
									
								
								External/tely
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								External/tely
									
									
									
									
										vendored
									
									
								
							| @ -1 +1 @@ | |||||||
| Subproject commit d58010b431d3ed7ee0076f3195f1d2a8ccc4a220 | Subproject commit 26f6dd7d348c5a732ddfb929bd2d9b01e644ac48 | ||||||
							
								
								
									
										223
									
								
								feely_pona.cpp
									
									
									
									
									
								
							
							
						
						
									
										223
									
								
								feely_pona.cpp
									
									
									
									
									
								
							| @ -5,6 +5,42 @@ | |||||||
| 
 | 
 | ||||||
| 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 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); | ||||||
|  | 
 | ||||||
|  |     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); | ||||||
|  |         } 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); | ||||||
|  |         } 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); | ||||||
|  |         } 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); | ||||||
|  |         } 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); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_Platform *platform, TELY_Assets *assets, Dqn_Arena *arena, Dqn_String8 sheet_name) | TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_Platform *platform, TELY_Assets *assets, Dqn_Arena *arena, Dqn_String8 sheet_name) | ||||||
| { | { | ||||||
|     TELY_AssetSpriteSheet result  = {}; |     TELY_AssetSpriteSheet result  = {}; | ||||||
| @ -230,6 +266,7 @@ void TELY_DLL_Reload(void *user_data) | |||||||
| { | { | ||||||
|     TELY_Platform *platform = DQN_CAST(TELY_Platform *)user_data; |     TELY_Platform *platform = DQN_CAST(TELY_Platform *)user_data; | ||||||
|     Dqn_Library_SetPointer(platform->core.dqn_lib); |     Dqn_Library_SetPointer(platform->core.dqn_lib); | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| extern "C" __declspec(dllexport) | extern "C" __declspec(dllexport) | ||||||
| @ -298,7 +335,7 @@ void TELY_DLL_Init(void *user_data) | |||||||
| 
 | 
 | ||||||
|         FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "Map"); |         FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "Map"); | ||||||
|         entity->type          = FP_EntityType_Map; |         entity->type          = FP_EntityType_Map; | ||||||
|         entity->sprite_height.meters = 41.9f; |         entity->sprite_height = FP_Entity_GetRenderData(game, entity->type, 0 /*state*/, FP_GameDirection_Down).height; | ||||||
|         entity->local_pos     = {}; |         entity->local_pos     = {}; | ||||||
| 
 | 
 | ||||||
|         Dqn_f32 size_scale           = FP_Entity_CalcSpriteScaleForDesiredHeight(game, entity->sprite_height, sprite_rect); |         Dqn_f32 size_scale           = FP_Entity_CalcSpriteScaleForDesiredHeight(game, entity->sprite_height, sprite_rect); | ||||||
| @ -368,7 +405,7 @@ void TELY_DLL_Init(void *user_data) | |||||||
|     // NOTE: Mid lane mob spawner ==================================================================
 |     // NOTE: Mid lane mob spawner ==================================================================
 | ||||||
|     Dqn_V2 base_mid_p               = Dqn_V2_InitNx2(1580, 0.f); |     Dqn_V2 base_mid_p               = Dqn_V2_InitNx2(1580, 0.f); | ||||||
|     Dqn_V2 mid_lane_mob_spawner_pos = Dqn_V2_InitNx2(game->map->local_hit_box_size.w * -0.5f, 0.f); |     Dqn_V2 mid_lane_mob_spawner_pos = Dqn_V2_InitNx2(game->map->local_hit_box_size.w * -0.5f, 0.f); | ||||||
|     Dqn_usize spawn_cap             = 128; |     Dqn_usize spawn_cap             = 16; | ||||||
|     { |     { | ||||||
|         FP_GameEntityHandle mob_spawner = FP_Entity_CreateMobSpawner(game, mid_lane_mob_spawner_pos, spawn_cap, "Mob spawner"); |         FP_GameEntityHandle mob_spawner = FP_Entity_CreateMobSpawner(game, mid_lane_mob_spawner_pos, spawn_cap, "Mob spawner"); | ||||||
|         FP_Game_PushParentEntity(game, mob_spawner); |         FP_Game_PushParentEntity(game, mob_spawner); | ||||||
| @ -419,8 +456,16 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
|     bool const action_has_finished   = !entering_new_state && game->clock_ms >= action->end_at_clock_ms; |     bool const action_has_finished   = !entering_new_state && game->clock_ms >= action->end_at_clock_ms; | ||||||
|     action->state                    = action->next_state; |     action->state                    = action->next_state; | ||||||
| 
 | 
 | ||||||
|     switch (entity->type) { |     // NOTE: Left-shift lets us strafe in the same direction
 | ||||||
|  |     if (!TELY_Platform_InputScanCodeIsDown(input, TELY_PlatformInputScanCode_LeftShift)) { | ||||||
|  |         if (acceleration_meters_per_s->x) | ||||||
|  |             entity->direction = acceleration_meters_per_s->x > 0.f ? FP_GameDirection_Right : FP_GameDirection_Left; | ||||||
|  |         else if (acceleration_meters_per_s->y) | ||||||
|  |             entity->direction = acceleration_meters_per_s->y > 0.f ? FP_GameDirection_Down : FP_GameDirection_Up; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|  |     FP_EntityRenderData render_data  = FP_Entity_GetRenderData(game, entity->type, entity->action.state, entity->direction); | ||||||
|  |     switch (entity->type) { | ||||||
|         case FP_EntityType_Terry: { |         case FP_EntityType_Terry: { | ||||||
|             FP_EntityTerryState *state = DQN_CAST(FP_EntityTerryState *) & action->state; |             FP_EntityTerryState *state = DQN_CAST(FP_EntityTerryState *) & action->state; | ||||||
| 
 | 
 | ||||||
| @ -431,9 +476,8 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
| 
 | 
 | ||||||
|                 case FP_EntityTerryState_Idle: { |                 case FP_EntityTerryState_Idle: { | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.terry_walk_idle, TELY_AssetFlip_No); |  | ||||||
|                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; |                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (we_are_clicked_entity) { |                     if (we_are_clicked_entity) { | ||||||
| @ -448,19 +492,8 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
| 
 | 
 | ||||||
|                 case FP_EntityTerryState_Attack: { |                 case FP_EntityTerryState_Attack: { | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         uint32_t asset_flip             = {}; |                         uint64_t duration_ms = render_data.sprite.anim->count * render_data.sprite.anim->ms_per_frame; | ||||||
|                         Dqn_String8 desired_action_name = {}; |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite); | ||||||
|                         switch (entity->direction) { |  | ||||||
|                             case FP_GameDirection_Up:    desired_action_name = g_anim_names.terry_attack_up;   break; |  | ||||||
|                             case FP_GameDirection_Down:  desired_action_name = g_anim_names.terry_attack_down; break; |  | ||||||
|                             case FP_GameDirection_Left:  desired_action_name = g_anim_names.terry_attack_side; break; |  | ||||||
|                             case FP_GameDirection_Right: desired_action_name = g_anim_names.terry_attack_side; asset_flip |= TELY_AssetFlip_X; break; |  | ||||||
|                             case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break; |  | ||||||
|                         } |  | ||||||
| 
 |  | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, desired_action_name, DQN_CAST(TELY_AssetFlip)asset_flip); |  | ||||||
|                         uint64_t duration_ms            = sprite.anim->count * sprite.anim->ms_per_frame; |  | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |  | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (action_has_finished) { |                     if (action_has_finished) { | ||||||
| @ -469,26 +502,16 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
|                 } break; |                 } break; | ||||||
| 
 | 
 | ||||||
|                 case FP_EntityTerryState_Run: { |                 case FP_EntityTerryState_Run: { | ||||||
|                     Dqn_String8 desired_action_name = {}; |                     if (entering_new_state || action->sprite.anim->label != render_data.anim_name) { | ||||||
|                     switch (entity->direction) { |  | ||||||
|                         case FP_GameDirection_Up:    desired_action_name = g_anim_names.terry_walk_up;    break; |  | ||||||
|                         case FP_GameDirection_Down:  desired_action_name = g_anim_names.terry_walk_down;  break; |  | ||||||
|                         case FP_GameDirection_Left:  desired_action_name = g_anim_names.terry_walk_left;  break; |  | ||||||
|                         case FP_GameDirection_Right: desired_action_name = g_anim_names.terry_walk_right; break; |  | ||||||
|                         case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break; |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     if (entering_new_state || action->sprite.anim->label != desired_action_name) { |  | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, desired_action_name, TELY_AssetFlip_No); |  | ||||||
|                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; |                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (we_are_clicked_entity) { |                     if (we_are_clicked_entity) { | ||||||
|                         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_LeftShift) || |                         } 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); | ||||||
|                         } |                         } | ||||||
| @ -502,7 +525,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
|                 case FP_EntityTerryState_Dash: { |                 case FP_EntityTerryState_Dash: { | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         uint64_t duration_ms = 250; |                         uint64_t duration_ms = 250; | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, entity->action.sprite); |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite); | ||||||
|                         *acceleration_meters_per_s *= 35.f; |                         *acceleration_meters_per_s *= 35.f; | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
| @ -565,11 +588,9 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
|                 } break; |                 } break; | ||||||
| 
 | 
 | ||||||
|                 case FP_EntitySmoochieState_Idle: { |                 case FP_EntitySmoochieState_Idle: { | ||||||
| 
 |  | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.smoochie_walk_down, TELY_AssetFlip_No); |  | ||||||
|                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; |                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (we_are_clicked_entity) { |                     if (we_are_clicked_entity) { | ||||||
| @ -588,9 +609,9 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
| 
 | 
 | ||||||
|                 case FP_EntitySmoochieState_Attack: { |                 case FP_EntitySmoochieState_Attack: { | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.smoochie_attack_down, TELY_AssetFlip_No); |                         uint64_t duration_ms = render_data.sprite.anim->count * render_data.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, render_data.sprite); | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); | 
 | ||||||
|                         // NOTE: Deal with this further down with the gameplay attack code.
 |                         // NOTE: Deal with this further down with the gameplay attack code.
 | ||||||
|                         TELY_Audio_Play(audio, game->audio[FP_GameAudio_Smooch], 1.f); |                         TELY_Audio_Play(audio, game->audio[FP_GameAudio_Smooch], 1.f); | ||||||
|                     } |                     } | ||||||
| @ -639,24 +660,18 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
| 
 | 
 | ||||||
|                 case FP_EntitySmoochieState_HurtSide: { |                 case FP_EntitySmoochieState_HurtSide: { | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         TELY_AssetFlip flip             = entity->direction == FP_GameDirection_Right ? TELY_AssetFlip_X : TELY_AssetFlip_No; |                         uint64_t duration_ms = render_data.sprite.anim->count * render_data.sprite.anim->ms_per_frame; | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.smoochie_hurt_side, flip); |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite); | ||||||
|                         uint64_t duration_ms            = sprite.anim->count * sprite.anim->ms_per_frame; |  | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |  | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (action_has_finished) |                     if (action_has_finished) | ||||||
|                         FP_Game_EntityTransitionState(game, entity, FP_EntitySmoochieState_Idle); |                         FP_Game_EntityTransitionState(game, entity, FP_EntitySmoochieState_Idle); | ||||||
|                 } break; |                 } break; | ||||||
| 
 | 
 | ||||||
|                 case FP_EntitySmoochieState_AttackHeart: { |  | ||||||
|                 } break; |  | ||||||
| 
 |  | ||||||
|                 case FP_EntitySmoochieState_Death: { |                 case FP_EntitySmoochieState_Death: { | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.smoochie_death, TELY_AssetFlip_No); |                         uint64_t duration_ms = render_data.sprite.anim->count * render_data.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, render_data.sprite); | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |  | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (action_has_finished) |                     if (action_has_finished) | ||||||
| @ -665,17 +680,8 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|                 case FP_EntitySmoochieState_Run: { |                 case FP_EntitySmoochieState_Run: { | ||||||
|                     Dqn_String8 desired_action_name = {}; |                     if (entering_new_state || action->sprite.anim->label != render_data.anim_name) { | ||||||
|                     switch (entity->direction) { |                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, render_data.anim_name, render_data.flip); | ||||||
|                         case FP_GameDirection_Up:    desired_action_name = g_anim_names.smoochie_walk_up;    break; |  | ||||||
|                         case FP_GameDirection_Down:  desired_action_name = g_anim_names.smoochie_walk_down;  break; |  | ||||||
|                         case FP_GameDirection_Left:  desired_action_name = g_anim_names.smoochie_walk_left;  break; |  | ||||||
|                         case FP_GameDirection_Right: desired_action_name = g_anim_names.smoochie_walk_right; break; |  | ||||||
|                         case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break; |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     if (entering_new_state || action->sprite.anim->label != desired_action_name) { |  | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, desired_action_name, TELY_AssetFlip_No); |  | ||||||
|                         uint64_t duration_ms              = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; |                         uint64_t duration_ms              = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); | ||||||
|                     } |                     } | ||||||
| @ -737,9 +743,8 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
| 
 | 
 | ||||||
|                 case FP_EntityClingerState_Idle: { |                 case FP_EntityClingerState_Idle: { | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.clinger_walk_down, TELY_AssetFlip_No); |  | ||||||
|                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; |                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (we_are_clicked_entity) { |                     if (we_are_clicked_entity) { | ||||||
| @ -757,21 +762,9 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
|                 } break; |                 } break; | ||||||
| 
 | 
 | ||||||
|                 case FP_EntityClingerState_Attack: { |                 case FP_EntityClingerState_Attack: { | ||||||
| 
 |  | ||||||
|                     uint32_t asset_flip             = {}; |  | ||||||
|                     Dqn_String8 desired_action_name = {}; |  | ||||||
|                     switch (entity->direction) { |  | ||||||
|                         case FP_GameDirection_Up:    desired_action_name = g_anim_names.clinger_attack_up;   break; |  | ||||||
|                         case FP_GameDirection_Down:  desired_action_name = g_anim_names.clinger_attack_down; break; |  | ||||||
|                         case FP_GameDirection_Left:  desired_action_name = g_anim_names.clinger_attack_side; asset_flip |= TELY_AssetFlip_X; break; |  | ||||||
|                         case FP_GameDirection_Right: desired_action_name = g_anim_names.clinger_attack_side; break; |  | ||||||
|                         case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break; |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, desired_action_name, DQN_CAST(TELY_AssetFlip)asset_flip); |                         uint64_t duration_ms = render_data.sprite.anim->count * render_data.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, render_data.sprite); | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |  | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (action_has_finished) |                     if (action_has_finished) | ||||||
| @ -791,19 +784,9 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
|                 } break; |                 } break; | ||||||
| 
 | 
 | ||||||
|                 case FP_EntityClingerState_Run: { |                 case FP_EntityClingerState_Run: { | ||||||
|                     Dqn_String8 desired_action_name = {}; |                     if (entering_new_state || action->sprite.anim->label != render_data.anim_name) { | ||||||
|                     switch (entity->direction) { |  | ||||||
|                         case FP_GameDirection_Up:    desired_action_name = g_anim_names.clinger_walk_up;   break; |  | ||||||
|                         case FP_GameDirection_Down:  desired_action_name = g_anim_names.clinger_walk_down; break; |  | ||||||
|                         case FP_GameDirection_Left:  desired_action_name = g_anim_names.clinger_walk_down; break; |  | ||||||
|                         case FP_GameDirection_Right: desired_action_name = g_anim_names.clinger_walk_down; break; |  | ||||||
|                         case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break; |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     if (entering_new_state || action->sprite.anim->label != desired_action_name) { |  | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, desired_action_name, TELY_AssetFlip_No); |  | ||||||
|                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; |                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (we_are_clicked_entity) { |                     if (we_are_clicked_entity) { | ||||||
| @ -862,9 +845,8 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
| 
 | 
 | ||||||
|                 case FP_EntityMerchantTerryState_Idle: { |                 case FP_EntityMerchantTerryState_Idle: { | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.merchant_terry, TELY_AssetFlip_No); |  | ||||||
|                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; |                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                 } break; |                 } break; | ||||||
| @ -880,9 +862,8 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
| 
 | 
 | ||||||
|                 case FP_EntityMerchantPhoneCompanyState_Idle: { |                 case FP_EntityMerchantPhoneCompanyState_Idle: { | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.merchant_phone_company, TELY_AssetFlip_No); |  | ||||||
|                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; |                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite); | ||||||
|                     } |                     } | ||||||
|                 } break; |                 } break; | ||||||
|             } |             } | ||||||
| @ -897,9 +878,8 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
| 
 | 
 | ||||||
|                 case FP_EntityMerchantGymState_Idle: { |                 case FP_EntityMerchantGymState_Idle: { | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.merchant_gym, TELY_AssetFlip_No); |  | ||||||
|                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; |                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                 } break; |                 } break; | ||||||
| @ -915,9 +895,8 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
| 
 | 
 | ||||||
|                 case FP_EntityMerchantGraveyardState_Idle: { |                 case FP_EntityMerchantGraveyardState_Idle: { | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.merchant_graveyard, TELY_AssetFlip_No); |  | ||||||
|                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; |                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                 } break; |                 } break; | ||||||
| @ -933,17 +912,15 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
| 
 | 
 | ||||||
|                 case FP_EntityClubTerryState_Idle: { |                 case FP_EntityClubTerryState_Idle: { | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.club_terry_dark, TELY_AssetFlip_No); |  | ||||||
|                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; |                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite); | ||||||
|                     } |                     } | ||||||
|                 } break; |                 } break; | ||||||
| 
 | 
 | ||||||
|                 case FP_EntityClubTerryState_PartyTime: { |                 case FP_EntityClubTerryState_PartyTime: { | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.club_terry_alive, TELY_AssetFlip_No); |  | ||||||
|                         uint64_t duration_ms = 5000; |                         uint64_t duration_ms = 5000; | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (action_has_finished) { |                     if (action_has_finished) { | ||||||
| @ -970,9 +947,8 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
| 
 | 
 | ||||||
|                 case FP_EntityMapState_Idle: { |                 case FP_EntityMapState_Idle: { | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.map, TELY_AssetFlip_No); |  | ||||||
|                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; |                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite); | ||||||
|                     } |                     } | ||||||
|                 } break; |                 } break; | ||||||
|             } |             } | ||||||
| @ -988,9 +964,8 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform | |||||||
| 
 | 
 | ||||||
|                 case FP_EntityHeartState_Idle: { |                 case FP_EntityHeartState_Idle: { | ||||||
|                     if (entering_new_state) { |                     if (entering_new_state) { | ||||||
|                         TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.heart, TELY_AssetFlip_No); |  | ||||||
|                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; |                         uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER; | ||||||
|                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite); |                         FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite); | ||||||
|                     } |                     } | ||||||
|                 } break; |                 } break; | ||||||
|             } |             } | ||||||
| @ -1088,15 +1063,11 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input | |||||||
|                     case FP_EntityType_MerchantGraveyard:    break; |                     case FP_EntityType_MerchantGraveyard:    break; | ||||||
|                     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; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (move_entity) { |                 if (move_entity) { | ||||||
|                     acceleration_meters_per_s = dir_vector * entity->base_acceleration_per_s.meters; |                     acceleration_meters_per_s = dir_vector * entity->base_acceleration_per_s.meters; | ||||||
|                     if (dir_vector.x) |  | ||||||
|                         entity->direction = dir_vector.x > 0.f ? FP_GameDirection_Right : FP_GameDirection_Left; |  | ||||||
|                     else if (dir_vector.y) |  | ||||||
|                         entity->direction = dir_vector.y > 0.f ? FP_GameDirection_Down : FP_GameDirection_Up; |  | ||||||
| 
 |  | ||||||
|                     if (TELY_Platform_InputScanCodeIsDown(input, TELY_PlatformInputScanCode_Space)) |                     if (TELY_Platform_InputScanCodeIsDown(input, TELY_PlatformInputScanCode_Space)) | ||||||
|                         acceleration_meters_per_s *= 2.5f; |                         acceleration_meters_per_s *= 2.5f; | ||||||
|                 } |                 } | ||||||
| @ -1357,6 +1328,9 @@ 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_F)) | ||||||
|  |                 game->build_mode = !game->build_mode; | ||||||
|  | 
 | ||||||
|             if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F1)) { |             if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F1)) { | ||||||
|                 entity->sprite_height.meters += 1; |                 entity->sprite_height.meters += 1; | ||||||
|                 Dqn_Log_InfoF("Height: %.1f", entity->sprite_height.meters); |                 Dqn_Log_InfoF("Height: %.1f", entity->sprite_height.meters); | ||||||
| @ -1368,6 +1342,14 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input | |||||||
| 
 | 
 | ||||||
|             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; | ||||||
|  | 
 | ||||||
|  |             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"); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // NOTE: Tick the state machine
 |         // NOTE: Tick the state machine
 | ||||||
| @ -1451,7 +1433,6 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input | |||||||
|                         waypoint->data.arrive                          = FP_GameWaypointArrive_WhenWithinEntitySize; |                         waypoint->data.arrive                          = FP_GameWaypointArrive_WhenWithinEntitySize; | ||||||
|                         waypoint->data.value                           = 1.5f; |                         waypoint->data.value                           = 1.5f; | ||||||
|                     } |                     } | ||||||
|                      |  | ||||||
|                     entity->enemies_spawned_this_wave++; |                     entity->enemies_spawned_this_wave++; | ||||||
| 
 | 
 | ||||||
|                     // NOTE: If all enemies for the current wave have been spawned
 |                     // NOTE: If all enemies for the current wave have been spawned
 | ||||||
| @ -1741,6 +1722,27 @@ 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); | ||||||
|  | 
 | ||||||
|  |             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*/, | ||||||
|  |                                         TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, 0.5f)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         // 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); | ||||||
| @ -1847,10 +1849,9 @@ void TELY_DLL_FrameUpdate(void *user_data) | |||||||
|     FP_Render(game, platform, renderer); |     FP_Render(game, platform, renderer); | ||||||
| 
 | 
 | ||||||
|     // 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); }; | ||||||
| 
 |     { | ||||||
|         // 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")); | ||||||
|  | |||||||
| @ -34,7 +34,6 @@ enum FP_EntitySmoochieState | |||||||
|     FP_EntitySmoochieState_Idle, |     FP_EntitySmoochieState_Idle, | ||||||
|     FP_EntitySmoochieState_Attack, |     FP_EntitySmoochieState_Attack, | ||||||
|     FP_EntitySmoochieState_HurtSide, |     FP_EntitySmoochieState_HurtSide, | ||||||
|     FP_EntitySmoochieState_AttackHeart, |  | ||||||
|     FP_EntitySmoochieState_Death, |     FP_EntitySmoochieState_Death, | ||||||
|     FP_EntitySmoochieState_Run, |     FP_EntitySmoochieState_Run, | ||||||
| }; | }; | ||||||
| @ -90,3 +89,14 @@ enum FP_EntityHeartState | |||||||
|     FP_EntityHeartState_Nil, |     FP_EntityHeartState_Nil, | ||||||
|     FP_EntityHeartState_Idle, |     FP_EntityHeartState_Idle, | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | struct FP_EntityRenderData | ||||||
|  | { | ||||||
|  |     FP_Meters                 height; | ||||||
|  |     TELY_AssetFlip            flip; | ||||||
|  |     Dqn_String8               anim_name; | ||||||
|  |     TELY_AssetSpriteSheet    *sheet; | ||||||
|  |     Dqn_Rect                  sheet_rect; | ||||||
|  |     Dqn_V2                    render_size; | ||||||
|  |     TELY_AssetAnimatedSprite  sprite; | ||||||
|  | }; | ||||||
|  | |||||||
| @ -3,6 +3,178 @@ | |||||||
| #include "feely_pona_unity.h" | #include "feely_pona_unity.h" | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | static Dqn_f32 FP_Entity_CalcSpriteScaleForDesiredHeight(FP_Game *game, FP_Meters height, Dqn_Rect sprite_rect) | ||||||
|  | { | ||||||
|  |     Dqn_f32 sprite_in_meters = FP_Game_PixelsToMetersNx1(game, sprite_rect.size.y); | ||||||
|  |     Dqn_f32 result           = height.meters / sprite_in_meters; | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | FP_EntityRenderData FP_Entity_GetRenderData(FP_Game *game, FP_EntityType type, uint32_t raw_state, FP_GameDirection direction) | ||||||
|  | { | ||||||
|  |     FP_EntityRenderData result = {}; | ||||||
|  |     switch (type) { | ||||||
|  |         case FP_EntityType_Nil: { | ||||||
|  |         } break; | ||||||
|  | 
 | ||||||
|  |         case FP_EntityType_Map: { | ||||||
|  |             result.height.meters = 41.9f; | ||||||
|  |             result.anim_name     = g_anim_names.map; | ||||||
|  |         } break; | ||||||
|  | 
 | ||||||
|  |         case FP_EntityType_Terry: { | ||||||
|  |             result.height.meters = 1.8f; | ||||||
|  |             FP_EntityTerryState state = DQN_CAST(FP_EntityTerryState)raw_state; | ||||||
|  |             switch (state) { | ||||||
|  |                 case FP_EntityTerryState_Nil: break; | ||||||
|  |                 case FP_EntityTerryState_Idle:   result.anim_name = g_anim_names.terry_walk_idle; break; | ||||||
|  | 
 | ||||||
|  |                 case FP_EntityTerryState_Attack: { | ||||||
|  |                     switch (direction) { | ||||||
|  |                         case FP_GameDirection_Up:    result.anim_name = g_anim_names.terry_attack_up;   break; | ||||||
|  |                         case FP_GameDirection_Down:  result.anim_name = g_anim_names.terry_attack_down; break; | ||||||
|  |                         case FP_GameDirection_Left:  result.anim_name = g_anim_names.terry_attack_side; break; | ||||||
|  |                         case FP_GameDirection_Right: result.anim_name = g_anim_names.terry_attack_side; result.flip = TELY_AssetFlip_X; 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; | ||||||
|  |                         case FP_GameDirection_Down:  result.anim_name = g_anim_names.terry_walk_down;  break; | ||||||
|  |                         case FP_GameDirection_Left:  result.anim_name = g_anim_names.terry_walk_left;  break; | ||||||
|  |                         case FP_GameDirection_Right: result.anim_name = g_anim_names.terry_walk_right; break; | ||||||
|  |                         case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break; | ||||||
|  |                     } | ||||||
|  |                 } break; | ||||||
|  |             } | ||||||
|  |         } break; | ||||||
|  | 
 | ||||||
|  |         case FP_EntityType_Smoochie: { | ||||||
|  |             result.height.meters = 1.6f; | ||||||
|  |             FP_EntitySmoochieState state = DQN_CAST(FP_EntitySmoochieState)raw_state; | ||||||
|  |             switch (state) { | ||||||
|  |                 case FP_EntitySmoochieState_Nil:         break; | ||||||
|  |                 case FP_EntitySmoochieState_Idle:        result.anim_name = g_anim_names.smoochie_walk_down; break; | ||||||
|  |                 case FP_EntitySmoochieState_Attack:      result.anim_name = g_anim_names.smoochie_attack_down; break; | ||||||
|  |                 case FP_EntitySmoochieState_HurtSide:    result.anim_name = g_anim_names.smoochie_hurt_side; result.flip = direction == FP_GameDirection_Right ? TELY_AssetFlip_X : TELY_AssetFlip_No; break; | ||||||
|  |                 case FP_EntitySmoochieState_Death:       result.anim_name = g_anim_names.smoochie_death; break; | ||||||
|  |                 case FP_EntitySmoochieState_Run: { | ||||||
|  |                     switch (direction) { | ||||||
|  |                         case FP_GameDirection_Up:    result.anim_name = g_anim_names.smoochie_walk_up;    break; | ||||||
|  |                         case FP_GameDirection_Down:  result.anim_name = g_anim_names.smoochie_walk_down;  break; | ||||||
|  |                         case FP_GameDirection_Left:  result.anim_name = g_anim_names.smoochie_walk_left;  break; | ||||||
|  |                         case FP_GameDirection_Right: result.anim_name = g_anim_names.smoochie_walk_right; break; | ||||||
|  |                         case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break; | ||||||
|  |                     } | ||||||
|  |                 } break; | ||||||
|  |             } | ||||||
|  |         } break; | ||||||
|  | 
 | ||||||
|  |         case FP_EntityType_MerchantTerry: { | ||||||
|  |             result.height.meters = 3.66f; | ||||||
|  |             FP_EntityMerchantTerryState state = DQN_CAST(FP_EntityMerchantTerryState)raw_state; | ||||||
|  |             switch (state) { | ||||||
|  |                 case FP_EntityMerchantTerryState_Nil: break; | ||||||
|  |                 case FP_EntityMerchantTerryState_Idle: result.anim_name = g_anim_names.merchant_terry; break; | ||||||
|  |             } | ||||||
|  |         } break; | ||||||
|  | 
 | ||||||
|  |         case FP_EntityType_MerchantGraveyard: { | ||||||
|  |             result.height.meters = 3.66f; | ||||||
|  |             FP_EntityMerchantGraveyardState state = DQN_CAST(FP_EntityMerchantGraveyardState)raw_state; | ||||||
|  |             switch (state) { | ||||||
|  |                 case FP_EntityMerchantGraveyardState_Nil: break; | ||||||
|  |                 case FP_EntityMerchantGraveyardState_Idle: result.anim_name = g_anim_names.merchant_graveyard; break; | ||||||
|  |             } | ||||||
|  |         } break; | ||||||
|  | 
 | ||||||
|  |         case FP_EntityType_MerchantGym: { | ||||||
|  |             result.height.meters = 3.66f; | ||||||
|  |             result.anim_name     = g_anim_names.merchant_gym; | ||||||
|  |             FP_EntityMerchantGymState state = DQN_CAST(FP_EntityMerchantGymState)raw_state; | ||||||
|  |             switch (state) { | ||||||
|  |                 case FP_EntityMerchantGymState_Nil: break; | ||||||
|  |                 case FP_EntityMerchantGymState_Idle: result.anim_name = g_anim_names.merchant_gym; break; | ||||||
|  |             } | ||||||
|  |         } break; | ||||||
|  | 
 | ||||||
|  |         case FP_EntityType_MerchantPhoneCompany: { | ||||||
|  |             result.height.meters = 3.66f; | ||||||
|  |             FP_EntityMerchantPhoneCompanyState state = DQN_CAST(FP_EntityMerchantPhoneCompanyState)raw_state; | ||||||
|  |             switch (state) { | ||||||
|  |                 case FP_EntityMerchantPhoneCompanyState_Nil: break; | ||||||
|  |                 case FP_EntityMerchantPhoneCompanyState_Idle: result.anim_name = g_anim_names.merchant_phone_company; break; | ||||||
|  |             } | ||||||
|  |         } break; | ||||||
|  | 
 | ||||||
|  |         case FP_EntityType_ClubTerry: { | ||||||
|  |             result.height.meters          = 4.f; | ||||||
|  |             FP_EntityClubTerryState state = DQN_CAST(FP_EntityClubTerryState)raw_state; | ||||||
|  |             switch (state) { | ||||||
|  |                 case FP_EntityClubTerryState_Nil:       break; | ||||||
|  |                 case FP_EntityClubTerryState_Idle:      result.anim_name = g_anim_names.club_terry_dark; break; | ||||||
|  |                 case FP_EntityClubTerryState_PartyTime: result.anim_name = g_anim_names.club_terry_alive; break; | ||||||
|  |             } | ||||||
|  |         } break; | ||||||
|  | 
 | ||||||
|  |         case FP_EntityType_Clinger: { | ||||||
|  |             result.height.meters = 1.6f; | ||||||
|  |             FP_EntityClingerState state = DQN_CAST(FP_EntityClingerState)raw_state; | ||||||
|  |             switch (state) { | ||||||
|  |                 case FP_EntityClingerState_Nil: break; | ||||||
|  |                 case FP_EntityClingerState_Idle: result.anim_name = g_anim_names.clinger_walk_down; break; | ||||||
|  | 
 | ||||||
|  |                 case FP_EntityClingerState_Attack: { | ||||||
|  |                     switch (direction) { | ||||||
|  |                         case FP_GameDirection_Up:    result.anim_name = g_anim_names.clinger_attack_up;   break; | ||||||
|  |                         case FP_GameDirection_Down:  result.anim_name = g_anim_names.clinger_attack_down; break; | ||||||
|  |                         case FP_GameDirection_Left:  result.anim_name = g_anim_names.clinger_attack_side; result.flip = TELY_AssetFlip_X; break; | ||||||
|  |                         case FP_GameDirection_Right: result.anim_name = g_anim_names.clinger_attack_side; break; | ||||||
|  |                         case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break; | ||||||
|  |                     } | ||||||
|  |                 } break; | ||||||
|  | 
 | ||||||
|  |                 case FP_EntityClingerState_Death: result.anim_name = g_anim_names.clinger_death; break; | ||||||
|  | 
 | ||||||
|  |                 case FP_EntityClingerState_Run: { | ||||||
|  |                     switch (direction) { | ||||||
|  |                         case FP_GameDirection_Up:    result.anim_name = g_anim_names.clinger_walk_up;   break; | ||||||
|  |                         case FP_GameDirection_Down:  result.anim_name = g_anim_names.clinger_walk_down; break; | ||||||
|  |                         case FP_GameDirection_Left:  result.anim_name = g_anim_names.clinger_walk_down; break; | ||||||
|  |                         case FP_GameDirection_Right: result.anim_name = g_anim_names.clinger_walk_down; break; | ||||||
|  |                         case FP_GameDirection_Count: DQN_INVALID_CODE_PATH; break; | ||||||
|  |                     } | ||||||
|  |                 } break; | ||||||
|  |             } | ||||||
|  |         } break; | ||||||
|  | 
 | ||||||
|  |         case FP_EntityType_Heart: { | ||||||
|  |             result.height.meters = 4.f; | ||||||
|  |             FP_EntityHeartState state = DQN_CAST(FP_EntityHeartState)raw_state; | ||||||
|  |             switch (state) { | ||||||
|  |                 case FP_EntityHeartState_Nil: break; | ||||||
|  |                 case FP_EntityHeartState_Idle: result.anim_name = g_anim_names.heart; break; | ||||||
|  |             } | ||||||
|  |         } break; | ||||||
|  | 
 | ||||||
|  |         case FP_EntityType_Count: DQN_INVALID_CODE_PATH; break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     result.sheet  = &game->atlas_sprite_sheet; | ||||||
|  |     TELY_AssetSpriteAnimation *sprite_anim = TELY_Asset_GetSpriteAnimation(result.sheet, result.anim_name); | ||||||
|  |     if (sprite_anim) { | ||||||
|  |         result.sheet_rect  = result.sheet->rects.data[sprite_anim->index]; | ||||||
|  |         Dqn_f32 size_scale = FP_Entity_CalcSpriteScaleForDesiredHeight(game, result.height, result.sheet_rect); | ||||||
|  |         result.render_size = result.sheet_rect.size * size_scale; | ||||||
|  |         result.sprite      = TELY_Asset_MakeAnimatedSprite(result.sheet, result.anim_name, result.flip); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void FP_Entity_AddDebugEditorFlags(FP_Game *game, FP_GameEntityHandle handle) | static void FP_Entity_AddDebugEditorFlags(FP_Game *game, FP_GameEntityHandle handle) | ||||||
| { | { | ||||||
|     FP_GameEntity *entity = FP_Game_GetEntity(game, handle); |     FP_GameEntity *entity = FP_Game_GetEntity(game, handle); | ||||||
| @ -14,13 +186,6 @@ static void FP_Entity_AddDebugEditorFlags(FP_Game *game, FP_GameEntityHandle han | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static Dqn_f32 FP_Entity_CalcSpriteScaleForDesiredHeight(FP_Game *game, FP_Meters height, Dqn_Rect sprite_rect) |  | ||||||
| { |  | ||||||
|     Dqn_f32 sprite_in_meters = FP_Game_PixelsToMetersNx1(game, sprite_rect.size.y); |  | ||||||
|     Dqn_f32 result           = height.meters / sprite_in_meters; |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static FP_GameEntityHandle FP_Entity_CreateWaypointF(FP_Game *game, Dqn_V2 pos, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) | static FP_GameEntityHandle FP_Entity_CreateWaypointF(FP_Game *game, Dqn_V2 pos, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) | ||||||
| { | { | ||||||
|     va_list args; |     va_list args; | ||||||
| @ -55,7 +220,7 @@ static FP_GameEntityHandle FP_Entity_CreateClinger(FP_Game *game, Dqn_V2 pos, DQ | |||||||
|     entity->is_dying                       = false; |     entity->is_dying                       = false; | ||||||
|     entity->base_acceleration_per_s.meters = 8.f; |     entity->base_acceleration_per_s.meters = 8.f; | ||||||
|     entity->local_pos                      = pos; |     entity->local_pos                      = pos; | ||||||
|     entity->sprite_height.meters           = 1.6f; |     entity->sprite_height                  = FP_Entity_GetRenderData(game, entity->type, 0 /*state*/, FP_GameDirection_Down).height; | ||||||
|     entity->attack_cooldown_ms             = 1000; |     entity->attack_cooldown_ms             = 1000; | ||||||
| 
 | 
 | ||||||
|     entity->local_hit_box_size   = FP_Game_MetersToPixelsNx2(game, 0.4f, entity->sprite_height.meters * .5f); |     entity->local_hit_box_size   = FP_Game_MetersToPixelsNx2(game, 0.4f, entity->sprite_height.meters * .5f); | ||||||
| @ -78,7 +243,7 @@ static FP_GameEntityHandle FP_Entity_CreateSmoochie(FP_Game *game, Dqn_V2 pos, D | |||||||
|     entity->hp                             = 1; |     entity->hp                             = 1; | ||||||
|     entity->is_dying                       = false; |     entity->is_dying                       = false; | ||||||
|     entity->local_pos                      = pos; |     entity->local_pos                      = pos; | ||||||
|     entity->sprite_height.meters           = 1.6f; |     entity->sprite_height                  = FP_Entity_GetRenderData(game, entity->type, 0 /*state*/, FP_GameDirection_Down).height; | ||||||
|     entity->attack_cooldown_ms             = 1000; |     entity->attack_cooldown_ms             = 1000; | ||||||
|     entity->local_hit_box_size             = FP_Game_MetersToPixelsNx2(game, 0.4f, entity->sprite_height.meters * .6f); |     entity->local_hit_box_size             = FP_Game_MetersToPixelsNx2(game, 0.4f, entity->sprite_height.meters * .6f); | ||||||
|     FP_Entity_AddDebugEditorFlags(game, entity->handle); |     FP_Entity_AddDebugEditorFlags(game, entity->handle); | ||||||
| @ -144,7 +309,7 @@ static FP_GameEntityHandle FP_Entity_CreateTerry(FP_Game *game, Dqn_V2 pos, DQN_ | |||||||
|     entity->type                           = FP_EntityType_Terry; |     entity->type                           = FP_EntityType_Terry; | ||||||
|     entity->local_pos                      = pos; |     entity->local_pos                      = pos; | ||||||
|     entity->base_acceleration_per_s.meters = 16.f; |     entity->base_acceleration_per_s.meters = 16.f; | ||||||
|     entity->sprite_height.meters           = 1.8f; |     entity->sprite_height                  = FP_Entity_GetRenderData(game, entity->type, 0 /*state*/, FP_GameDirection_Down).height; | ||||||
|     entity->attack_cooldown_ms             = 500; |     entity->attack_cooldown_ms             = 500; | ||||||
|     entity->local_hit_box_size             = FP_Game_MetersToPixelsNx2(game, 0.5f, entity->sprite_height.meters * .6f); |     entity->local_hit_box_size             = FP_Game_MetersToPixelsNx2(game, 0.5f, entity->sprite_height.meters * .6f); | ||||||
|     FP_Entity_AddDebugEditorFlags(game, result); |     FP_Entity_AddDebugEditorFlags(game, result); | ||||||
| @ -164,7 +329,7 @@ static FP_GameEntityHandle FP_Entity_CreateMerchantTerry(FP_Game *game, Dqn_V2 p | |||||||
| 
 | 
 | ||||||
|     entity->type                 = FP_EntityType_MerchantTerry; |     entity->type                 = FP_EntityType_MerchantTerry; | ||||||
|     entity->local_pos            = pos; |     entity->local_pos            = pos; | ||||||
|     entity->sprite_height.meters = 3.66f; |     entity->sprite_height        = FP_Entity_GetRenderData(game, entity->type, 0 /*state*/, FP_GameDirection_Down).height; | ||||||
|     FP_Entity_AddDebugEditorFlags(game, result); |     FP_Entity_AddDebugEditorFlags(game, result); | ||||||
|     entity->flags              |= FP_GameEntityFlag_NonTraversable; |     entity->flags              |= FP_GameEntityFlag_NonTraversable; | ||||||
| 
 | 
 | ||||||
| @ -188,7 +353,7 @@ static FP_GameEntityHandle FP_Entity_CreateMerchantGraveyard(FP_Game *game, Dqn_ | |||||||
| 
 | 
 | ||||||
|     entity->type                 = FP_EntityType_MerchantGraveyard; |     entity->type                 = FP_EntityType_MerchantGraveyard; | ||||||
|     entity->local_pos            = pos; |     entity->local_pos            = pos; | ||||||
|     entity->sprite_height.meters = 3.66f; |     entity->sprite_height        = FP_Entity_GetRenderData(game, entity->type, 0 /*state*/, FP_GameDirection_Down).height; | ||||||
|     FP_Entity_AddDebugEditorFlags(game, result); |     FP_Entity_AddDebugEditorFlags(game, result); | ||||||
|     entity->flags              |= FP_GameEntityFlag_NonTraversable; |     entity->flags              |= FP_GameEntityFlag_NonTraversable; | ||||||
| 
 | 
 | ||||||
| @ -213,7 +378,7 @@ static FP_GameEntityHandle FP_Entity_CreateMerchantGym(FP_Game *game, Dqn_V2 pos | |||||||
| 
 | 
 | ||||||
|     entity->type               = FP_EntityType_MerchantGym; |     entity->type               = FP_EntityType_MerchantGym; | ||||||
|     entity->local_pos          = pos; |     entity->local_pos          = pos; | ||||||
|     entity->sprite_height.meters = 3.66f; |     entity->sprite_height      = FP_Entity_GetRenderData(game, entity->type, 0 /*state*/, FP_GameDirection_Down).height; | ||||||
|     FP_Entity_AddDebugEditorFlags(game, result); |     FP_Entity_AddDebugEditorFlags(game, result); | ||||||
|     entity->flags             |= FP_GameEntityFlag_NonTraversable; |     entity->flags             |= FP_GameEntityFlag_NonTraversable; | ||||||
| 
 | 
 | ||||||
| @ -237,7 +402,7 @@ static FP_GameEntityHandle FP_Entity_CreateMerchantPhoneCompany(FP_Game *game, D | |||||||
| 
 | 
 | ||||||
|     entity->type                 = FP_EntityType_MerchantPhoneCompany; |     entity->type                 = FP_EntityType_MerchantPhoneCompany; | ||||||
|     entity->local_pos            = pos; |     entity->local_pos            = pos; | ||||||
|     entity->sprite_height.meters = 3.66f; |     entity->sprite_height        = FP_Entity_GetRenderData(game, entity->type, 0 /*state*/, FP_GameDirection_Down).height; | ||||||
|     FP_Entity_AddDebugEditorFlags(game, result); |     FP_Entity_AddDebugEditorFlags(game, result); | ||||||
|     entity->flags              |= FP_GameEntityFlag_NonTraversable; |     entity->flags              |= FP_GameEntityFlag_NonTraversable; | ||||||
| 
 | 
 | ||||||
| @ -261,7 +426,7 @@ static FP_GameEntityHandle FP_Entity_CreateClubTerry(FP_Game *game, Dqn_V2 pos, | |||||||
| 
 | 
 | ||||||
|     entity->type                 = FP_EntityType_ClubTerry; |     entity->type                 = FP_EntityType_ClubTerry; | ||||||
|     entity->local_pos            = pos; |     entity->local_pos            = pos; | ||||||
|     entity->sprite_height.meters = 4.f; |     entity->sprite_height        = FP_Entity_GetRenderData(game, entity->type, 0 /*state*/, FP_GameDirection_Down).height; | ||||||
|     FP_Entity_AddDebugEditorFlags(game, result); |     FP_Entity_AddDebugEditorFlags(game, result); | ||||||
|     entity->flags              |= FP_GameEntityFlag_NonTraversable; |     entity->flags              |= FP_GameEntityFlag_NonTraversable; | ||||||
| 
 | 
 | ||||||
| @ -285,7 +450,7 @@ static FP_GameEntityHandle FP_Entity_CreateHeart(FP_Game *game, Dqn_V2 pos, DQN_ | |||||||
| 
 | 
 | ||||||
|     entity->type                 = FP_EntityType_Heart; |     entity->type                 = FP_EntityType_Heart; | ||||||
|     entity->local_pos            = pos; |     entity->local_pos            = pos; | ||||||
|     entity->sprite_height.meters = 4.f; |     entity->sprite_height        = FP_Entity_GetRenderData(game, entity->type, 0 /*state*/, FP_GameDirection_Down).height; | ||||||
|     FP_Entity_AddDebugEditorFlags(game, result); |     FP_Entity_AddDebugEditorFlags(game, result); | ||||||
|     entity->flags              |= FP_GameEntityFlag_NonTraversable; |     entity->flags              |= FP_GameEntityFlag_NonTraversable; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -254,6 +254,8 @@ struct FP_Game | |||||||
|     Dqn_f32                               meters_to_pixels; |     Dqn_f32                               meters_to_pixels; | ||||||
|     uint64_t                              clock_ms; |     uint64_t                              clock_ms; | ||||||
|     Dqn_PCG32                             rng; |     Dqn_PCG32                             rng; | ||||||
|  | 
 | ||||||
|  |     bool                                 build_mode; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct FP_GameAStarNode | struct FP_GameAStarNode | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user