diff --git a/game/neo/scripts/HudLayout.res b/game/neo/scripts/HudLayout.res index c5f1072b6..7e29e25a3 100644 --- a/game/neo/scripts/HudLayout.res +++ b/game/neo/scripts/HudLayout.res @@ -908,6 +908,16 @@ "sprint_text_color" "255 255 255 100" "sprint_color" "255 255 255 150" } + neo_walking_indicator + { + "fieldName" "neo_walking_indicator" + "xpos" "208" + "ypos" "470" + "wide" "24" + "tall" "24" + "visible" "1" + "enabled" "1" + } RoundResult { "fieldName" "RoundResult" diff --git a/src/game/client/CMakeLists.txt b/src/game/client/CMakeLists.txt index da9041233..b161820e9 100644 --- a/src/game/client/CMakeLists.txt +++ b/src/game/client/CMakeLists.txt @@ -1610,6 +1610,8 @@ target_sources_grouped( neo/ui/neo_hud_round_state.h neo/ui/neo_hud_startup_sequence.cpp neo/ui/neo_hud_startup_sequence.h + neo/ui/neo_hud_walking_indicator.cpp + neo/ui/neo_hud_walking_indicator.h neo/ui/neo_hud_worldpos_marker.cpp neo/ui/neo_hud_worldpos_marker.h neo/ui/neo_hud_worldpos_marker_generic.cpp diff --git a/src/game/client/neo/c_neo_player.h b/src/game/client/neo/c_neo_player.h index 283a199c4..ee5375a05 100644 --- a/src/game/client/neo/c_neo_player.h +++ b/src/game/client/neo/c_neo_player.h @@ -188,7 +188,8 @@ class C_NEO_Player : public C_HL2MP_Player #ifdef GLOWS_ENABLE void UpdateGlowEffects(int iNewTeam); #endif // GLOWS_ENABLE - + bool ShouldPlayerMakeFootsteps(float speed = -1.f); + float SpeedFractionToSoundThreshold(float speed = -1.f); private: char m_sNameWithTakeoverContextProcessingBuffer[MAX_PLAYER_NAME_LENGTH]; diff --git a/src/game/client/neo/ui/neo_hud_walking_indicator.cpp b/src/game/client/neo/ui/neo_hud_walking_indicator.cpp new file mode 100644 index 000000000..0652f9169 --- /dev/null +++ b/src/game/client/neo/ui/neo_hud_walking_indicator.cpp @@ -0,0 +1,85 @@ +#include "cbase.h" +#include "neo_hud_walking_indicator.h" + +#include "iclientmode.h" +#include + +#include "c_neo_player.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +DECLARE_NAMED_HUDELEMENT(CNEOHud_WalkingIndicator, neo_walking_indicator); + +NEO_HUD_ELEMENT_DECLARE_FREQ_CVAR(WalkingIndicator, 0.1) + +CNEOHud_WalkingIndicator::CNEOHud_WalkingIndicator(const char *pElementName, vgui::Panel *parent) + : CHudElement(pElementName), Panel(parent, pElementName) +{ + SetAutoDelete(true); + m_iHideHudElementNumber = NEO_HUD_ELEMENT_WALKING_INDICATOR; + + if (parent) { + SetParent(parent); + } + else + { + SetParent(g_pClientMode->GetViewport()); + } + + m_hWalkingIndicatorTexture = vgui::surface()->CreateNewTextureID(); + Assert(m_hWalkingIndicatorTexture > 0); + vgui::surface()->DrawSetTextureFile(m_hWalkingIndicatorTexture, "vgui/hud/player/walkingIndicator", 1, false); + + SetVisible(true); +} + +void CNEOHud_WalkingIndicator::ApplySchemeSettings(vgui::IScheme* pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); + + SetBounds(xpos, ypos-tall, wide, tall); + SetFgColor(COLOR_TRANSPARENT); + SetBgColor(COLOR_TRANSPARENT); +} + +void CNEOHud_WalkingIndicator::UpdateStateForNeoHudElementDraw() +{ +} + +void CNEOHud_WalkingIndicator::DrawNeoHudElement() +{ + if (!ShouldDraw()) + return; + + C_NEO_Player* pLocalPlayer = C_NEO_Player::GetLocalNEOPlayer(); + if (!pLocalPlayer) + return; + + C_NEO_Player* pTargetPlayer = pLocalPlayer->IsObserver() && (pLocalPlayer->GetObserverMode() == OBS_MODE_IN_EYE || pLocalPlayer->GetObserverMode() == OBS_MODE_CHASE) ? static_cast(pLocalPlayer->GetObserverTarget()) : pLocalPlayer; + if (!pTargetPlayer) + return; + + if (!pTargetPlayer->IsAlive() || !pTargetPlayer->IsWalking())// && !pTargetPlayer->IsInAim()) player is also silent if aiming and not abusing the threshold, but its much harder to make noise when aiming, better for the indicator to strictly appear when walk is pressed + return; + + // we don't want the subrectangle taken from the texture to vary in size when speed changes but the split between the top and bottom image remains in the same spot since texture can be larger than the area its drawn to + const int pictureSplitDistanceInPixels = tall * (1 - Max(0.f, Min(1.f, pTargetPlayer->SpeedFractionToSoundThreshold()))); + const float pictureSplitDistanceFraction = (float)pictureSplitDistanceInPixels / tall; + + vgui::surface()->DrawSetTexture(m_hWalkingIndicatorTexture); + vgui::surface()->DrawSetColor(COLOR_WHITE); + const float ICON_WIDTH = 1 / 2.f; + const float ICON_HEIGHT = 1 / 2.f; + vgui::surface()->DrawTexturedSubRect(0, 0, wide, pictureSplitDistanceInPixels, + 0, ICON_HEIGHT, ICON_WIDTH, ICON_HEIGHT + (ICON_HEIGHT * pictureSplitDistanceFraction)); + vgui::surface()->DrawSetColor(255, 255 * pictureSplitDistanceFraction, 255 * pictureSplitDistanceFraction, 255); + vgui::surface()->DrawTexturedSubRect(0, pictureSplitDistanceInPixels, wide, tall, + 0, ICON_HEIGHT * pictureSplitDistanceFraction, ICON_WIDTH, ICON_HEIGHT); +} + +void CNEOHud_WalkingIndicator::Paint() +{ + BaseClass::Paint(); + PaintNeoElement(); +} \ No newline at end of file diff --git a/src/game/client/neo/ui/neo_hud_walking_indicator.h b/src/game/client/neo/ui/neo_hud_walking_indicator.h new file mode 100644 index 000000000..5c4054aa3 --- /dev/null +++ b/src/game/client/neo/ui/neo_hud_walking_indicator.h @@ -0,0 +1,34 @@ +#pragma once + +#include "neo_hud_childelement.h" +#include "hudelement.h" +#include + +class CNEOHud_WalkingIndicator : public CNEOHud_ChildElement, public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE(CNEOHud_WalkingIndicator, Panel); + +public: + CNEOHud_WalkingIndicator(const char *pElementName, vgui::Panel *parent = NULL); + void ApplySchemeSettings(vgui::IScheme* pScheme) override; + + virtual void Paint() override; + +protected: + virtual void UpdateStateForNeoHudElementDraw() override; + virtual void DrawNeoHudElement() override; + virtual ConVar* GetUpdateFrequencyConVar() const override; + +private: + vgui::HTexture m_hWalkingIndicatorTexture = 0; + + CPanelAnimationVarAliasType(int, xpos, "xpos", "r203", "proportional_xpos"); + CPanelAnimationVarAliasType(int, ypos, "ypos", "446", "proportional_ypos"); + CPanelAnimationVarAliasType(int, wide, "wide", "203", "proportional_xpos"); + CPanelAnimationVarAliasType(int, tall, "tall", "32", "proportional_ypos"); + CPanelAnimationVarAliasType(int, visible, "visible", "1", "int"); + CPanelAnimationVarAliasType(int, enabled, "enabled", "1", "int"); + +private: + CNEOHud_WalkingIndicator(const CNEOHud_WalkingIndicator&other); +}; \ No newline at end of file diff --git a/src/game/server/neo/neo_player.cpp b/src/game/server/neo/neo_player.cpp index cf2660fef..3ff3e4df4 100644 --- a/src/game/server/neo/neo_player.cpp +++ b/src/game/server/neo/neo_player.cpp @@ -172,6 +172,8 @@ ConVar sv_neo_warmup_godmode("sv_neo_warmup_godmode", "0", FCVAR_REPLICATED, "If ConVar bot_class("bot_class", "-1", 0, "Force all bots to spawn with the specified class number, or -1 to disable.", true, NEO_CLASS_RANDOM, true, NEO_CLASS_LOADOUTABLE_COUNT-1); static void BotChangeClassFn(const CCommand& args); ConCommand bot_changeclass("bot_changeclass", BotChangeClassFn, "Force all bots to switch to the specified class number."); +static void BotChangeSkinFn(const CCommand& args); +ConCommand bot_changeskin("bot_changeskin", BotChangeSkinFn, "Force all bots to switch to the specified skin number."); // Bot Cloak Detection Thresholds // Base detection chance ratio (0.0 - 1.0) for bots to notice a cloaked target based on difficulty @@ -4315,3 +4317,33 @@ static void BotChangeClassFn(const CCommand& args) player->RequestSetClass(botClass); } } + +static void BotChangeSkinFn(const CCommand& args) +{ + constexpr int minValue = NEO_SKIN_FIRST; + constexpr int maxValue = NEO_SKIN__ENUM_COUNT - 1; + + const auto nag = [&args]() { + Msg("Format: %s \n", args.Arg(0), minValue, maxValue); + }; + + if (args.ArgC() != 2) + { + nag(); + return; + } + + const int botSkin = V_atoi(args.Arg(1)); + if (botSkin < minValue || botSkin > maxValue) + { + nag(); + return; + } + + for (int i = 1; i <= gpGlobals->maxClients; ++i) + { + auto* player = assert_cast(UTIL_PlayerByIndex(i)); + if (player && player->IsBot() && player->GetTeamNumber() >= FIRST_GAME_TEAM) + player->RequestSetSkin(botSkin); + } +} diff --git a/src/game/server/neo/neo_player.h b/src/game/server/neo/neo_player.h index 6e9a15f7b..9cfab5f8e 100644 --- a/src/game/server/neo/neo_player.h +++ b/src/game/server/neo/neo_player.h @@ -238,6 +238,9 @@ class CNEO_Player : public CHL2MP_Player void BecomeJuggernaut(); void SpawnJuggernautPostDeath(); + bool ShouldPlayerMakeFootsteps(float speed = -1.f); + float SpeedFractionToSoundThreshold(float speed = -1.f); + private: bool m_bAllowGibbing; diff --git a/src/game/shared/baseplayer_shared.cpp b/src/game/shared/baseplayer_shared.cpp index 23e4d887b..07cd1c77b 100644 --- a/src/game/shared/baseplayer_shared.cpp +++ b/src/game/shared/baseplayer_shared.cpp @@ -693,29 +693,18 @@ void CBasePlayer::UpdateStepSound( surfacedata_t *psurface, const Vector &vecOri } #ifdef NEO - // Changing movement direction, looking around, wall-running accelerate the player. Threshold should be lower than regular speed, but higher than walk/aim speed - constexpr float SILENT_THRESHOLD_GRACE = 0.7f; -#endif //NEO + if (!neoPlayer->ShouldPlayerMakeFootsteps(speed)) + { + return; + } +#endif // NEO + // play the sound // 65% volume if ducking if ( GetFlags() & FL_DUCKING ) { fvol *= 0.65; -#ifdef NEO - if ((neoPlayer->IsInAim() || neoPlayer->IsWalking()) && speed <= (neoPlayer->GetCrouchSpeed() * SILENT_THRESHOLD_GRACE)) - { - return; - } -#endif // NEO - } -#ifdef NEO - - else if ((neoPlayer->IsInAim() || neoPlayer->IsWalking()) && speed <= (neoPlayer->GetNormSpeed() * SILENT_THRESHOLD_GRACE)) - { - return; } - -#endif PlayStepSound( feet, psurface, fvol, false ); } diff --git a/src/game/shared/neo/neo_gamerules.h b/src/game/shared/neo/neo_gamerules.h index c8cbfd2d3..8fc80ae95 100644 --- a/src/game/shared/neo/neo_gamerules.h +++ b/src/game/shared/neo/neo_gamerules.h @@ -158,6 +158,7 @@ enum NeoHudElements : NEO_HUD_BITS_UNDERLYING_TYPE { NEO_HUD_ELEMENT_SCOREBOARD = (static_cast(1) << 14), NEO_HUD_ELEMENT_PLAYER_PING = (static_cast(1) << 15), NEO_HUD_ELEMENT_WORLDPOS_MARKER_ENT = (static_cast(1) << 16), + NEO_HUD_ELEMENT_WALKING_INDICATOR = (static_cast(1) << 17), }; class CNEORules : public CHL2MPRules, public CGameEventListener diff --git a/src/game/shared/neo/neo_player_shared.cpp b/src/game/shared/neo/neo_player_shared.cpp index fb8cdde29..fd25e2e89 100644 --- a/src/game/shared/neo/neo_player_shared.cpp +++ b/src/game/shared/neo/neo_player_shared.cpp @@ -403,3 +403,39 @@ void CNEO_Player::CheckAimButtons() Weapon_SetZoom(false); } } + +// Changing movement direction, looking around, wall-running accelerate the player. Threshold should be lower than regular speed, but higher than walk/aim speed +constexpr float SILENT_THRESHOLD_GRACE = 0.7f; +bool CNEO_Player::ShouldPlayerMakeFootsteps(float speed) // Could simply always get speed from the player, but didnt want to risk changing the behavior of UpdateStepSound in baseplayer_shared +{ + if (speed < 0) + { + speed = GetAbsVelocity().Length(); + } + + if ( GetFlags() & FL_DUCKING && (IsInAim() || IsWalking()) && speed <= (GetCrouchSpeed() * SILENT_THRESHOLD_GRACE) ) + { + return false; + } + else if ((IsInAim() || IsWalking()) && speed <= (GetNormSpeed() * SILENT_THRESHOLD_GRACE)) + { + return false; + } + + return true; +} + +float CNEO_Player::SpeedFractionToSoundThreshold(float speed) +{ + if (speed < 0) + { + speed = GetAbsVelocity().Length(); + } + + if (IsInAim() || IsWalking()) + { + const float difference = ((GetFlags() & FL_DUCKING ? GetCrouchSpeed() : GetNormSpeed()) * SILENT_THRESHOLD_GRACE) - GetPlayerMaxSpeed(); + return (speed - GetPlayerMaxSpeed()) / difference; + } + return 1.f; +} \ No newline at end of file