diff --git a/Data/Textures/atlas.txt b/Data/Textures/atlas.txt index e92c32d..d7e9b8f 100644 --- a/Data/Textures/atlas.txt +++ b/Data/Textures/atlas.txt @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7bdca69d3d7e98d739cb4922e95923218c65b3629f6aaf024efffb47fa75cd09 +oid sha256:e180b08d05e746ad49f01ff474c4755ac41d846c7f0520e1b4717ff653377cf2 size 4579 diff --git a/Data/Textures/sprite_spec.txt b/Data/Textures/sprite_spec.txt index d490acf..43b316c 100644 --- a/Data/Textures/sprite_spec.txt +++ b/Data/Textures/sprite_spec.txt @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:868bda4e10fd1a8f2d32f8b9cb5eea3ee25d1809b9820dd6d2caceae49d00a50 +oid sha256:44384e83bfbc0eef71126c2b4ee0aeb83ea41507391b20f22eeb56facc637e09 size 1333 diff --git a/feely_pona.cpp b/feely_pona.cpp index b2f0dee..a62cc31 100644 --- a/feely_pona.cpp +++ b/feely_pona.cpp @@ -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_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_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_right = Dqn_V2_InitNx2(base_bottom_right_pos.x, base_bottom_right_pos.y); - FP_Entity_CreateMerchantTerry(game, base_top_left, "Merchant"); - FP_Entity_CreateMerchantGraveyard(game, base_bottom_left, "Graveyard"); - FP_Entity_CreateMerchantGym(game, base_bottom_right, "Gym"); - FP_Entity_CreateMerchantPhoneCompany(game, base_top_right, "PhoneCompany"); + game->merchant_terry = FP_Entity_CreateMerchantTerry(game, base_top_left, "Merchant"); + game->merchant_graveyard = FP_Entity_CreateMerchantGraveyard(game, base_bottom_left, "Graveyard"); + game->merchant_gym = FP_Entity_CreateMerchantGym(game, base_bottom_right, "Gym"); + game->merchant_phone_company = FP_Entity_CreateMerchantPhoneCompany(game, base_top_right, "PhoneCompany"); } 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 (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_H)) - game->build_mode = !game->build_mode; + if (game->active_menu == FP_GameActiveMenu_Nil || game->active_menu == FP_GameActiveMenu_Build) { + 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) 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 (game->active_menu == FP_GameActiveMenu_Build) { 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); @@ -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) 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; { TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity()); 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); Dqn_Rect dest = {}; 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)); 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, next_pos, 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_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); + + 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); } - 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 ========================================================= - 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_GameEntity *entity = FP_Game_GetEntity(game, game->clicked_entity); 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); diff --git a/feely_pona.h b/feely_pona.h index d5504ec..6b40d0f 100644 --- a/feely_pona.h +++ b/feely_pona.h @@ -60,7 +60,7 @@ struct FP_GlobalAnimations 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_graveyard_menu = DQN_STRING8("merchant_graveyard_menu"); 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"); diff --git a/feely_pona_game.h b/feely_pona_game.h index 40dde60..77f9f2d 100644 --- a/feely_pona_game.h +++ b/feely_pona_game.h @@ -228,6 +228,13 @@ enum FP_GameAudio FP_GameAudio_Count, }; +enum FP_GameActiveMenu +{ + FP_GameActiveMenu_Nil, + FP_GameActiveMenu_Build, + FP_GameActiveMenu_Merchant, +}; + struct FP_Game { Dqn_f32 delta_s_accumulator; @@ -244,13 +251,19 @@ struct FP_Game Dqn_FArray parent_entity_stack; Dqn_VArray entities; - TELY_AssetSpriteSheet atlas_sprite_sheet; + TELY_AssetSpriteSheet atlas_sprite_sheet; FP_GameEntity *root_entity; FP_GameEntity *entity_free_list; FP_GameEntity *map; 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 hot_entity; @@ -266,10 +279,11 @@ struct FP_Game uint64_t clock_ms; Dqn_PCG32 rng; - bool build_mode; - bool build_mode_can_place_building; bool debug_ui; + FP_GameActiveMenu active_menu; + bool build_mode_can_place_building; Dqn_usize build_mode_building_index; + }; struct FP_GameAStarNode