|
|
|
@ -127,18 +127,18 @@ static TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_OS *os, TELY_Assets
|
|
|
|
|
static void FP_SetDefaultGamepadBindings(FP_GameControls *controls)
|
|
|
|
|
{
|
|
|
|
|
// NOTE: Note up/down/left/right uses analog sticks, non-negotiable.
|
|
|
|
|
controls->attack.gamepad_key = TELY_OSInputGamepadKey_X;
|
|
|
|
|
controls->range_attack.gamepad_key = TELY_OSInputGamepadKey_Y;
|
|
|
|
|
controls->build_mode.gamepad_key = TELY_OSInputGamepadKey_L3;
|
|
|
|
|
controls->strafe.gamepad_key = TELY_OSInputGamepadKey_B;
|
|
|
|
|
controls->dash.gamepad_key = TELY_OSInputGamepadKey_A;
|
|
|
|
|
controls->buy_building.gamepad_key = TELY_OSInputGamepadKey_LeftBumper;
|
|
|
|
|
controls->buy_upgrade.gamepad_key = TELY_OSInputGamepadKey_RightBumper;
|
|
|
|
|
controls->move_building_ui_cursor_left.gamepad_key = TELY_OSInputGamepadKey_DLeft;
|
|
|
|
|
controls->move_building_ui_cursor_right.gamepad_key = TELY_OSInputGamepadKey_DRight;
|
|
|
|
|
controls->attack.gamepad_key = TELY_InputGamepadKey_X;
|
|
|
|
|
controls->range_attack.gamepad_key = TELY_InputGamepadKey_Y;
|
|
|
|
|
controls->build_mode.gamepad_key = TELY_InputGamepadKey_L3;
|
|
|
|
|
controls->strafe.gamepad_key = TELY_InputGamepadKey_B;
|
|
|
|
|
controls->dash.gamepad_key = TELY_InputGamepadKey_A;
|
|
|
|
|
controls->buy_building.gamepad_key = TELY_InputGamepadKey_LeftBumper;
|
|
|
|
|
controls->buy_upgrade.gamepad_key = TELY_InputGamepadKey_RightBumper;
|
|
|
|
|
controls->move_building_ui_cursor_left.gamepad_key = TELY_InputGamepadKey_DLeft;
|
|
|
|
|
controls->move_building_ui_cursor_right.gamepad_key = TELY_InputGamepadKey_DRight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static FP_ListenForNewPlayerResult FP_ListenForNewPlayer(TELY_OSInput *input, FP_Game *game, bool tutorial_is_allowed)
|
|
|
|
|
static FP_ListenForNewPlayerResult FP_ListenForNewPlayer(TELY_Input *input, FP_Game *game, bool tutorial_is_allowed)
|
|
|
|
|
{
|
|
|
|
|
FP_ListenForNewPlayerResult result = {};
|
|
|
|
|
if (game->play.players.size == 2)
|
|
|
|
@ -159,16 +159,16 @@ static FP_ListenForNewPlayerResult FP_ListenForNewPlayer(TELY_OSInput *input, FP
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool keyboard_pressed = !keyboard_already_allocated && TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_B);
|
|
|
|
|
bool gamepad_pressed = TELY_OSInput_GamepadKeyIsPressed(input, gamepad_index, TELY_OSInputGamepadKey_Start);
|
|
|
|
|
bool keyboard_pressed = !keyboard_already_allocated && TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_B);
|
|
|
|
|
bool gamepad_pressed = TELY_Input_GamepadKeyIsPressed(input, gamepad_index, TELY_InputGamepadKey_Start);
|
|
|
|
|
|
|
|
|
|
if (tutorial_is_allowed) {
|
|
|
|
|
if (!keyboard_already_allocated && TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_T)) {
|
|
|
|
|
if (!keyboard_already_allocated && TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_T)) {
|
|
|
|
|
keyboard_pressed = true;
|
|
|
|
|
result.tutorial_requested = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TELY_OSInput_GamepadKeyIsPressed(input, gamepad_index, TELY_OSInputGamepadKey_Select)) {
|
|
|
|
|
if (TELY_Input_GamepadKeyIsPressed(input, gamepad_index, TELY_InputGamepadKey_Select)) {
|
|
|
|
|
gamepad_pressed = true;
|
|
|
|
|
result.tutorial_requested = true;
|
|
|
|
|
}
|
|
|
|
@ -190,19 +190,19 @@ static FP_ListenForNewPlayerResult FP_ListenForNewPlayer(TELY_OSInput *input, FP
|
|
|
|
|
FP_GameControls *controls = &terry->controls;
|
|
|
|
|
if (keyboard_pressed) {
|
|
|
|
|
controls->mode = FP_GameControlMode_Keyboard;
|
|
|
|
|
controls->up.scan_key = TELY_OSInputScanKey_W;
|
|
|
|
|
controls->down.scan_key = TELY_OSInputScanKey_S;
|
|
|
|
|
controls->left.scan_key = TELY_OSInputScanKey_A;
|
|
|
|
|
controls->right.scan_key = TELY_OSInputScanKey_D;
|
|
|
|
|
controls->attack.scan_key = TELY_OSInputScanKey_J;
|
|
|
|
|
controls->range_attack.scan_key = TELY_OSInputScanKey_K;
|
|
|
|
|
controls->build_mode.scan_key = TELY_OSInputScanKey_H;
|
|
|
|
|
controls->strafe.scan_key = TELY_OSInputScanKey_L;
|
|
|
|
|
controls->dash.scan_key = TELY_OSInputScanKey_N;
|
|
|
|
|
controls->buy_building.scan_key = TELY_OSInputScanKey_U;
|
|
|
|
|
controls->buy_upgrade.scan_key = TELY_OSInputScanKey_I;
|
|
|
|
|
controls->move_building_ui_cursor_left.scan_key = TELY_OSInputScanKey_Q;
|
|
|
|
|
controls->move_building_ui_cursor_right.scan_key = TELY_OSInputScanKey_E;
|
|
|
|
|
controls->up.scan_key = TELY_InputScanKey_W;
|
|
|
|
|
controls->down.scan_key = TELY_InputScanKey_S;
|
|
|
|
|
controls->left.scan_key = TELY_InputScanKey_A;
|
|
|
|
|
controls->right.scan_key = TELY_InputScanKey_D;
|
|
|
|
|
controls->attack.scan_key = TELY_InputScanKey_J;
|
|
|
|
|
controls->range_attack.scan_key = TELY_InputScanKey_K;
|
|
|
|
|
controls->build_mode.scan_key = TELY_InputScanKey_H;
|
|
|
|
|
controls->strafe.scan_key = TELY_InputScanKey_L;
|
|
|
|
|
controls->dash.scan_key = TELY_InputScanKey_N;
|
|
|
|
|
controls->buy_building.scan_key = TELY_InputScanKey_U;
|
|
|
|
|
controls->buy_upgrade.scan_key = TELY_InputScanKey_I;
|
|
|
|
|
controls->move_building_ui_cursor_left.scan_key = TELY_InputScanKey_Q;
|
|
|
|
|
controls->move_building_ui_cursor_right.scan_key = TELY_InputScanKey_E;
|
|
|
|
|
} else {
|
|
|
|
|
controls->mode = FP_GameControlMode_Gamepad;
|
|
|
|
|
controls->gamepad_index = gamepad_index;
|
|
|
|
@ -245,7 +245,10 @@ static void FP_PlayReset(FP_Game *game, TELY_OS *os)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NOTE: Fisher yates shuffle the list
|
|
|
|
|
DQN_MSVC_WARNING_PUSH
|
|
|
|
|
DQN_MSVC_WARNING_DISABLE(6293) // Ill-formed for loop (potential wrapping index)
|
|
|
|
|
for (Dqn_usize index = DQN_ARRAY_UCOUNT(play->monkey_spawn_shuffled_list) - 1; index < DQN_ARRAY_UCOUNT(play->monkey_spawn_shuffled_list); index--) {
|
|
|
|
|
DQN_MSVC_WARNING_POP
|
|
|
|
|
uint32_t swap_index = Dqn_PCG32_Range(&play->rng, 0, DQN_CAST(uint32_t)index + 1);
|
|
|
|
|
DQN_SWAP(play->monkey_spawn_shuffled_list[swap_index], play->monkey_spawn_shuffled_list[index]);
|
|
|
|
|
}
|
|
|
|
@ -421,6 +424,7 @@ void TELY_OS_DLLInit(TELY_OS *os)
|
|
|
|
|
|
|
|
|
|
// NOTE: TELY Game =============================================================================
|
|
|
|
|
TELY_Assets *assets = &os->assets;
|
|
|
|
|
assets->chunk_pool = &os->chunk_pool;
|
|
|
|
|
FP_Game *game = Dqn_Arena_New(&os->arena, FP_Game, Dqn_ZeroMem_Yes);
|
|
|
|
|
|
|
|
|
|
Dqn_f32 font_scalar = FP_TARGET_VIEWPORT_SIZE.w / DQN_CAST(Dqn_f32)os->core.window_size.x;
|
|
|
|
@ -434,27 +438,27 @@ void TELY_OS_DLLInit(TELY_OS *os)
|
|
|
|
|
game->jetbrains_mono_font = TELY_Asset_LoadFont(assets, DQN_STR8("JetBrains Mono NL (Regular)"), DQN_STR8("Data/Fonts/JetBrainsMonoNL-Regular.ttf"));
|
|
|
|
|
game->talkco_font = TELY_Asset_LoadFont(assets, DQN_STR8("Talkco"), DQN_STR8("Data/Fonts/Talkco.otf"));
|
|
|
|
|
|
|
|
|
|
game->audio[FP_GameAudio_TerryHit] = os->funcs.load_audio(assets, DQN_STR8("Terry Hit"), DQN_STR8("Data/Audio/terry_hit.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Ching] = os->funcs.load_audio(assets, DQN_STR8("Ching"), DQN_STR8("Data/Audio/ching.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Church] = os->funcs.load_audio(assets, DQN_STR8("Church"), DQN_STR8("Data/Audio/church.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Club] = os->funcs.load_audio(assets, DQN_STR8("Club"), DQN_STR8("Data/Audio/club_terry.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Dog] = os->funcs.load_audio(assets, DQN_STR8("Dog"), DQN_STR8("Data/Audio/dog.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_MerchantGhost] = os->funcs.load_audio(assets, DQN_STR8("Ghost"), DQN_STR8("Data/Audio/merchant_ghost.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_MerchantGym] = os->funcs.load_audio(assets, DQN_STR8("Gym"), DQN_STR8("Data/Audio/merchant_gym.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_MerchantPhone] = os->funcs.load_audio(assets, DQN_STR8("Phone"), DQN_STR8("Data/Audio/merchant_tech.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_MerchantTerry] = os->funcs.load_audio(assets, DQN_STR8("Door"), DQN_STR8("Data/Audio/merchant_terry.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Message] = os->funcs.load_audio(assets, DQN_STR8("Message"), DQN_STR8("Data/Audio/message.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Monkey] = os->funcs.load_audio(assets, DQN_STR8("Monkey"), DQN_STR8("Data/Audio/monkey.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Plane] = os->funcs.load_audio(assets, DQN_STR8("Plane"), DQN_STR8("Data/Audio/airport.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_PortalDestroy] = os->funcs.load_audio(assets, DQN_STR8("Portal Destroy"), DQN_STR8("Data/Audio/portal_destroy.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Smooch] = os->funcs.load_audio(assets, DQN_STR8("Smooch"), DQN_STR8("Data/Audio/smooch.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Woosh] = os->funcs.load_audio(assets, DQN_STR8("Woosh"), DQN_STR8("Data/Audio/woosh.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_GameStart] = os->funcs.load_audio(assets, DQN_STR8("Game Start"), DQN_STR8("Data/Audio/game_start.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_PerryStart] = os->funcs.load_audio(assets, DQN_STR8("Perry Start"), DQN_STR8("Data/Audio/perry_start.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Ambience1] = os->funcs.load_audio(assets, DQN_STR8("Ambience one"), DQN_STR8("Data/Audio/ambience_1.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Ambience2] = os->funcs.load_audio(assets, DQN_STR8("Ambience two"), DQN_STR8("Data/Audio/ambience_2.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Music1] = os->funcs.load_audio(assets, DQN_STR8("Music one"), DQN_STR8("Data/Audio/music_1.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Music2] = os->funcs.load_audio(assets, DQN_STR8("Music two"), DQN_STR8("Data/Audio/music_2.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_TerryHit] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Terry Hit"), DQN_STR8("Data/Audio/terry_hit.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Ching] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Ching"), DQN_STR8("Data/Audio/ching.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Church] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Church"), DQN_STR8("Data/Audio/church.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Club] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Club"), DQN_STR8("Data/Audio/club_terry.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Dog] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Dog"), DQN_STR8("Data/Audio/dog.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_MerchantGhost] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Ghost"), DQN_STR8("Data/Audio/merchant_ghost.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_MerchantGym] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Gym"), DQN_STR8("Data/Audio/merchant_gym.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_MerchantPhone] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Phone"), DQN_STR8("Data/Audio/merchant_tech.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_MerchantTerry] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Door"), DQN_STR8("Data/Audio/merchant_terry.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Message] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Message"), DQN_STR8("Data/Audio/message.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Monkey] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Monkey"), DQN_STR8("Data/Audio/monkey.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Plane] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Plane"), DQN_STR8("Data/Audio/airport.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_PortalDestroy] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Portal Destroy"), DQN_STR8("Data/Audio/portal_destroy.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Smooch] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Smooch"), DQN_STR8("Data/Audio/smooch.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Woosh] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Woosh"), DQN_STR8("Data/Audio/woosh.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_GameStart] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Game Start"), DQN_STR8("Data/Audio/game_start.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_PerryStart] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Perry Start"), DQN_STR8("Data/Audio/perry_start.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Ambience1] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Ambience one"), DQN_STR8("Data/Audio/ambience_1.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Ambience2] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Ambience two"), DQN_STR8("Data/Audio/ambience_2.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Music1] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Music one"), DQN_STR8("Data/Audio/music_1.ogg"));
|
|
|
|
|
game->audio[FP_GameAudio_Music2] = TELY_Asset_LoadAudio(assets, os, DQN_STR8("Music two"), DQN_STR8("Data/Audio/music_2.ogg"));
|
|
|
|
|
|
|
|
|
|
// NOTE: Load sprite sheets ====================================================================
|
|
|
|
|
os->user_data = game;
|
|
|
|
@ -520,7 +524,7 @@ static void FP_AppendMobSpawnerWaypoints(FP_Game *game, FP_GameEntityHandle src_
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_OSInput *input, FP_GameEntity *entity, Dqn_V2 *acceleration_meters_per_s)
|
|
|
|
|
static void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_Input *input, FP_GameEntity *entity, Dqn_V2 *acceleration_meters_per_s)
|
|
|
|
|
{
|
|
|
|
|
TELY_AssetSpriteSheet *sheet = &game->atlas_sprite_sheet;
|
|
|
|
|
FP_GameEntityAction *action = &entity->action;
|
|
|
|
@ -1296,7 +1300,7 @@ static void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_O
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void FP_Update(TELY_OS *os, FP_Game *game, TELY_OSInput *input, TELY_Audio *audio)
|
|
|
|
|
static void FP_Update(TELY_OS *os, FP_Game *game, TELY_Input *input, TELY_Audio *audio)
|
|
|
|
|
{
|
|
|
|
|
Dqn_Profiler_ZoneScopeWithIndex("FP_Update", FP_ProfileZone_FPUpdate);
|
|
|
|
|
if (game->play.state == FP_GameState_Pause)
|
|
|
|
@ -1310,16 +1314,16 @@ static void FP_Update(TELY_OS *os, FP_Game *game, TELY_OSInput *input, TELY_Audi
|
|
|
|
|
|
|
|
|
|
DQN_MSVC_WARNING_PUSH
|
|
|
|
|
DQN_MSVC_WARNING_DISABLE(4127) // Conditional expression is constant 'FP_DEVELOPER_MODE'
|
|
|
|
|
if (FP_DEVELOPER_MODE && TELY_OSInput_KeyIsReleased(input->mouse_left))
|
|
|
|
|
if (FP_DEVELOPER_MODE && TELY_Input_KeyIsReleased(input->mouse_keys[TELY_InputMouseKey_Left]))
|
|
|
|
|
game->play.clicked_entity = game->play.prev_active_entity;
|
|
|
|
|
|
|
|
|
|
if (TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_Escape)) {
|
|
|
|
|
if (TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_Escape)) {
|
|
|
|
|
game->play.state = FP_GameState_Pause;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (FP_DEVELOPER_MODE && game->play.clicked_entity.id) {
|
|
|
|
|
if (TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_Delete))
|
|
|
|
|
if (TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_Delete))
|
|
|
|
|
FP_Game_DeleteEntity(game, game->play.clicked_entity);
|
|
|
|
|
}
|
|
|
|
|
DQN_MSVC_WARNING_POP
|
|
|
|
@ -1347,7 +1351,7 @@ static void FP_Update(TELY_OS *os, FP_Game *game, TELY_OSInput *input, TELY_Audi
|
|
|
|
|
|
|
|
|
|
// NOTE: Gamepad movement input
|
|
|
|
|
if (controls->mode == FP_GameControlMode_Gamepad) {
|
|
|
|
|
TELY_OSInputGamepad *gamepad = input->gamepads + controls->gamepad_index;
|
|
|
|
|
TELY_InputGamepad *gamepad = input->gamepads + controls->gamepad_index;
|
|
|
|
|
dir_vector += gamepad->left_stick;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2015,16 +2019,18 @@ static void FP_Update(TELY_OS *os, FP_Game *game, TELY_OSInput *input, TELY_Audi
|
|
|
|
|
// haven't given the player cooldown yet, so we assign a timestamp for that
|
|
|
|
|
if (game->play.wave_cooldown_timestamp_ms == 0) {
|
|
|
|
|
game->play.wave_cooldown_timestamp_ms = game->play.clock_ms + FP_COOLDOWN_WAVE_TIME_MS;
|
|
|
|
|
TELY_Audio_Stop(audio, game->audio[FP_GameAudio_Music1]);
|
|
|
|
|
TELY_Audio_Play(audio, game->audio[FP_GameAudio_Music2], 1.f);
|
|
|
|
|
TELY_Audio_Fade(audio, game->bg_music1, TELY_AudioEffectFade_Out, 2000 /*fade_duration_ms*/);
|
|
|
|
|
game->bg_music2 = TELY_Audio_Play(audio, game->audio[FP_GameAudio_Music2], 1.f);
|
|
|
|
|
TELY_Audio_Fade(audio, game->bg_music2, TELY_AudioEffectFade_In, 2000 /*fade_duration_ms*/);
|
|
|
|
|
} else {
|
|
|
|
|
// NOTE: Check if cooldown has elapsed, the next wave can start if so
|
|
|
|
|
if (game->play.clock_ms > game->play.wave_cooldown_timestamp_ms) {
|
|
|
|
|
game->play.enemies_per_wave = DQN_MAX(5 * DQN_CAST(uint32_t)game->play.mob_spawners.size, DQN_CAST(uint32_t)(game->play.enemies_per_wave * 1.5));
|
|
|
|
|
game->play.enemies_spawned_this_wave = 0; // Important! Reset the spawn count
|
|
|
|
|
game->play.wave_cooldown_timestamp_ms = 0; // Important! We reset the timestamp for the next wave
|
|
|
|
|
TELY_Audio_Stop(audio, game->audio[FP_GameAudio_Music2]);
|
|
|
|
|
TELY_Audio_Play(audio, game->audio[FP_GameAudio_Music1], 1.f);
|
|
|
|
|
TELY_Audio_Fade(audio, game->bg_music2, TELY_AudioEffectFade_Out, 2000 /*fade_duration_ms*/);
|
|
|
|
|
game->bg_music1 = TELY_Audio_Play(audio, game->audio[FP_GameAudio_Music1], 1.f);
|
|
|
|
|
TELY_Audio_Fade(audio, game->bg_music1, TELY_AudioEffectFade_In, 2000 /*fade_duration_ms*/);
|
|
|
|
|
|
|
|
|
|
if (monkey_spawn && game->play.current_wave != 0) {
|
|
|
|
|
// NOTE: We spawn a monkey at these wave intervals;
|
|
|
|
@ -2432,27 +2438,27 @@ static void FP_Update(TELY_OS *os, FP_Game *game, TELY_OSInput *input, TELY_Audi
|
|
|
|
|
Dqn_Profiler_EndZone(update_zone);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Dqn_Str8 FP_ScanKeyToLabel(Dqn_Arena *arena, TELY_OSInputScanKey scan_key)
|
|
|
|
|
static Dqn_Str8 FP_ScanKeyToLabel(Dqn_Arena *arena, TELY_InputScanKey scan_key)
|
|
|
|
|
{
|
|
|
|
|
Dqn_Str8 result = {};
|
|
|
|
|
Dqn_Allocator allocator = Dqn_Arena_Allocator(arena);
|
|
|
|
|
if (scan_key >= TELY_OSInputScanKey_A && scan_key <= TELY_OSInputScanKey_Z) {
|
|
|
|
|
char scan_key_ch = DQN_CAST(char)('A' + (scan_key - TELY_OSInputScanKey_A));
|
|
|
|
|
if (scan_key >= TELY_InputScanKey_A && scan_key <= TELY_InputScanKey_Z) {
|
|
|
|
|
char scan_key_ch = DQN_CAST(char)('A' + (scan_key - TELY_InputScanKey_A));
|
|
|
|
|
result = Dqn_Str8_InitF(allocator, "[%c]", scan_key_ch);
|
|
|
|
|
} else {
|
|
|
|
|
if (scan_key == TELY_OSInputScanKey_Up) {
|
|
|
|
|
if (scan_key == TELY_InputScanKey_Up) {
|
|
|
|
|
result = Dqn_Str8_InitF(allocator, "[Up]");
|
|
|
|
|
} else if (scan_key == TELY_OSInputScanKey_Down) {
|
|
|
|
|
} else if (scan_key == TELY_InputScanKey_Down) {
|
|
|
|
|
result = Dqn_Str8_InitF(allocator, "[Down]");
|
|
|
|
|
} else if (scan_key == TELY_OSInputScanKey_Left) {
|
|
|
|
|
} else if (scan_key == TELY_InputScanKey_Left) {
|
|
|
|
|
result = Dqn_Str8_InitF(allocator, "[Left]");
|
|
|
|
|
} else if (scan_key == TELY_OSInputScanKey_Right) {
|
|
|
|
|
} else if (scan_key == TELY_InputScanKey_Right) {
|
|
|
|
|
result = Dqn_Str8_InitF(allocator, "[Right]");
|
|
|
|
|
} else if (scan_key == TELY_OSInputScanKey_Semicolon) {
|
|
|
|
|
} else if (scan_key == TELY_InputScanKey_Semicolon) {
|
|
|
|
|
result = Dqn_Str8_InitF(allocator, "[;]");
|
|
|
|
|
} else if (scan_key == TELY_OSInputScanKey_Apostrophe) {
|
|
|
|
|
} else if (scan_key == TELY_InputScanKey_Apostrophe) {
|
|
|
|
|
result = Dqn_Str8_InitF(allocator, "[']");
|
|
|
|
|
} else if (scan_key == TELY_OSInputScanKey_Backslash) {
|
|
|
|
|
} else if (scan_key == TELY_InputScanKey_Backslash) {
|
|
|
|
|
result = Dqn_Str8_InitF(allocator, "[/]");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -2475,13 +2481,13 @@ static void FP_DrawBillboardKeyBindHint(TELY_Renderer *renderer,
|
|
|
|
|
|
|
|
|
|
if (mode == FP_GameControlMode_Gamepad) {
|
|
|
|
|
Dqn_Str8 tex_name = {};
|
|
|
|
|
if (key_bind.gamepad_key == TELY_OSInputGamepadKey_A)
|
|
|
|
|
if (key_bind.gamepad_key == TELY_InputGamepadKey_A)
|
|
|
|
|
tex_name = g_anim_names.merchant_button_a;
|
|
|
|
|
else if (key_bind.gamepad_key == TELY_OSInputGamepadKey_B)
|
|
|
|
|
else if (key_bind.gamepad_key == TELY_InputGamepadKey_B)
|
|
|
|
|
tex_name = g_anim_names.merchant_button_b;
|
|
|
|
|
else if (key_bind.gamepad_key == TELY_OSInputGamepadKey_X)
|
|
|
|
|
else if (key_bind.gamepad_key == TELY_InputGamepadKey_X)
|
|
|
|
|
tex_name = g_anim_names.merchant_button_x;
|
|
|
|
|
else if (key_bind.gamepad_key == TELY_OSInputGamepadKey_Y)
|
|
|
|
|
else if (key_bind.gamepad_key == TELY_InputGamepadKey_Y)
|
|
|
|
|
tex_name = g_anim_names.merchant_button_y;
|
|
|
|
|
|
|
|
|
|
if (tex_name.size) {
|
|
|
|
@ -2512,7 +2518,7 @@ static void FP_DrawBillboardKeyBindHint(TELY_Renderer *renderer,
|
|
|
|
|
static void FP_Render(FP_Game *game, TELY_OS *os, TELY_Renderer *renderer, TELY_Audio *audio)
|
|
|
|
|
{
|
|
|
|
|
Dqn_Profiler_ZoneScopeWithIndex("FP_Render", FP_ProfileZone_FPRender);
|
|
|
|
|
TELY_OSInput *input = &os->input;
|
|
|
|
|
TELY_Input *input = &os->input;
|
|
|
|
|
TELY_RFui *rfui = &game->rfui;
|
|
|
|
|
TELY_Assets *assets = &os->assets;
|
|
|
|
|
|
|
|
|
@ -3314,13 +3320,13 @@ static void FP_Render(FP_Game *game, TELY_OS *os, TELY_Renderer *renderer, TELY_
|
|
|
|
|
bool trigger_buy_anim = false;
|
|
|
|
|
|
|
|
|
|
if (have_enough_coins) {
|
|
|
|
|
if (TELY_OSInput_ScanKeyIsPressed(input, key_bind.scan_key)) {
|
|
|
|
|
if (TELY_Input_ScanKeyIsPressed(input, key_bind.scan_key)) {
|
|
|
|
|
game->play.player_trigger_purchase_building_timestamp = game->play.clock_ms + buy_duration_ms;
|
|
|
|
|
} else if (TELY_OSInput_ScanKeyIsDown(input, key_bind.scan_key)) {
|
|
|
|
|
} else if (TELY_Input_ScanKeyIsDown(input, key_bind.scan_key)) {
|
|
|
|
|
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_OSInput_ScanKeyIsReleased(input, key_bind.scan_key)) {
|
|
|
|
|
} else if (TELY_Input_ScanKeyIsReleased(input, key_bind.scan_key)) {
|
|
|
|
|
if (game->play.clock_ms > game->play.player_trigger_purchase_building_timestamp) {
|
|
|
|
|
if (mapping.inventory_count) {
|
|
|
|
|
player->coins -= *mapping.building_base_price;
|
|
|
|
@ -3446,13 +3452,13 @@ static void FP_Render(FP_Game *game, TELY_OS *os, TELY_Renderer *renderer, TELY_
|
|
|
|
|
bool trigger_buy_anim = false;
|
|
|
|
|
|
|
|
|
|
if (have_enough_coins) {
|
|
|
|
|
if (TELY_OSInput_ScanKeyIsPressed(input, key_bind.scan_key)) {
|
|
|
|
|
if (TELY_Input_ScanKeyIsPressed(input, key_bind.scan_key)) {
|
|
|
|
|
game->play.player_trigger_purchase_upgrade_timestamp = game->play.clock_ms + buy_duration_ms;
|
|
|
|
|
} else if (TELY_OSInput_ScanKeyIsDown(input, key_bind.scan_key)) {
|
|
|
|
|
} else if (TELY_Input_ScanKeyIsDown(input, key_bind.scan_key)) {
|
|
|
|
|
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_OSInput_ScanKeyIsReleased(input, key_bind.scan_key)) {
|
|
|
|
|
} else if (TELY_Input_ScanKeyIsReleased(input, key_bind.scan_key)) {
|
|
|
|
|
if (game->play.clock_ms > game->play.player_trigger_purchase_upgrade_timestamp) {
|
|
|
|
|
player->coins -= *mapping.upgrade_base_price;
|
|
|
|
|
*mapping.upgrade_base_price *= 1;
|
|
|
|
@ -3990,7 +3996,7 @@ static void FP_Render(FP_Game *game, TELY_OS *os, TELY_Renderer *renderer, TELY_
|
|
|
|
|
TELY_Render_PopFont(renderer);
|
|
|
|
|
TELY_Render_PopColourV4(renderer);
|
|
|
|
|
|
|
|
|
|
if (TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_Return))
|
|
|
|
|
if (TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_Return))
|
|
|
|
|
game->play.state = FP_GameState_Play;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -4154,7 +4160,7 @@ static void FP_Render(FP_Game *game, TELY_OS *os, TELY_Renderer *renderer, TELY_
|
|
|
|
|
TELY_Render_PopFont(renderer);
|
|
|
|
|
TELY_Render_PopColourV4(renderer);
|
|
|
|
|
|
|
|
|
|
if (TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_Return))
|
|
|
|
|
if (TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_Return))
|
|
|
|
|
FP_PlayReset(game, os);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -4202,7 +4208,7 @@ static void FP_Render(FP_Game *game, TELY_OS *os, TELY_Renderer *renderer, TELY_
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// NOTE: Debug UI ==============================================================================
|
|
|
|
|
if (TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F1))
|
|
|
|
|
if (TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_F1))
|
|
|
|
|
game->play.debug_ui = !game->play.debug_ui;
|
|
|
|
|
|
|
|
|
|
DQN_MSVC_WARNING_PUSH
|
|
|
|
@ -4283,23 +4289,23 @@ static void FP_Render(FP_Game *game, TELY_OS *os, TELY_Renderer *renderer, TELY_
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F1 Debug info").clicked)
|
|
|
|
|
game->play.debug_ui = !game->play.debug_ui;
|
|
|
|
|
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F2 Add coins x10,000").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F2)) {
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F2 Add coins x10,000").clicked || TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_F2)) {
|
|
|
|
|
for (FP_GameEntityHandle player_handle : game->play.players) {
|
|
|
|
|
FP_GameEntity *player = FP_Game_GetEntity(game, player_handle);
|
|
|
|
|
player->coins += 10'000;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F3 Win game").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F3))
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F3 Win game").clicked || TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_F3))
|
|
|
|
|
game->play.state = FP_GameState_WinGame;
|
|
|
|
|
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F4 Lose game").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F4))
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F4 Lose game").clicked || TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_F4))
|
|
|
|
|
game->play.state = FP_GameState_LoseGame;
|
|
|
|
|
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F5 Reset game").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F5))
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F5 Reset game").clicked || TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_F5))
|
|
|
|
|
FP_PlayReset(game, os);
|
|
|
|
|
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F6 Increase health").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F6)) {
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F6 Increase health").clicked || TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_F6)) {
|
|
|
|
|
for (FP_GameEntityHandle player_handle : game->play.players) {
|
|
|
|
|
FP_GameEntity *player = FP_Game_GetEntity(game, player_handle);
|
|
|
|
|
player->hp_cap += FP_DEFAULT_DAMAGE;
|
|
|
|
@ -4307,7 +4313,7 @@ static void FP_Render(FP_Game *game, TELY_OS *os, TELY_Renderer *renderer, TELY_
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F7 Increase stamina").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F7)) {
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F7 Increase stamina").clicked || TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_F7)) {
|
|
|
|
|
for (FP_GameEntityHandle player_handle : game->play.players) {
|
|
|
|
|
FP_GameEntity *player = FP_Game_GetEntity(game, player_handle);
|
|
|
|
|
player->stamina_cap += DQN_CAST(uint16_t)(FP_TERRY_DASH_STAMINA_COST * .5f);
|
|
|
|
@ -4315,7 +4321,7 @@ static void FP_Render(FP_Game *game, TELY_OS *os, TELY_Renderer *renderer, TELY_
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F8 Increase mobile data").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F8)) {
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F8 Increase mobile data").clicked || TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_F8)) {
|
|
|
|
|
for (FP_GameEntityHandle player_handle : game->play.players) {
|
|
|
|
|
FP_GameEntity *player = FP_Game_GetEntity(game, player_handle);
|
|
|
|
|
player->terry_mobile_data_plan_cap += DQN_KILOBYTES(1);
|
|
|
|
@ -4323,10 +4329,10 @@ static void FP_Render(FP_Game *game, TELY_OS *os, TELY_Renderer *renderer, TELY_
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F9 %s god mode", game->play.god_mode ? "Disable" : "Enable").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F9))
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F9 %s god mode", game->play.god_mode ? "Disable" : "Enable").clicked || TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_F9))
|
|
|
|
|
game->play.god_mode = !game->play.god_mode;
|
|
|
|
|
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F11 Building inventory +1").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F11)) {
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "F11 Building inventory +1").clicked || TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_F11)) {
|
|
|
|
|
for (FP_GameEntityHandle player_handle : game->play.players) {
|
|
|
|
|
FP_GameEntity *player = FP_Game_GetEntity(game, player_handle);
|
|
|
|
|
player->inventory.clubs += 1;
|
|
|
|
@ -4336,7 +4342,7 @@ static void FP_Render(FP_Game *game, TELY_OS *os, TELY_Renderer *renderer, TELY_
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "1 %s HUD", game->play.debug_hide_hud ? "Show" : "Hide").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_1))
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "1 %s HUD", game->play.debug_hide_hud ? "Show" : "Hide").clicked || TELY_Input_ScanKeyIsPressed(input, TELY_InputScanKey_1))
|
|
|
|
|
game->play.debug_hide_hud = !game->play.debug_hide_hud;
|
|
|
|
|
|
|
|
|
|
if (TELY_RFui_ButtonF(rfui, "%s bounding rects", game->play.debug_hide_bounding_rectangles ? "Show" : "Hide").clicked)
|
|
|
|
@ -4443,7 +4449,7 @@ static void FP_Render(FP_Game *game, TELY_OS *os, TELY_Renderer *renderer, TELY_
|
|
|
|
|
TELY_OS_DLL_FUNCTION
|
|
|
|
|
void TELY_OS_DLLFrameUpdate(TELY_OS *os)
|
|
|
|
|
{
|
|
|
|
|
TELY_OSInput *input = &os->input;
|
|
|
|
|
TELY_Input *input = &os->input;
|
|
|
|
|
TELY_Renderer *renderer = &os->renderer;
|
|
|
|
|
FP_Game *game = DQN_CAST(FP_Game *) os->user_data;
|
|
|
|
|
|
|
|
|
@ -4459,18 +4465,8 @@ void TELY_OS_DLLFrameUpdate(TELY_OS *os)
|
|
|
|
|
|
|
|
|
|
// =============================================================================================
|
|
|
|
|
|
|
|
|
|
TELY_Audio *audio = &os->audio;
|
|
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
|
if (audio->playback_size == 0) {
|
|
|
|
|
//TELY_Audio_Play(audio, game->audio[FP_GameAudio_Music2], 1.f /*volume*/);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// =============================================================================================
|
|
|
|
|
|
|
|
|
|
if (game->play.state == FP_GameState_Play || game->play.state == FP_GameState_Tutorial) {
|
|
|
|
|
if (TELY_OSInput_KeyWasDown(input->mouse_left) && TELY_OSInput_KeyIsDown(input->mouse_left)) {
|
|
|
|
|
if (TELY_Input_KeyWasDown(input->mouse_keys[TELY_InputMouseKey_Left]) && TELY_Input_KeyIsDown(input->mouse_keys[TELY_InputMouseKey_Left])) {
|
|
|
|
|
if (game->play.prev_active_entity.id)
|
|
|
|
|
game->play.active_entity = game->play.prev_active_entity;
|
|
|
|
|
} else {
|
|
|
|
@ -4490,7 +4486,7 @@ void TELY_OS_DLLFrameUpdate(TELY_OS *os)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
game->play.hot_entity = entity->handle;
|
|
|
|
|
if (TELY_OSInput_KeyIsPressed(input->mouse_left)) {
|
|
|
|
|
if (TELY_Input_KeyIsPressed(input->mouse_keys[TELY_InputMouseKey_Left])) {
|
|
|
|
|
game->play.active_entity = entity->handle;
|
|
|
|
|
game->play.clicked_entity = entity->handle;
|
|
|
|
|
}
|
|
|
|
@ -4498,6 +4494,7 @@ void TELY_OS_DLLFrameUpdate(TELY_OS *os)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TELY_Audio *audio = &os->audio;
|
|
|
|
|
for (game->play.delta_s_accumulator += DQN_CAST(Dqn_f32)input->delta_s;
|
|
|
|
|
game->play.delta_s_accumulator > FP_GAME_PHYSICS_STEP;
|
|
|
|
|
game->play.delta_s_accumulator -= FP_GAME_PHYSICS_STEP) {
|
|
|
|
|