diff --git a/Data/Textures/atlas.txt b/Data/Textures/atlas.txt index b4b1269..efdce85 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:49fa211b91a2075bd5f761386ac2e05efa68dce6d8f6e12fc0e7ad0c8c4232c7 +oid sha256:7e825367e12d0e2f48c80c843bfe4faba80473d8fde2af14cfec407fde5f7579 size 14174 diff --git a/Data/Textures/sprite_spec.txt b/Data/Textures/sprite_spec.txt index e24a077..c5940f3 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:ac6f59c0336437e0938eb9cd344f17f72d646da9122c61ae8cc502cfaae272ab +oid sha256:2ba632d5b14ef6b414f9d17fa86837a7e51d45fd62fc4152303c3620e8b7839e size 2260 diff --git a/feely_pona.cpp b/feely_pona.cpp index 027c2a6..e2576f3 100644 --- a/feely_pona.cpp +++ b/feely_pona.cpp @@ -2160,7 +2160,6 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input particle_desc.duration_ms = 1000; FP_EmitParticle(&game->play, particle_desc, Dqn_PCG32_Range(&game->play.rng, 1, 3)); - // NOTE: God mode override ========================================================= if (game->play.heart == defender->handle) { if (game->play.god_mode) @@ -2838,39 +2837,6 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer, } } - for (FP_Particle &particle_ : game->play.particles) { - FP_Particle *particle = &particle_; - if (!particle->alive) - continue; - - Dqn_usize elapsed_ms = game->play.clock_ms - particle->start_ms; - Dqn_usize duration_ms = particle->end_ms - particle->start_ms; - - Dqn_f32 t = DQN_MIN(1.f, elapsed_ms / DQN_CAST(Dqn_f32)duration_ms); - Dqn_V4 colour = {}; - colour.r = Dqn_Lerp_F32(particle->colour_begin.r, t, particle->colour_end.r); - colour.b = Dqn_Lerp_F32(particle->colour_begin.b, t, particle->colour_end.b); - colour.g = Dqn_Lerp_F32(particle->colour_begin.g, t, particle->colour_end.g); - colour.a = Dqn_Lerp_F32(particle->colour_begin.a, t, particle->colour_end.a); - - if (particle->anim_name.size) { - TELY_AssetSpriteAnimation *anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, particle->anim_name); - Dqn_Rect tex_rect = game->atlas_sprite_sheet.rects.data[anim->index]; - Dqn_Rect dest_rect = {}; - dest_rect.size = tex_rect.size; - dest_rect.pos = particle->pos - (tex_rect.size * .5f); - TELY_Render_TextureColourV4(renderer, - game->atlas_sprite_sheet.tex_handle, - tex_rect, - dest_rect, - Dqn_V2_Zero /*rotate origin*/, - 0.f /*rotation*/, - colour); - } else { - TELY_Render_CircleColourV4(renderer, particle->pos, 20.f, TELY_RenderShapeMode_Fill, colour); - } - } - // NOTE: Render overlay UI ===================================================================== if (!game->play.debug_hide_hud && (game->play.state == FP_GameState_Pause || game->play.state == FP_GameState_Play)) { @@ -2940,6 +2906,17 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer, } // NOTE: Render the player(s) HUD and merchant menu interaction ============================ + FP_ParticleDescriptor dollar_buy_particle = {}; + { + dollar_buy_particle.anim_name = g_anim_names.particle_purchase; + dollar_buy_particle.velocity.y = -16.f; + dollar_buy_particle.velocity_variance.y = (dollar_buy_particle.velocity.y * .5f); + dollar_buy_particle.velocity_variance.x = DQN_ABS(dollar_buy_particle.velocity.y); + dollar_buy_particle.colour_begin = TELY_COLOUR_WHITE_V4; + dollar_buy_particle.colour_end = TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, 0.f); + dollar_buy_particle.duration_ms = 2000; + } + Dqn_Rect first_player_avatar_rect = {}; DQN_FOR_UINDEX (player_index, game->play.players.size) { FP_GameEntityHandle player_handle = game->play.players.data[player_index]; @@ -3059,55 +3036,10 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer, { bool const have_enough_coins = player->coins >= *mapping.building_base_price; FP_GameKeyBind key_bind = player->controls.buy_building; - // NOTE: Buy trigger + animation =============================== - { - bool trigger_buy_anim = false; - - if (have_enough_coins) { - if (TELY_Platform_InputScanCodeIsPressed(input, key_bind.scan_code)) { - game->play.player_trigger_purchase_building_timestamp = game->play.clock_ms + buy_duration_ms; - } else if (TELY_Platform_InputScanCodeIsDown(input, key_bind.scan_code)) { - trigger_buy_anim = true; - if (game->play.clock_ms > game->play.player_trigger_purchase_building_timestamp) - game->play.player_trigger_purchase_building_timestamp = game->play.clock_ms; - } else if (TELY_Platform_InputScanCodeIsReleased(input, key_bind.scan_code)) { - if (game->play.clock_ms > game->play.player_trigger_purchase_building_timestamp) { - if (mapping.inventory_count) { - player->coins -= *mapping.building_base_price; - TELY_Audio_Play(audio, game->audio[FP_GameAudio_Ching], 1.f); - *mapping.building_base_price *= 1; - - // NOTE: Raise the prices of everything else - invent->airports_base_price *= 1; - invent->clubs_base_price *= 1; - invent->kennels_base_price *= 1; - invent->churchs_base_price *= 1; - - (*mapping.inventory_count)++; - } - } else { - game->play.player_trigger_purchase_building_timestamp = UINT64_MAX; - } - } - - if (trigger_buy_anim) { - uint64_t start_buy_time = game->play.player_trigger_purchase_building_timestamp - buy_duration_ms; - uint64_t elapsed_time = game->play.clock_ms - start_buy_time; - - Dqn_f32 buy_t = DQN_MIN(elapsed_time / DQN_CAST(Dqn_f32)buy_duration_ms, 1.f); - Dqn_Rect buy_lerp_rect = {}; - buy_lerp_rect.pos = Dqn_Rect_InterpolatedPoint(merchant_menu_rect, Dqn_V2_InitNx2(0.297f, 0.215f)); - buy_lerp_rect.size.w = (merchant_menu_rect.size.w * 0.38f) * buy_t; - buy_lerp_rect.size.h = merchant_menu_rect.size.h * .611f; - - TELY_Render_RectColourV4(renderer, buy_lerp_rect, TELY_RenderShapeMode_Fill, TELY_Colour_V4Alpha(TELY_COLOUR_BLUE_CADET_V4, 0.5f)); - } - } - - } // NOTE: Render the (A) button ================================= - Dqn_V4 tex_mod_colour = have_enough_coins ? TELY_COLOUR_WHITE_V4 : TELY_Colour_V4Alpha(TELY_COLOUR_RED_TOMATO_V4, .5f); + Dqn_V2 dollar_text_label_pos = {}; + Dqn_V4 tex_mod_colour = have_enough_coins ? TELY_COLOUR_WHITE_V4 : TELY_Colour_V4Alpha(TELY_COLOUR_RED_TOMATO_V4, .5f); { // NOTE: Render the interaction button Dqn_Rect interact_btn_rect = {}; @@ -3143,9 +3075,60 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer, } // NOTE: Render the $ cost - TELY_Render_TextF(renderer, Dqn_Rect_InterpolatedPoint(interact_btn_rect, Dqn_V2_InitNx2(0.5f, -0.8f)), Dqn_V2_InitNx2(0.5, 0.f), "$%u", *mapping.building_base_price); + dollar_text_label_pos = Dqn_Rect_InterpolatedPoint(interact_btn_rect, Dqn_V2_InitNx2(0.5f, -0.8f)); + TELY_Render_TextF(renderer, dollar_text_label_pos, Dqn_V2_InitNx2(0.5, 0.f), "$%u", *mapping.building_base_price); } + // NOTE: Buy trigger + animation =========================================== + { + bool trigger_buy_anim = false; + + if (have_enough_coins) { + if (TELY_Platform_InputScanCodeIsPressed(input, key_bind.scan_code)) { + game->play.player_trigger_purchase_building_timestamp = game->play.clock_ms + buy_duration_ms; + } else if (TELY_Platform_InputScanCodeIsDown(input, key_bind.scan_code)) { + trigger_buy_anim = true; + if (game->play.clock_ms > game->play.player_trigger_purchase_building_timestamp) + game->play.player_trigger_purchase_building_timestamp = game->play.clock_ms; + } else if (TELY_Platform_InputScanCodeIsReleased(input, key_bind.scan_code)) { + if (game->play.clock_ms > game->play.player_trigger_purchase_building_timestamp) { + if (mapping.inventory_count) { + player->coins -= *mapping.building_base_price; + TELY_Audio_Play(audio, game->audio[FP_GameAudio_Ching], 1.f); + *mapping.building_base_price *= 1; + + // NOTE: Raise the prices of everything else + invent->airports_base_price *= 1; + invent->clubs_base_price *= 1; + invent->kennels_base_price *= 1; + invent->churchs_base_price *= 1; + + (*mapping.inventory_count)++; + + dollar_buy_particle.pos = dollar_text_label_pos; + FP_EmitParticle(&game->play, dollar_buy_particle, 1); + } + } else { + game->play.player_trigger_purchase_building_timestamp = UINT64_MAX; + } + } + + if (trigger_buy_anim) { + uint64_t start_buy_time = game->play.player_trigger_purchase_building_timestamp - buy_duration_ms; + uint64_t elapsed_time = game->play.clock_ms - start_buy_time; + + Dqn_f32 buy_t = DQN_MIN(elapsed_time / DQN_CAST(Dqn_f32)buy_duration_ms, 1.f); + Dqn_Rect buy_lerp_rect = {}; + buy_lerp_rect.pos = Dqn_Rect_InterpolatedPoint(merchant_menu_rect, Dqn_V2_InitNx2(0.297f, 0.215f)); + buy_lerp_rect.size.w = (merchant_menu_rect.size.w * 0.38f) * buy_t; + buy_lerp_rect.size.h = merchant_menu_rect.size.h * .611f; + + TELY_Render_RectColourV4(renderer, buy_lerp_rect, TELY_RenderShapeMode_Fill, TELY_Colour_V4Alpha(TELY_COLOUR_BLUE_CADET_V4, 0.5f)); + } + } + } + + // NOTE: Render the merchant shop item building ================ { TELY_AssetSpriteAnimation *anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, mapping.building); @@ -3167,55 +3150,10 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer, { bool const have_enough_coins = player->coins >= *mapping.upgrade_base_price; FP_GameKeyBind key_bind = player->controls.buy_upgrade; - // NOTE: Buy trigger + animation =============================== - { - bool trigger_buy_anim = false; - - if (have_enough_coins) { - if (TELY_Platform_InputScanCodeIsPressed(input, key_bind.scan_code)) { - game->play.player_trigger_purchase_upgrade_timestamp = game->play.clock_ms + buy_duration_ms; - } else if (TELY_Platform_InputScanCodeIsDown(input, key_bind.scan_code)) { - trigger_buy_anim = true; - if (game->play.clock_ms > game->play.player_trigger_purchase_upgrade_timestamp) - game->play.player_trigger_purchase_upgrade_timestamp = game->play.clock_ms; - } else if (TELY_Platform_InputScanCodeIsReleased(input, key_bind.scan_code)) { - if (game->play.clock_ms > game->play.player_trigger_purchase_upgrade_timestamp) { - player->coins -= *mapping.upgrade_base_price; - *mapping.upgrade_base_price *= 1; - TELY_Audio_Play(audio, game->audio[FP_GameAudio_Ching], 1.f); - - if (mapping.merchant == game->play.merchant_terry) { - player->base_attack += DQN_CAST(uint32_t)(FP_DEFAULT_DAMAGE * 1.2f); - } else if (mapping.merchant == game->play.merchant_graveyard) { - player->stamina_cap += DQN_CAST(uint32_t)(FP_TERRY_DASH_STAMINA_COST * .5f); - } else if (mapping.merchant == game->play.merchant_gym) { - player->hp_cap += FP_DEFAULT_DAMAGE; - player->hp = player->hp_cap; - } else if (mapping.merchant == game->play.merchant_phone_company) { - player->terry_mobile_data_plan_cap += DQN_KILOBYTES(1); - } - } else { - game->play.player_trigger_purchase_upgrade_timestamp = UINT64_MAX; - } - } - - if (trigger_buy_anim) { - uint64_t start_buy_time = game->play.player_trigger_purchase_upgrade_timestamp - buy_duration_ms; - uint64_t elapsed_time = game->play.clock_ms - start_buy_time; - - Dqn_f32 buy_t = DQN_MIN(elapsed_time / DQN_CAST(Dqn_f32)buy_duration_ms, 1.f); - Dqn_Rect buy_lerp_rect = {}; - buy_lerp_rect.pos = Dqn_Rect_InterpolatedPoint(merchant_menu_rect, Dqn_V2_InitNx2(0.68f, 0.215f)); - buy_lerp_rect.size.w = (merchant_menu_rect.size.w * 0.211f) * buy_t; - buy_lerp_rect.size.h = merchant_menu_rect.size.h * .611f; - - TELY_Render_RectColourV4(renderer, buy_lerp_rect, TELY_RenderShapeMode_Fill, TELY_Colour_V4Alpha(TELY_COLOUR_RED_TOMATO_V4, 0.5f)); - } - } - } // NOTE: Render the (B) button ================================= Dqn_V4 tex_mod_colour = have_enough_coins ? TELY_COLOUR_WHITE_V4 : TELY_Colour_V4Alpha(TELY_COLOUR_RED_TOMATO_V4, .5f); + Dqn_V2 dollar_text_label_pos = {}; { Dqn_V2 interp_pos01 = Dqn_V2_InitNx2(0.7f, 0.41f); Dqn_Rect interact_btn_rect = {}; @@ -3268,9 +3206,60 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer, } // NOTE: Render the $ cost - TELY_Render_TextF(renderer, Dqn_Rect_InterpolatedPoint(interact_btn_rect, Dqn_V2_InitNx2(1.f, -0.8f)), Dqn_V2_InitNx2(0.5, 0.f), "$%u", *mapping.upgrade_base_price); + dollar_text_label_pos = Dqn_Rect_InterpolatedPoint(interact_btn_rect, Dqn_V2_InitNx2(1.f, -0.8f)); + TELY_Render_TextF(renderer, dollar_text_label_pos, Dqn_V2_InitNx2(0.5, 0.f), "$%u", *mapping.upgrade_base_price); } + + // NOTE: Buy trigger + animation =========================================== + { + bool trigger_buy_anim = false; + + if (have_enough_coins) { + if (TELY_Platform_InputScanCodeIsPressed(input, key_bind.scan_code)) { + game->play.player_trigger_purchase_upgrade_timestamp = game->play.clock_ms + buy_duration_ms; + } else if (TELY_Platform_InputScanCodeIsDown(input, key_bind.scan_code)) { + trigger_buy_anim = true; + if (game->play.clock_ms > game->play.player_trigger_purchase_upgrade_timestamp) + game->play.player_trigger_purchase_upgrade_timestamp = game->play.clock_ms; + } else if (TELY_Platform_InputScanCodeIsReleased(input, key_bind.scan_code)) { + if (game->play.clock_ms > game->play.player_trigger_purchase_upgrade_timestamp) { + player->coins -= *mapping.upgrade_base_price; + *mapping.upgrade_base_price *= 1; + TELY_Audio_Play(audio, game->audio[FP_GameAudio_Ching], 1.f); + + dollar_buy_particle.pos = dollar_text_label_pos; + FP_EmitParticle(&game->play, dollar_buy_particle, 1); + + if (mapping.merchant == game->play.merchant_terry) { + player->base_attack += DQN_CAST(uint32_t)(FP_DEFAULT_DAMAGE * 1.2f); + } else if (mapping.merchant == game->play.merchant_graveyard) { + player->stamina_cap += DQN_CAST(uint32_t)(FP_TERRY_DASH_STAMINA_COST * .5f); + } else if (mapping.merchant == game->play.merchant_gym) { + player->hp_cap += FP_DEFAULT_DAMAGE; + player->hp = player->hp_cap; + } else if (mapping.merchant == game->play.merchant_phone_company) { + player->terry_mobile_data_plan_cap += DQN_KILOBYTES(1); + } + } else { + game->play.player_trigger_purchase_upgrade_timestamp = UINT64_MAX; + } + } + + if (trigger_buy_anim) { + uint64_t start_buy_time = game->play.player_trigger_purchase_upgrade_timestamp - buy_duration_ms; + uint64_t elapsed_time = game->play.clock_ms - start_buy_time; + + Dqn_f32 buy_t = DQN_MIN(elapsed_time / DQN_CAST(Dqn_f32)buy_duration_ms, 1.f); + Dqn_Rect buy_lerp_rect = {}; + buy_lerp_rect.pos = Dqn_Rect_InterpolatedPoint(merchant_menu_rect, Dqn_V2_InitNx2(0.68f, 0.215f)); + buy_lerp_rect.size.w = (merchant_menu_rect.size.w * 0.211f) * buy_t; + buy_lerp_rect.size.h = merchant_menu_rect.size.h * .611f; + + TELY_Render_RectColourV4(renderer, buy_lerp_rect, TELY_RenderShapeMode_Fill, TELY_Colour_V4Alpha(TELY_COLOUR_RED_TOMATO_V4, 0.5f)); + } + } + } } } @@ -3830,6 +3819,44 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer, FP_GameRenderScanlines(renderer, scanline_gap, scanline_thickness, window_rect.size); } + for (FP_Particle &particle_ : game->play.particles) { + FP_Particle *particle = &particle_; + if (!particle->alive) + continue; + + Dqn_usize elapsed_ms = game->play.clock_ms - particle->start_ms; + Dqn_usize duration_ms = particle->end_ms - particle->start_ms; + + Dqn_f32 t = DQN_MIN(1.f, elapsed_ms / DQN_CAST(Dqn_f32)duration_ms); + Dqn_V4 colour = {}; + colour.r = Dqn_Lerp_F32(particle->colour_begin.r, t, particle->colour_end.r); + colour.b = Dqn_Lerp_F32(particle->colour_begin.b, t, particle->colour_end.b); + colour.g = Dqn_Lerp_F32(particle->colour_begin.g, t, particle->colour_end.g); + colour.a = Dqn_Lerp_F32(particle->colour_begin.a, t, particle->colour_end.a); + + if (particle->anim_name.size) { + TELY_AssetSpriteAnimation *anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, particle->anim_name); + uint16_t const raw_anim_frame = DQN_CAST(uint16_t)(elapsed_ms / anim->ms_per_frame); + uint16_t anim_frame = raw_anim_frame % anim->count; + + Dqn_Rect tex_rect = game->atlas_sprite_sheet.rects.data[anim->index + anim_frame]; + Dqn_Rect dest_rect = {}; + dest_rect.size = tex_rect.size; + dest_rect.pos = particle->pos - (tex_rect.size * .5f); + + TELY_Render_TextureColourV4(renderer, + game->atlas_sprite_sheet.tex_handle, + tex_rect, + dest_rect, + Dqn_V2_Zero /*rotate origin*/, + 0.f /*rotation*/, + colour); + } else { + TELY_Render_CircleColourV4(renderer, particle->pos, 20.f, TELY_RenderShapeMode_Fill, colour); + } + } + + // NOTE: Debug UI ============================================================================== DQN_MSVC_WARNING_PUSH DQN_MSVC_WARNING_DISABLE(4127) // Conditional expression is constant 'FP_DEVELOPER_MODE'