diff --git a/game/neo/scripts/HudLayout.res b/game/neo/scripts/HudLayout.res index d692ff1c0..704d863bd 100644 --- a/game/neo/scripts/HudLayout.res +++ b/game/neo/scripts/HudLayout.res @@ -908,6 +908,20 @@ "sprint_text_color" "255 255 255 100" "sprint_color" "255 255 255 150" } + neo_walking_indicator + { + "fieldName" "neo_walking_indicator" + "visible" "1" + + "xpos" "208" + "ypos" "446" + "wide" "24" + "tall" "24" + "color" "255 255 255 200" + "texture" "vgui/hud/player/walkingIndicator" + + "barwidth" "0" + } RoundResult { "fieldName" "RoundResult" diff --git a/src/game/client/CMakeLists.txt b/src/game/client/CMakeLists.txt index 9273ef749..b804b9050 100644 --- a/src/game/client/CMakeLists.txt +++ b/src/game/client/CMakeLists.txt @@ -1667,6 +1667,7 @@ set(UNITY_SOURCE_NEO_UI neo/ui/neo_hud_player_ping.cpp neo/ui/neo_hud_round_state.cpp neo/ui/neo_hud_startup_sequence.cpp + neo/ui/neo_hud_walking_indicator.cpp neo/ui/neo_hud_worldpos_marker.cpp neo/ui/neo_hud_worldpos_marker_generic.cpp neo/ui/neo_scoreboard.cpp @@ -1706,6 +1707,7 @@ target_sources_grouped( neo/ui/neo_hud_player_ping.h neo/ui/neo_hud_round_state.h neo/ui/neo_hud_startup_sequence.h + neo/ui/neo_hud_walking_indicator.h neo/ui/neo_hud_worldpos_marker.h neo/ui/neo_hud_worldpos_marker_generic.h neo/ui/neo_scoreboard.h diff --git a/src/game/client/neo/c_neo_player.h b/src/game/client/neo/c_neo_player.h index 607d7185e..d99e5da0f 100644 --- a/src/game/client/neo/c_neo_player.h +++ b/src/game/client/neo/c_neo_player.h @@ -198,6 +198,9 @@ class C_NEO_Player : public C_HL2MP_Player bool ValidTakeoverTargetFor(CNEO_Player* pPlayerTakingOver); + bool ShouldPlayerMakeFootsteps(float speed = -1.f); + float SpeedFractionToSoundThreshold(float speed = -1.f); + private: char m_sNameWithTakeoverContextProcessingBuffer[MAX_PLAYER_NAME_LENGTH]; void CheckAimButtons(); 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..8878082c1 --- /dev/null +++ b/src/game/client/neo/ui/neo_hud_walking_indicator.cpp @@ -0,0 +1,79 @@ +#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()); + } + + SetVisible(true); +} + +void CNEOHud_WalkingIndicator::ApplySchemeSettings(vgui::IScheme* pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); + + SetBounds(xpos, ypos, wide, tall); + SetFgColor(COLOR_TRANSPARENT); + SetBgColor(COLOR_TRANSPARENT); +} + +void CNEOHud_WalkingIndicator::UpdateStateForNeoHudElementDraw() +{ +} + +void CNEOHud_WalkingIndicator::DrawNeoHudElement() +{ + if (!ShouldDraw() || !visible) + 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()) + return; + + vgui::surface()->DrawSetTexture(texture); + vgui::surface()->DrawSetColor(color); + vgui::surface()->DrawTexturedRect(0, 0, wide, tall); + + if (barwidth) + { + const float percentageTowardsGraceThreshold = pTargetPlayer->SpeedFractionToSoundThreshold(); + const float colourGB = 255 - (255 * (percentageTowardsGraceThreshold < 1 ? percentageTowardsGraceThreshold * 0.5f : 1)); + vgui::surface()->DrawSetColor(255, colourGB, colourGB, 255); + vgui::surface()->DrawFilledRect(0, tall - (tall * percentageTowardsGraceThreshold), barwidth, tall); + } +} + +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..f24d4f336 --- /dev/null +++ b/src/game/client/neo/ui/neo_hud_walking_indicator.h @@ -0,0 +1,36 @@ +#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: + CPanelAnimationVarAliasType(bool, visible, "visible", "1", "bool"); + + CPanelAnimationVarAliasType(int, xpos, "xpos", "r203", "proportional_xpos"); + CPanelAnimationVarAliasType(int, ypos, "ypos", "446", "proportional_ypos"); + CPanelAnimationVarAliasType(int, wide, "wide", "24", "proportional_xpos"); + CPanelAnimationVarAliasType(int, tall, "tall", "24", "proportional_ypos"); + CPanelAnimationVarAliasType(Color, color, "color", "150 150 150 40", "Color"); + CPanelAnimationVarAliasType(int, texture, "texture", "vgui/hud/player/walkingIndicatorInverted", "textureid"); + + CPanelAnimationVarAliasType(int, barwidth, "barwidth", "0", "proportional_xpos"); + +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 7e04b45bc..22e089242 100644 --- a/src/game/server/neo/neo_player.cpp +++ b/src/game/server/neo/neo_player.cpp @@ -159,6 +159,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 @@ -4532,3 +4534,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 7e5f7ac8a..f8fe8f667 100644 --- a/src/game/server/neo/neo_player.h +++ b/src/game/server/neo/neo_player.h @@ -247,6 +247,9 @@ class CNEO_Player : public CHL2MP_Player bool IsAFK() const; bool ValidTakeoverTargetFor(CNEO_Player* pPlayerTakingOver); + 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 7d3045be3..01ff532c9 100644 --- a/src/game/shared/neo/neo_gamerules.h +++ b/src/game/shared/neo/neo_gamerules.h @@ -162,6 +162,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), }; enum NeoSpectateEvent { diff --git a/src/game/shared/neo/neo_player_shared.cpp b/src/game/shared/neo/neo_player_shared.cpp index 9eb432423..1ac3fd8b6 100644 --- a/src/game/shared/neo/neo_player_shared.cpp +++ b/src/game/shared/neo/neo_player_shared.cpp @@ -728,4 +728,57 @@ CBaseEntity *CNEO_Player::FindUseEntity() } return pNearest; +} + +// Changing movement direction, looking around, wall-running accelerate the player. Raise the threshold. +constexpr float SILENT_THRESHOLD_GRACE = 0.7f; +#define MAX_SILENT_SPEED SILENT_THRESHOLD_GRACE * (GetFlags() & FL_DUCKING ? GetCrouchSpeed() : GetNormSpeed()) +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 (const bool canBeSilent = IsInAim() || IsWalking(); + !canBeSilent) + { + return true; + } + + if (speed <= MAX_SILENT_SPEED) + { + return false; + } + + return true; +} + +float CNEO_Player::SpeedFractionToSoundThreshold(float speed) +{ + if (speed < 0) + { + speed = GetAbsVelocity().Length(); + } + + if (const bool canBeSilent = IsInAim() || IsWalking()) + { + const float bottom = GetPlayerMaxSpeed(); + if (speed < bottom) + { + return 0.f; + } + + float top = MAX_SILENT_SPEED; + if (speed > top) + { + return 1.f; + } + + top -= bottom; + speed -= bottom; + return top != 0 ? speed / top : 1.f; + } + + return 1.f; } \ No newline at end of file