6 Commits
8 changed files with 183 additions and 76 deletions

No files matched your search

BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
+162 -66
View File
@@ -550,6 +550,8 @@ void TELY_DLL_Init(void *user_data)
controls->build_mode.scan_code = TELY_PlatformInputScanCode_H;
controls->strafe.scan_code = TELY_PlatformInputScanCode_L;
controls->dash.scan_code = TELY_PlatformInputScanCode_N;
controls->buy_building.scan_code = TELY_PlatformInputScanCode_U;
controls->buy_upgrade.scan_code = TELY_PlatformInputScanCode_I;
}
struct FP_GetClosestPortalMonkeyResult
@@ -650,7 +652,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
}
if (we_are_clicked_entity) {
if (game->play.in_game_menu == FP_GameInGameMenu_Nil) {
if (game->play.in_game_menu != FP_GameInGameMenu_Build) {
bool picked_up_monkey_this_frame = false;
if (FP_Game_IsNilEntityHandle(game, entity->carried_monkey)) {
// NOTE: Check if we are nearby a monkey and picking it up
@@ -718,7 +720,7 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
if (we_are_clicked_entity) {
bool picked_up_monkey_this_frame = false;
if (game->play.in_game_menu == FP_GameInGameMenu_Nil) {
if (game->play.in_game_menu != FP_GameInGameMenu_Build) {
if (FP_Game_IsNilEntityHandle(game, entity->carried_monkey)) {
// NOTE: Check if we are nearby a monkey and picking it up
FP_GetClosestPortalMonkeyResult closest_monkey = FP_GetClosestPortalMonkey(game, entity->handle);
@@ -975,9 +977,8 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
case FP_EntityClingerState_Death: {
if (entering_new_state) {
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, g_anim_names.clinger_death, TELY_AssetFlip_No);
uint64_t duration_ms = sprite.anim->count * sprite.anim->ms_per_frame;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
uint64_t duration_ms = render_data.sprite.anim->count * render_data.sprite.anim->ms_per_frame;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite);
entity->local_hit_box_size = {};
}
@@ -1240,9 +1241,8 @@ void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Platform
case FP_EntityCatfishState_Run: {
if (entering_new_state || action->sprite.anim->label != render_data.anim_name) {
TELY_AssetAnimatedSprite sprite = TELY_Asset_MakeAnimatedSprite(sheet, render_data.anim_name, render_data.flip);
uint64_t duration_ms = FP_GAME_ENTITY_ACTION_INFINITE_TIMER;
FP_Game_EntityActionReset(game, entity->handle, duration_ms, sprite);
FP_Game_EntityActionReset(game, entity->handle, duration_ms, render_data.sprite);
}
if (we_are_clicked_entity) {
@@ -1995,26 +1995,8 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
}
if (entity->flags & FP_GameEntityFlag_CameraTracking) {
FP_GameCamera *camera = &game->play.camera;
// NOTE: calculate camera position based on camera shake
Dqn_V2 camera_position = camera->world_pos;
if (camera->shake_duration > 0) {
Dqn_f32 offset_x = (Dqn_PCG32_NextF32(&game->play.rng) * 1000 - 500) * camera->shake_intensity;
Dqn_f32 offset_y = (Dqn_PCG32_NextF32(&game->play.rng) * 1000 - 500) * camera->shake_intensity;
camera_position.x += offset_x;
camera_position.y += offset_y;
camera->shake_duration -= input->delta_s;
}
Dqn_f64 camera_smoothing = 5.0f;
camera->world_pos.x += (camera_position.x - camera->world_pos.x) * (camera_smoothing * input->delta_s);
camera->world_pos.y += (camera_position.y - camera->world_pos.y) * (camera_smoothing * input->delta_s);
camera->world_pos_target = FP_Game_CalcEntityWorldPos(game, entity->handle) * camera->scale;
game->play.camera_tracking_entity = entity->handle;
game->play.camera.world_pos_target = FP_Game_CalcEntityWorldPos(game, entity->handle) * game->play.camera.scale;
}
FP_GamePlaceableBuilding placeable_building = PLACEABLE_BUILDINGS[game->play.build_mode_building_index];
@@ -2149,6 +2131,8 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
}
}
entity->trauma01 = DQN_MAX(0.f, entity->trauma01 - 0.05f);
// NOTE: Derive dynmamic bounding boxes ====================================================
if (entity->flags & FP_GameEntityFlag_DeriveHitBoxFromChildrenBoundingBox) {
Dqn_Rect children_bbox = {};
@@ -2263,12 +2247,8 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
}
defender->hp = defender->hp >= attacker->base_attack ? defender->hp - attacker->base_attack : 0;
defender->hit_on_frame = game->play.update_counter;
if (game->play.player == defender->handle) {
game->play.camera.shake_intensity = 0.1f;
game->play.camera.shake_duration = 0.25f;
}
defender->hit_on_clock_ms = game->play.update_counter;
defender->trauma01 = 1.f - (defender->hp / DQN_CAST(Dqn_f32)defender->hp_cap);
if (defender->hp <= 0) {
if (!defender->is_dying) {
@@ -2352,7 +2332,29 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
TELY_RFui_PushFont(rfui, game->jetbrains_mono_font);
TELY_RFui_PushLabelColourV4(rfui, TELY_COLOUR_BLACK_MIDNIGHT_V4);
FP_GameCameraM2x3 camera_xforms = FP_Game_CameraModelViewM2x3(game->play.camera);
FP_GameCamera shake_camera = game->play.camera;
FP_GameEntity *camera_entity = FP_Game_GetEntity(game, game->play.camera_tracking_entity);
{
// NOTE: Calculate camera position based on camera shake
Dqn_f32 trauma01 = DQN_SQUARED(camera_entity->trauma01);
if (camera_entity->type == FP_EntityType_Terry) {
// NOTE: The heart shake is trauma^3 to emphasise the severity of losing heart health
FP_GameEntity *heart = FP_Game_GetEntity(game, game->play.heart);
trauma01 = DQN_MAX(trauma01, DQN_SQUARED(heart->trauma01) * heart->trauma01);
}
Dqn_f32 max_shake_dist = 400.f;
Dqn_f32 half_shake_dist = max_shake_dist * .5f;
Dqn_V2 shake_offset = {};
shake_offset.x = (Dqn_PCG32_NextF32(&game->play.rng) * max_shake_dist - half_shake_dist) * trauma01;
shake_offset.y = (Dqn_PCG32_NextF32(&game->play.rng) * max_shake_dist - half_shake_dist) * trauma01;
Dqn_f32 interp_rate = 5.0f * DQN_CAST(Dqn_f32)input->delta_s;
shake_camera.world_pos += shake_offset * interp_rate;
}
FP_GameCameraM2x3 camera_xforms = FP_Game_CameraModelViewM2x3(shake_camera);
TELY_Render_PushTransform(renderer, camera_xforms.model_view);
Dqn_V2 world_mouse_p = Dqn_M2x3_MulV2(camera_xforms.view_model, input->mouse_p);
@@ -2375,6 +2377,7 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
TELY_Render_PushColourV4(renderer, TELY_COLOUR_BLACK_V4);
// NOTE: Draw entities =========================================================================
Dqn_V4 const colour_accent_yellow = TELY_Colour_V4InitRGBU32(0xFFE726);
for (FP_GameEntityIterator it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &it, game->play.root_entity); ) {
FP_GameEntity *entity = it.entity;
if (entity->flags & FP_GameEntityFlag_OccupiedInBuilding)
@@ -2459,14 +2462,14 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
dest_rect.size.h *= -1.f; // NOTE: Flip the texture vertically
Dqn_V4 sprite_colour = TELY_COLOUR_WHITE_V4;
if (entity->hit_on_frame) {
DQN_ASSERT(game->play.update_counter >= entity->hit_on_frame);
Dqn_usize frames_elapsed_since_hit = game->play.update_counter - entity->hit_on_frame;
Dqn_usize const HIT_CONFIRM_DURATION = 8;
if (frames_elapsed_since_hit < HIT_CONFIRM_DURATION) {
if (entity->hit_on_clock_ms) {
DQN_ASSERT(game->play.clock_ms >= entity->hit_on_clock_ms);
Dqn_usize ms_since_hit = game->play.clock_ms - entity->hit_on_clock_ms;
Dqn_usize const HIT_CONFIRM_DURATION_MS = 8 * 16;
if (ms_since_hit < HIT_CONFIRM_DURATION_MS) {
sprite_colour = TELY_COLOUR_RED_V4;
sprite_colour.g = ((1.f / HIT_CONFIRM_DURATION) * frames_elapsed_since_hit);
sprite_colour.b = ((1.f / HIT_CONFIRM_DURATION) * frames_elapsed_since_hit);
sprite_colour.g = ((1.f / HIT_CONFIRM_DURATION_MS) * ms_since_hit);
sprite_colour.b = ((1.f / HIT_CONFIRM_DURATION_MS) * ms_since_hit);
}
}
@@ -2483,7 +2486,6 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
Dqn_V2 label_p = Dqn_Rect_InterpolatedPoint(dest_rect, Dqn_V2_InitNx2(0, -0.25f));
TELY_Render_TextF(renderer, label_p, Dqn_V2_InitNx2(0.f, 0.1f), "CONVERTED");
}
}
DQN_FOR_UINDEX(anim_index, entity->extra_cosmetic_anims.size) {
@@ -2661,7 +2663,7 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
case FP_EntityBillboardState_Attack: {
key_bind = &game->controls.attack;
draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.65f, 0.2f));
colour = TELY_Colour_V4InitRGBU32(0xFFE726);
colour = colour_accent_yellow;
} break;
case FP_EntityBillboardState_Dash: {
@@ -2709,9 +2711,14 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
Dqn_V2 player_pos = FP_Game_CalcEntityWorldPos(game, game->play.player);
{
static bool sound_played_flags[4] = {false, false, false, false};
FP_GameInventory *invent = &player->inventory;
FP_GamePlay *play = &game->play;
struct FP_MerchantToMenuMapping {
FP_GameEntityHandle merchant;
Dqn_V2 *menu_pos;
Dqn_String8 upgrade_icon;
Dqn_String8 menu_anim;
Dqn_String8 building;
Dqn_V2 building_offset01;
@@ -2721,10 +2728,10 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
FP_GameAudio audio_type;
bool *sound_played;
} merchants[] = {
{game->play.merchant_terry, g_anim_names.merchant_terry_menu, g_anim_names.club_terry_dark, Dqn_V2_InitNx2(0.015f, +0.04f), &invent->clubs, &invent->clubs_base_price, &invent->health_base_price, FP_GameAudio_MerchantTerry, &sound_played_flags[0]},
{game->play.merchant_graveyard, g_anim_names.merchant_graveyard_menu, g_anim_names.church_terry_dark, Dqn_V2_InitNx2(0.04f, -0.15f), &invent->churchs, &invent->churchs_base_price, &invent->stamina_base_price, FP_GameAudio_MerchantGhost, &sound_played_flags[1]},
{game->play.merchant_gym, g_anim_names.merchant_gym_menu, g_anim_names.kennel_terry, Dqn_V2_InitNx2(0, +0), &invent->kennels, &invent->kennels_base_price, &invent->attack_base_price, FP_GameAudio_MerchantGym, &sound_played_flags[2]},
{game->play.merchant_phone_company, g_anim_names.merchant_phone_company_menu, g_anim_names.airport_terry, Dqn_V2_InitNx2(0, -0.1f), &invent->airports, &invent->airports_base_price, &invent->mobile_plan_base_price, FP_GameAudio_MerchantPhone, &sound_played_flags[3]},
{play->merchant_terry, &play->merchant_terry_menu_pos, g_anim_names.icon_attack, g_anim_names.merchant_terry_menu, g_anim_names.club_terry_dark, Dqn_V2_InitNx2(0.015f, +0.04f), &invent->clubs, &invent->clubs_base_price, &invent->health_base_price, FP_GameAudio_MerchantTerry, &sound_played_flags[0]},
{play->merchant_graveyard, &play->merchant_graveyard_menu_pos, g_anim_names.icon_stamina, g_anim_names.merchant_graveyard_menu, g_anim_names.church_terry_dark, Dqn_V2_InitNx2(0.04f, -0.15f), &invent->churchs, &invent->churchs_base_price, &invent->stamina_base_price, FP_GameAudio_MerchantGhost, &sound_played_flags[1]},
{play->merchant_gym, &play->merchant_gym_menu_pos, g_anim_names.icon_health, g_anim_names.merchant_gym_menu, g_anim_names.kennel_terry, Dqn_V2_InitNx2(0, +0), &invent->kennels, &invent->kennels_base_price, &invent->attack_base_price, FP_GameAudio_MerchantGym, &sound_played_flags[2]},
{play->merchant_phone_company, &play->merchant_phone_company_menu_pos, g_anim_names.icon_phone, g_anim_names.merchant_phone_company_menu, g_anim_names.airport_terry, Dqn_V2_InitNx2(0, -0.1f), &invent->airports, &invent->airports_base_price, &invent->mobile_plan_base_price, FP_GameAudio_MerchantPhone, &sound_played_flags[3]},
};
bool activated_merchant = false;
@@ -2755,8 +2762,30 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
Dqn_usize sprite_index = sprite->asset.anim->index + anim_frame;
Dqn_Rect src_rect = sprite->asset.sheet->rects.data[sprite_index];
if (*mapping.menu_pos == Dqn_V2_Zero)
*mapping.menu_pos = world_pos;
Dqn_Rect top_rect = Dqn_Rect_InitV2x2(world_pos - (src_rect.size * .5f) - Dqn_V2_InitNx2(0.f, src_rect.size.h), src_rect.size);
Dqn_Rect bottom_rect = Dqn_Rect_InitV2x2(world_pos - (src_rect.size * .5f) + Dqn_V2_InitNx2(0.f, src_rect.size.h), src_rect.size);
// NOTE: Move the merchant menu if we overlap with it so as to not occlude the player
{
Dqn_V2 target_pos = {};
Dqn_Rect camera_entity_hit_box = FP_Game_CalcEntityWorldHitBox(game, camera_entity->handle);
if (Dqn_Rect_Intersects(top_rect, camera_entity_hit_box)) {
target_pos = bottom_rect.pos;
} else {
target_pos = top_rect.pos;
}
// NOTE: Interpolate the menu position
*mapping.menu_pos += (target_pos - *mapping.menu_pos) * (24.f * DQN_CAST(Dqn_f32)input->delta_s);
}
merchant_menu_rect.size = src_rect.size;
merchant_menu_rect.pos = world_pos - (merchant_menu_rect.size * .5f) - Dqn_V2_InitNx2(0.f, src_rect.size.y);
merchant_menu_rect.pos = *mapping.menu_pos;
// NOTE: Bob the merchant menu
Dqn_f32 sin_t = DQN_SINF(DQN_CAST(Dqn_f32)input->timer_s * 3.f);
merchant_menu_rect.pos.y += sin_t * 4.f;
@@ -2774,7 +2803,7 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
}
}
TELY_Render_PushColourV4(renderer, TELY_COLOUR_WHITE_V4);
TELY_Render_PushColourV4(renderer, TELY_COLOUR_BLACK_V4);
TELY_Render_PushFont(renderer, game->talkco_font_large);
DQN_DEFER {
TELY_Render_PopFont(renderer);
@@ -2783,21 +2812,22 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
// NOTE: Render the merchant button for buildings ==================
uint64_t const buy_duration_ms = 500;
Dqn_V4 keybind_btn_shadow_colour = Dqn_V4_InitNx4(0.4f, 0.4f, 0.4f, 1.f);
{
bool const have_enough_coins = player->coins >= *mapping.building_base_price;
FP_GameKeyBind key_bind = game->controls.buy_building;
// NOTE: Buy trigger + animation ===============================
{
TELY_PlatformInputScanCode key = game->controls.attack.scan_code;
bool trigger_buy_anim = false;
if (have_enough_coins) {
if (TELY_Platform_InputScanCodeIsPressed(input, key)) {
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)) {
} 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)) {
} 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;
@@ -2835,21 +2865,45 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
// 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);
{
// NOTE: Render the gamepad button
Dqn_Rect gamepad_btn_rect = {};
{
TELY_AssetSpriteAnimation *anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.merchant_button_a);
Dqn_Rect button_rect = game->atlas_sprite_sheet.rects.data[anim->index];
Dqn_Rect dest_rect = {};
dest_rect.size = button_rect.size * 1.5f;
dest_rect.pos = Dqn_Rect_InterpolatedPoint(merchant_menu_rect, Dqn_V2_InitNx2(0.345f, 0.5f));
gamepad_btn_rect.size = button_rect.size * 1.5f;
gamepad_btn_rect.pos = Dqn_Rect_InterpolatedPoint(merchant_menu_rect, Dqn_V2_InitNx2(0.345f, 0.41f));
TELY_Render_TextureColourV4(renderer,
game->atlas_sprite_sheet.tex_handle,
button_rect,
dest_rect,
gamepad_btn_rect,
Dqn_V2_Zero /*rotate origin*/,
0.f /*rotation*/,
tex_mod_colour);
}
TELY_Render_TextF(renderer, Dqn_Rect_InterpolatedPoint(dest_rect, Dqn_V2_InitNx2(0.5f, -1)), Dqn_V2_InitNx2(0.5, 0.f), "$%u", *mapping.building_base_price);
// NOTE: Render the $ cost
TELY_Render_TextF(renderer, Dqn_Rect_InterpolatedPoint(gamepad_btn_rect, Dqn_V2_InitNx2(0.5f, -0.8f)), Dqn_V2_InitNx2(0.5, 0.f), "$%u", *mapping.building_base_price);
// NOTE: Render the keyboard binding =======================================
{
DQN_ASSERT(key_bind.scan_code >= TELY_PlatformInputScanCode_A && key_bind.scan_code <= TELY_PlatformInputScanCode_Z);
char scan_code_ch = DQN_CAST(char)('A' + (key_bind.scan_code - TELY_PlatformInputScanCode_A));
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
TELY_AssetFont const *font = TELY_Render_Font(renderer, assets);
Dqn_String8 key_bind_label = Dqn_String8_InitF(scratch.allocator, "[%c]", scan_code_ch);
Dqn_Rect key_bind_rect = {};
key_bind_rect.pos = Dqn_Rect_InterpolatedPoint(gamepad_btn_rect, Dqn_V2_InitNx2(-0.1f, 1.1f));
key_bind_rect.size = TELY_Asset_MeasureText(font, key_bind_label);
key_bind_rect = Dqn_Rect_Expand(key_bind_rect, 2.f);
TELY_Render_PushColourV4(renderer, TELY_Colour_V4Alpha(colour_accent_yellow, tex_mod_colour.a));
TELY_Render_RectColourV4(renderer, key_bind_rect, TELY_RenderShapeMode_Fill, TELY_Colour_V4Alpha(keybind_btn_shadow_colour, tex_mod_colour.a));
TELY_Render_Text(renderer, Dqn_Rect_InterpolatedPoint(key_bind_rect, Dqn_V2_InitNx1(0.5f)), Dqn_V2_InitNx1(0.5f), key_bind_label);
TELY_Render_PopColourV4(renderer);
}
}
// NOTE: Render the merchant shop item building ================
@@ -2872,26 +2926,25 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
// NOTE: Render the merchant button for buildings
{
bool const have_enough_coins = player->coins >= *mapping.upgrade_base_price;
FP_GameKeyBind key_bind = game->controls.buy_upgrade;
// NOTE: Buy trigger + animation ===============================
{
TELY_PlatformInputScanCode key = game->controls.range_attack.scan_code;
bool trigger_buy_anim = false;
if (have_enough_coins) {
if (TELY_Platform_InputScanCodeIsPressed(input, key)) {
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)) {
} 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)) {
} 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) {
// TODO(doyle): Attack damage? Or increase attack range?
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);
@@ -2923,12 +2976,33 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
// 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 interp_pos01 = {};
Dqn_Rect gamepad_btn_rect = {};
// NOTE: Render the gamepad button
{
TELY_AssetSpriteAnimation *anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.merchant_button_b);
Dqn_Rect button_rect = game->atlas_sprite_sheet.rects.data[anim->index];
interp_pos01 = Dqn_V2_InitNx2(0.71f, 0.41f);
gamepad_btn_rect.size = button_rect.size * 1.5f;
gamepad_btn_rect.pos = Dqn_Rect_InterpolatedPoint(merchant_menu_rect, interp_pos01);
TELY_Render_TextureColourV4(renderer,
game->atlas_sprite_sheet.tex_handle,
button_rect,
gamepad_btn_rect,
Dqn_V2_Zero /*rotate origin*/,
0.f /*rotation*/,
tex_mod_colour);
}
// NOTE: Render the building
{
TELY_AssetSpriteAnimation *anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, mapping.upgrade_icon);
Dqn_Rect button_rect = game->atlas_sprite_sheet.rects.data[anim->index];
Dqn_Rect dest_rect = {};
dest_rect.size = button_rect.size * 1.5f;
dest_rect.pos = Dqn_Rect_InterpolatedPoint(merchant_menu_rect, Dqn_V2_InitNx2(0.75f, 0.5f));
dest_rect.size = button_rect.size * .75f;
dest_rect.pos = Dqn_Rect_InterpolatedPoint(merchant_menu_rect, interp_pos01 + Dqn_V2_InitNx2(0.12f, 0.15f)) - (dest_rect.size * .5f);
TELY_Render_TextureColourV4(renderer,
game->atlas_sprite_sheet.tex_handle,
button_rect,
@@ -2936,8 +3010,30 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
Dqn_V2_Zero /*rotate origin*/,
0.f /*rotation*/,
tex_mod_colour);
}
TELY_Render_TextF(renderer, Dqn_Rect_InterpolatedPoint(dest_rect, Dqn_V2_InitNx2(0.5f, -1)), Dqn_V2_InitNx2(0.5, 0.f), "$%u", *mapping.upgrade_base_price);
// NOTE: Render the $ cost
TELY_Render_TextF(renderer, Dqn_Rect_InterpolatedPoint(gamepad_btn_rect, Dqn_V2_InitNx2(1.f, -0.8f)), Dqn_V2_InitNx2(0.5, 0.f), "$%u", *mapping.upgrade_base_price);
// NOTE: Render the keyboard binding =======================================
{
DQN_ASSERT(key_bind.scan_code >= TELY_PlatformInputScanCode_A && key_bind.scan_code <= TELY_PlatformInputScanCode_Z);
char scan_code_ch = DQN_CAST(char)('A' + (key_bind.scan_code - TELY_PlatformInputScanCode_A));
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
TELY_AssetFont const *font = TELY_Render_Font(renderer, assets);
Dqn_String8 key_bind_label = Dqn_String8_InitF(scratch.allocator, "[%c]", scan_code_ch);
Dqn_Rect key_bind_rect = {};
key_bind_rect.pos = Dqn_Rect_InterpolatedPoint(gamepad_btn_rect, Dqn_V2_InitNx2(-0.1f, 1.1f));
key_bind_rect.size = TELY_Asset_MeasureText(font, key_bind_label);
key_bind_rect = Dqn_Rect_Expand(key_bind_rect, 2.f);
TELY_Render_PushColourV4(renderer, TELY_Colour_V4Alpha(colour_accent_yellow, tex_mod_colour.a));
TELY_Render_RectColourV4(renderer, key_bind_rect, TELY_RenderShapeMode_Fill, TELY_Colour_V4Alpha(keybind_btn_shadow_colour, tex_mod_colour.a));
TELY_Render_Text(renderer, Dqn_Rect_InterpolatedPoint(key_bind_rect, Dqn_V2_InitNx1(0.5f)), Dqn_V2_InitNx1(0.5f), key_bind_label);
TELY_Render_PopColourV4(renderer);
}
}
}
}
+1
View File
@@ -52,6 +52,7 @@ struct FP_GlobalAnimations
Dqn_String8 heart = DQN_STRING8("heart");
Dqn_String8 heart_bleed = DQN_STRING8("heart_bleed");
Dqn_String8 icon_attack = DQN_STRING8("icon_attack");
Dqn_String8 icon_health = DQN_STRING8("icon_health");
Dqn_String8 icon_money = DQN_STRING8("icon_money");
Dqn_String8 icon_phone = DQN_STRING8("icon_phone");
+10 -3
View File
@@ -191,11 +191,12 @@ struct FP_GameEntity
// NOTE: The entity hit box is positioned at the center of the entity.
Dqn_V2 local_hit_box_size;
Dqn_V2 local_hit_box_offset;
Dqn_f32 trauma01;
Dqn_V2 attack_box_size;
Dqn_V2 attack_box_offset;
bool attack_processed;
Dqn_usize hit_on_frame;
Dqn_usize hit_on_clock_ms;
bool is_dying;
uint64_t last_attack_timestamp;
uint64_t attack_cooldown_ms;
@@ -261,8 +262,6 @@ struct FP_GameCamera
Dqn_V2 world_pos_target;
Dqn_f32 rotate_rads;
Dqn_V2 scale;
Dqn_f32 shake_intensity;
Dqn_f64 shake_duration;
};
enum FP_GameAudio
@@ -325,6 +324,11 @@ struct FP_GamePlay
FP_GameEntityHandle merchant_gym;
FP_GameEntityHandle merchant_phone_company;
Dqn_V2 merchant_terry_menu_pos;
Dqn_V2 merchant_graveyard_menu_pos;
Dqn_V2 merchant_gym_menu_pos;
Dqn_V2 merchant_phone_company_menu_pos;
FP_GameEntityHandle clicked_entity;
FP_GameEntityHandle hot_entity;
FP_GameEntityHandle active_entity;
@@ -332,6 +336,7 @@ struct FP_GamePlay
FP_GameEntityHandle prev_hot_entity;
FP_GameEntityHandle prev_active_entity;
FP_GameEntityHandle camera_tracking_entity;
FP_GameCamera camera;
Dqn_f32 meters_to_pixels;
uint64_t clock_ms;
@@ -369,6 +374,8 @@ struct FP_GameControls
FP_GameKeyBind left;
FP_GameKeyBind right;
FP_GameKeyBind attack;
FP_GameKeyBind buy_building;
FP_GameKeyBind buy_upgrade;
FP_GameKeyBind range_attack;
FP_GameKeyBind build_mode;
FP_GameKeyBind strafe;