fp: Add a pop-up merchant menu and key bindings text

This commit is contained in:
doyle 2023-10-06 23:16:55 +11:00
parent a591254d5b
commit fe4095b6bb
5 changed files with 114 additions and 29 deletions

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

Binary file not shown.

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

Binary file not shown.

View File

@ -427,17 +427,17 @@ void TELY_DLL_Init(void *user_data)
{ {
Dqn_V2 base_top_left_pos = Dqn_V2_InitNx2(1018, -335); Dqn_V2 base_top_left_pos = Dqn_V2_InitNx2(1018, -335);
Dqn_V2 base_bottom_right_pos = Dqn_V2_InitNx2(2118, +351); Dqn_V2 base_bottom_right_pos = Dqn_V2_InitNx2(2050, +351);
Dqn_V2 base_top_left = base_top_left_pos; Dqn_V2 base_top_left = base_top_left_pos;
Dqn_V2 base_top_right = Dqn_V2_InitNx2(base_bottom_right_pos.x, base_top_left_pos.y); Dqn_V2 base_top_right = Dqn_V2_InitNx2(base_bottom_right_pos.x, base_top_left_pos.y);
Dqn_V2 base_bottom_left = Dqn_V2_InitNx2(base_top_left_pos.x, base_bottom_right_pos.y); Dqn_V2 base_bottom_left = Dqn_V2_InitNx2(base_top_left_pos.x, base_bottom_right_pos.y);
Dqn_V2 base_bottom_right = Dqn_V2_InitNx2(base_bottom_right_pos.x, base_bottom_right_pos.y); Dqn_V2 base_bottom_right = Dqn_V2_InitNx2(base_bottom_right_pos.x, base_bottom_right_pos.y);
FP_Entity_CreateMerchantTerry(game, base_top_left, "Merchant"); game->merchant_terry = FP_Entity_CreateMerchantTerry(game, base_top_left, "Merchant");
FP_Entity_CreateMerchantGraveyard(game, base_bottom_left, "Graveyard"); game->merchant_graveyard = FP_Entity_CreateMerchantGraveyard(game, base_bottom_left, "Graveyard");
FP_Entity_CreateMerchantGym(game, base_bottom_right, "Gym"); game->merchant_gym = FP_Entity_CreateMerchantGym(game, base_bottom_right, "Gym");
FP_Entity_CreateMerchantPhoneCompany(game, base_top_right, "PhoneCompany"); game->merchant_phone_company = FP_Entity_CreateMerchantPhoneCompany(game, base_top_right, "PhoneCompany");
} }
FP_Entity_CreateClubTerry(game, Dqn_V2_InitNx2(567, -191), "Club Terry"); FP_Entity_CreateClubTerry(game, Dqn_V2_InitNx2(567, -191), "Club Terry");
@ -1664,15 +1664,16 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
} }
if (game->clicked_entity == entity->handle) { if (game->clicked_entity == entity->handle) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_H)) if (game->active_menu == FP_GameActiveMenu_Nil || game->active_menu == FP_GameActiveMenu_Build) {
game->build_mode = !game->build_mode; if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_H))
game->active_menu = DQN_CAST(FP_GameActiveMenu)(DQN_CAST(uint32_t)game->active_menu ^ FP_GameActiveMenu_Build);
}
if (entity->flags & FP_GameEntityFlag_CameraTracking) if (entity->flags & FP_GameEntityFlag_CameraTracking)
game->camera.world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle) - Dqn_V2_InitV2I(platform->core.window_size) * .5f; game->camera.world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle) - Dqn_V2_InitV2I(platform->core.window_size) * .5f;
game->build_mode_can_place_building = false; game->build_mode_can_place_building = false;
if (game->build_mode) { if (game->active_menu == FP_GameActiveMenu_Build) {
FP_GamePlaceableBuilding placeable_building = PLACEABLE_BUILDINGS[game->build_mode_building_index]; FP_GamePlaceableBuilding placeable_building = PLACEABLE_BUILDINGS[game->build_mode_building_index];
Dqn_Rect dest_rect = FP_Game_GetBuildingPlacementRectForEntity(game, placeable_building, entity->handle); Dqn_Rect dest_rect = FP_Game_GetBuildingPlacementRectForEntity(game, placeable_building, entity->handle);
Dqn_V2 placement_pos = Dqn_Rect_Center(dest_rect); Dqn_V2 placement_pos = Dqn_Rect_Center(dest_rect);
@ -2109,7 +2110,7 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer)
} }
} }
if (game->build_mode) { if (game->active_menu == FP_GameActiveMenu_Build) {
if (entity->flags & FP_GameEntityFlag_BuildZone) 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)); TELY_Render_RectColourV4(renderer, world_hit_box, TELY_RenderShapeMode_Fill, TELY_Colour_V4Alpha(TELY_COLOUR_BLUE_CADET_V4, 0.5f));
} }
@ -2187,13 +2188,74 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer)
} }
} }
// NOTE: Render player avatar HUD // NOTE: Render the merchant menus =========================================
FP_GameEntity *player = FP_Game_GetEntity(game, game->player);
Dqn_V2 player_pos = FP_Game_CalcEntityWorldPos(game, game->player);
{
struct FP_MerchantToMenuMapping {
FP_GameEntityHandle merchant;
Dqn_String8 menu_anim;
} merchants[] = {
{game->merchant_terry, g_anim_names.merchant_terry_menu},
{game->merchant_graveyard, g_anim_names.merchant_graveyard_menu},
{game->merchant_gym, g_anim_names.merchant_gym_menu},
{game->merchant_phone_company, g_anim_names.merchant_phone_company_menu},
};
bool activated_merchant = false;
for (FP_MerchantToMenuMapping mapping : merchants) {
FP_GameEntityHandle merchant_handle = mapping.merchant;
Dqn_V2 world_pos = FP_Game_CalcEntityWorldPos(game, merchant_handle);
Dqn_f32 dist_squared = Dqn_V2_LengthSq_V2x2(world_pos, player_pos);
if (dist_squared > DQN_SQUARED(FP_Game_MetersToPixelsNx1(game, 4)))
continue;
activated_merchant = true;
FP_GameRenderSprite *sprite = &game->player_merchant_menu;
if (!sprite->asset.anim || sprite->asset.anim->label != mapping.menu_anim) {
sprite->asset = TELY_Asset_MakeAnimatedSprite(&game->atlas_sprite_sheet, mapping.menu_anim, TELY_AssetFlip_No);
sprite->started_at_clock_ms = game->clock_ms;
}
uint64_t elapsed_ms = game->clock_ms - sprite->started_at_clock_ms;
uint16_t raw_anim_frame = DQN_CAST(uint16_t)(elapsed_ms / sprite->asset.anim->ms_per_frame);
uint16_t anim_frame = raw_anim_frame % sprite->asset.anim->count;
Dqn_usize sprite_index = sprite->asset.anim->index + anim_frame;
Dqn_Rect src_rect = sprite->asset.sheet->rects.data[sprite_index];
Dqn_Rect dest_rect = {};
dest_rect.size = src_rect.size;
dest_rect.pos = world_pos - (dest_rect.size * .5f) - Dqn_V2_InitNx2(0.f, src_rect.size.y);
Dqn_f32 sin_t = DQN_SINF(DQN_CAST(Dqn_f32)input->timer_s * 3.f);
dest_rect.pos.y += sin_t * 4.f;
TELY_Render_TextureColourV4(renderer,
sprite->asset.sheet->tex_handle,
src_rect,
dest_rect,
Dqn_V2_Zero /*rotate origin*/,
0.f /*rotation*/,
TELY_COLOUR_WHITE_V4);
}
if (activated_merchant) {
game->active_menu = FP_GameActiveMenu_Merchant;
} else {
if (game->active_menu == FP_GameActiveMenu_Merchant) {
game->active_menu = FP_GameActiveMenu_Nil;
}
}
}
// NOTE: Render player avatar HUD ==========================================
Dqn_f32 ui_start_y = 32.f; Dqn_f32 ui_start_y = 32.f;
{ {
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); };
FP_GameEntity *player = FP_Game_GetEntity(game, game->player);
FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, FP_EntityType_Terry, FP_EntityTerryState_Idle, FP_GameDirection_Down); FP_EntityRenderData render_data = FP_Entity_GetRenderData(game, FP_EntityType_Terry, FP_EntityTerryState_Idle, FP_GameDirection_Down);
Dqn_Rect dest = {}; Dqn_Rect dest = {};
dest.size = render_data.render_size; dest.size = render_data.render_size;
@ -2212,7 +2274,9 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer)
Dqn_V2 next_pos = Dqn_Rect_InterpolatedPoint(dest, Dqn_V2_InitNx2(1.f, 0)); Dqn_V2 next_pos = Dqn_Rect_InterpolatedPoint(dest, Dqn_V2_InitNx2(1.f, 0));
TELY_Render_TextF(renderer, next_pos, Dqn_V2_Zero, "Terry"); TELY_Render_TextF(renderer, next_pos, Dqn_V2_Zero, "Terry");
next_pos.y += TELY_Render_FontHeight(renderer, &platform->assets); Dqn_f32 font_height = TELY_Render_FontHeight(renderer, &platform->assets);
next_pos.y += font_height;
TELY_Render_TextF(renderer, TELY_Render_TextF(renderer,
next_pos, next_pos,
Dqn_V2_Zero, Dqn_V2_Zero,
@ -2220,21 +2284,28 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer)
player->terry_mobile_data_plan, player->terry_mobile_data_plan,
player->terry_mobile_data_plan_cap); player->terry_mobile_data_plan_cap);
next_pos.y += TELY_Render_FontHeight(renderer, &platform->assets); next_pos.y += font_height;
TELY_Render_TextF(renderer, next_pos, Dqn_V2_Zero, "$%I64u", player->coins); TELY_Render_TextF(renderer, next_pos, Dqn_V2_Zero, "$%I64u", player->coins);
next_pos.y += font_height;
TELY_Render_TextF(renderer, next_pos, Dqn_V2_Zero, "[H] Build Menu");
next_pos.y += font_height;
TELY_Render_TextF(renderer, next_pos, Dqn_V2_Zero, "[Shift+WASD] Strafe");
next_pos.y += font_height;
TELY_Render_TextF(renderer, next_pos, Dqn_V2_Zero, "[Ctrl+WASD] Dash");
next_pos.y += font_height;
TELY_Render_TextF(renderer, next_pos, Dqn_V2_Zero, "[J|K] Melee/Range");
TELY_Render_PopFont(renderer); TELY_Render_PopFont(renderer);
} }
if (!FP_Game_IsNilEntityHandle(game, game->clicked_entity)) { if (!FP_Game_IsNilEntityHandle(game, game->clicked_entity) && game->active_menu == FP_GameActiveMenu_Build) {
// NOTE: Render building blueprint ========================================================= // NOTE: Render building blueprint =========================================================
if (game->build_mode) { {
FP_GameEntity *entity = FP_Game_GetEntity(game, game->clicked_entity); FP_GameEntity *entity = FP_Game_GetEntity(game, game->clicked_entity);
TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity());
Dqn_V2 label_p = Dqn_V2_InitNx2(platform->core.window_size.x * .5f, platform->core.window_size.y * .1f);
TELY_Render_Text(renderer, label_p, Dqn_V2_InitNx2(0.5f, 0.5f), DQN_STRING8("Build Mode"));
TELY_Render_PopTransform(renderer);
FP_GamePlaceableBuilding placeable_building = PLACEABLE_BUILDINGS[game->build_mode_building_index]; FP_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); 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_Rect dest_rect = FP_Game_GetBuildingPlacementRectForEntity(game, placeable_building, entity->handle);

View File

@ -60,7 +60,7 @@ struct FP_GlobalAnimations
Dqn_String8 merchant_button_y = DQN_STRING8("merchant_button_y"); Dqn_String8 merchant_button_y = DQN_STRING8("merchant_button_y");
Dqn_String8 merchant_graveyard = DQN_STRING8("merchant_graveyard"); Dqn_String8 merchant_graveyard = DQN_STRING8("merchant_graveyard");
Dqn_String8 merchant_graveyard_menu = DQN_STRING8("merchant_graveyard"); Dqn_String8 merchant_graveyard_menu = DQN_STRING8("merchant_graveyard_menu");
Dqn_String8 merchant_gym = DQN_STRING8("merchant_gym"); Dqn_String8 merchant_gym = DQN_STRING8("merchant_gym");
Dqn_String8 merchant_gym_menu = DQN_STRING8("merchant_gym_menu"); 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 = DQN_STRING8("merchant_phone_company");

View File

@ -228,6 +228,13 @@ enum FP_GameAudio
FP_GameAudio_Count, FP_GameAudio_Count,
}; };
enum FP_GameActiveMenu
{
FP_GameActiveMenu_Nil,
FP_GameActiveMenu_Build,
FP_GameActiveMenu_Merchant,
};
struct FP_Game struct FP_Game
{ {
Dqn_f32 delta_s_accumulator; Dqn_f32 delta_s_accumulator;
@ -244,13 +251,19 @@ struct FP_Game
Dqn_FArray<FP_GameEntityHandle, 8> parent_entity_stack; Dqn_FArray<FP_GameEntityHandle, 8> parent_entity_stack;
Dqn_VArray<FP_GameEntity> entities; Dqn_VArray<FP_GameEntity> entities;
TELY_AssetSpriteSheet atlas_sprite_sheet; TELY_AssetSpriteSheet atlas_sprite_sheet;
FP_GameEntity *root_entity; FP_GameEntity *root_entity;
FP_GameEntity *entity_free_list; FP_GameEntity *entity_free_list;
FP_GameEntity *map; FP_GameEntity *map;
FP_GameEntityHandle player; FP_GameEntityHandle player;
FP_GameRenderSprite player_merchant_menu;
FP_GameEntityHandle merchant_terry;
FP_GameEntityHandle merchant_graveyard;
FP_GameEntityHandle merchant_gym;
FP_GameEntityHandle merchant_phone_company;
FP_GameEntityHandle clicked_entity; FP_GameEntityHandle clicked_entity;
FP_GameEntityHandle hot_entity; FP_GameEntityHandle hot_entity;
@ -266,10 +279,11 @@ struct FP_Game
uint64_t clock_ms; uint64_t clock_ms;
Dqn_PCG32 rng; Dqn_PCG32 rng;
bool build_mode;
bool build_mode_can_place_building;
bool debug_ui; bool debug_ui;
FP_GameActiveMenu active_menu;
bool build_mode_can_place_building;
Dqn_usize build_mode_building_index; Dqn_usize build_mode_building_index;
}; };
struct FP_GameAStarNode struct FP_GameAStarNode