From 49943cb4c9895696e09dc44e17b2bc419b0c8935 Mon Sep 17 00:00:00 2001 From: "MyGamepedia (Sorry For My English)" <103366204+MyGamepedia@users.noreply.github.com> Date: Mon, 23 Feb 2026 01:34:40 +0200 Subject: [PATCH 1/8] custom weapon script loading --- sp/src/game/client/c_basecombatweapon.cpp | 14 ++ sp/src/game/client/hl2/hud_ammo.cpp | 58 +++++- sp/src/game/client/weapon_selection.cpp | 6 +- sp/src/game/server/ai_basenpc_squad.cpp | 4 +- sp/src/game/server/basecombatweapon.cpp | 9 +- sp/src/game/server/baseentity.h | 5 +- sp/src/game/server/gameweaponmanager.cpp | 8 +- sp/src/game/server/hl2/npc_alyx_episodic.cpp | 6 +- sp/src/game/server/hl2/npc_citizen17.cpp | 15 +- sp/src/game/server/hl2/npc_combine.cpp | 2 +- .../game/server/hl2/npc_playercompanion.cpp | 10 +- sp/src/game/server/mapbase/GlobalStrings.h | 2 +- sp/src/game/server/player_command.cpp | 2 +- .../game/shared/basecombatweapon_shared.cpp | 181 +++++++++++++++++- sp/src/game/shared/basecombatweapon_shared.h | 11 ++ sp/src/game/shared/weapon_parse.h | 3 + 16 files changed, 296 insertions(+), 40 deletions(-) diff --git a/sp/src/game/client/c_basecombatweapon.cpp b/sp/src/game/client/c_basecombatweapon.cpp index ff8e6d64f98..0f884356131 100644 --- a/sp/src/game/client/c_basecombatweapon.cpp +++ b/sp/src/game/client/c_basecombatweapon.cpp @@ -191,6 +191,20 @@ void C_BaseCombatWeapon::OnDataChanged( DataUpdateType_t updateType ) m_iOldState = m_iState; m_bJustRestored = false; + +#ifdef MAPBASE + if (updateType == DATA_UPDATE_CREATED) + { + Precache(); //cache weapon on client again, otherwise the client will always use default script name while server not + } + + //update script in case if wanted + if (m_iOldNeedsUpdate != m_iNeedsUpdate) + { + Precache(); + m_iOldNeedsUpdate = m_iNeedsUpdate; //assign new value to prevent updates on client when we don't want + } +#endif } //----------------------------------------------------------------------------- diff --git a/sp/src/game/client/hl2/hud_ammo.cpp b/sp/src/game/client/hl2/hud_ammo.cpp index 9e9e913991c..e3e3aa4ebfd 100644 --- a/sp/src/game/client/hl2/hud_ammo.cpp +++ b/sp/src/game/client/hl2/hud_ammo.cpp @@ -51,6 +51,9 @@ class CHudAmmo : public CHudNumericDisplay, public CHudElement int m_iAmmo; int m_iAmmo2; CHudTexture *m_iconPrimaryAmmo; +#ifdef MAPBASE + int m_iOldNeedsUpdate; //needs update tracking +#endif }; DECLARE_HUDELEMENT( CHudAmmo ); @@ -66,6 +69,9 @@ CHudAmmo::CHudAmmo( const char *pElementName ) : BaseClass(NULL, "HudAmmo"), CHu hudlcd->SetGlobalStat( "(ammo_secondary)", "0" ); hudlcd->SetGlobalStat( "(weapon_print_name)", "" ); hudlcd->SetGlobalStat( "(weapon_name)", "" ); +#ifdef MAPBASE + m_iOldNeedsUpdate = -1; // Initialize +#endif } //----------------------------------------------------------------------------- @@ -75,6 +81,9 @@ void CHudAmmo::Init( void ) { m_iAmmo = -1; m_iAmmo2 = -1; +#ifdef MAPBASE + m_iOldNeedsUpdate = -1; // Initialize +#endif m_iconPrimaryAmmo = NULL; @@ -107,6 +116,9 @@ void CHudAmmo::Reset() m_hCurrentVehicle = NULL; m_iAmmo = 0; m_iAmmo2 = 0; +#ifdef MAPBASE + m_iOldNeedsUpdate = -1; // Initialize +#endif UpdateAmmoDisplays(); } @@ -158,7 +170,12 @@ void CHudAmmo::UpdatePlayerAmmo( C_BasePlayer *player ) hudlcd->SetGlobalStat( "(ammo_primary)", VarArgs( "%d", ammo1 ) ); hudlcd->SetGlobalStat( "(ammo_secondary)", VarArgs( "%d", ammo2 ) ); +#ifdef MAPBASE + int iNeedsUpdate = wpn ? wpn->m_iOldNeedsUpdate : -1; + if (wpn == m_hCurrentActiveWeapon && m_iOldNeedsUpdate == iNeedsUpdate) +#else if (wpn == m_hCurrentActiveWeapon) +#endif { // same weapon, just update counts SetAmmo(ammo1, true); @@ -185,6 +202,10 @@ void CHudAmmo::UpdatePlayerAmmo( C_BasePlayer *player ) g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponChanged"); m_hCurrentActiveWeapon = wpn; } + +#ifdef MAPBASE + m_iOldNeedsUpdate = iNeedsUpdate; +#endif } void CHudAmmo::UpdateVehicleAmmo( C_BasePlayer *player, IClientVehicle *pVehicle ) @@ -362,6 +383,9 @@ class CHudSecondaryAmmo : public CHudNumericDisplay, public CHudElement CHudSecondaryAmmo( const char *pElementName ) : BaseClass( NULL, "HudAmmoSecondary" ), CHudElement( pElementName ) { m_iAmmo = -1; +#ifdef MAPBASE + m_iOldNeedsUpdate = -1; +#endif SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_WEAPONSELECTION | HIDEHUD_PLAYERDEAD | HIDEHUD_NEEDSUIT ); } @@ -369,6 +393,10 @@ class CHudSecondaryAmmo : public CHudNumericDisplay, public CHudElement void Init( void ) { #ifndef HL2MP +#ifdef MAPBASE + m_iOldNeedsUpdate = -1; +#endif + wchar_t *tempString = g_pVGuiLocalize->Find("#Valve_Hud_AMMO_ALT"); if (tempString) { @@ -414,6 +442,9 @@ class CHudSecondaryAmmo : public CHudNumericDisplay, public CHudElement // hud reset, update ammo state BaseClass::Reset(); m_iAmmo = 0; +#ifdef MAPBASE + m_iOldNeedsUpdate = -1; +#endif m_hCurrentActiveWeapon = NULL; SetAlpha( 0 ); UpdateAmmoState(); @@ -473,9 +504,14 @@ class CHudSecondaryAmmo : public CHudNumericDisplay, public CHudElement SetAmmo(player->GetAmmoCount(wpn->GetSecondaryAmmoType())); } +#ifdef MAPBASE + int iNeedsUpdate = wpn ? wpn->m_iOldNeedsUpdate : -1; + if (m_hCurrentActiveWeapon != wpn || m_iOldNeedsUpdate != iNeedsUpdate) +#else if ( m_hCurrentActiveWeapon != wpn ) +#endif { - if ( wpn->UsesSecondaryAmmo() ) + if (wpn && wpn->UsesSecondaryAmmo()) { // we've changed to a weapon that uses secondary ammo g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponUsesSecondaryAmmo"); @@ -487,15 +523,35 @@ class CHudSecondaryAmmo : public CHudNumericDisplay, public CHudElement } m_hCurrentActiveWeapon = wpn; +#ifndef MAPBASE // Get the icon we should be displaying m_iconSecondaryAmmo = gWR.GetAmmoIconFromWeapon( m_hCurrentActiveWeapon->GetSecondaryAmmoType() ); +#endif + } + +#ifdef MAPBASE + // Always update the icon if weapon is valid + if (wpn && wpn->UsesSecondaryAmmo()) + { + m_iconSecondaryAmmo = gWR.GetAmmoIconFromWeapon(wpn->GetSecondaryAmmoType()); } + else + { + m_iconSecondaryAmmo = nullptr; + } + + // Update m_iOldNeedsUpdate + m_iOldNeedsUpdate = iNeedsUpdate; +#endif } private: CHandle< C_BaseCombatWeapon > m_hCurrentActiveWeapon; CHudTexture *m_iconSecondaryAmmo; int m_iAmmo; +#ifdef MAPBASE + int m_iOldNeedsUpdate; //needs update tracking +#endif }; DECLARE_HUDELEMENT( CHudSecondaryAmmo ); diff --git a/sp/src/game/client/weapon_selection.cpp b/sp/src/game/client/weapon_selection.cpp index 5568c532ec3..ad0d0c37afd 100644 --- a/sp/src/game/client/weapon_selection.cpp +++ b/sp/src/game/client/weapon_selection.cpp @@ -505,8 +505,10 @@ void CBaseHudWeaponSelection::SwitchToLastWeapon( void ) void CBaseHudWeaponSelection::SetWeaponSelected( void ) { Assert( GetSelectedWeapon() ); - // Mark selection so that it's placed into next CUserCmd created - input->MakeWeaponSelection( GetSelectedWeapon() ); + + //Mark selection so that it's placed into next CUserCmd created if isn't active (or we'll get prediction glitch with custom scripts) + if(GetSelectedWeapon() != GetActiveWeapon()) + input->MakeWeaponSelection( GetSelectedWeapon() ); } diff --git a/sp/src/game/server/ai_basenpc_squad.cpp b/sp/src/game/server/ai_basenpc_squad.cpp index 1e895536f0c..91c276ac662 100644 --- a/sp/src/game/server/ai_basenpc_squad.cpp +++ b/sp/src/game/server/ai_basenpc_squad.cpp @@ -267,7 +267,7 @@ int CAI_BaseNPC::NumWeaponsInSquad( const char *pszWeaponClassname ) if( !GetSquad() ) { - if( GetActiveWeapon() && GetActiveWeapon()->m_iClassname == iszWeaponClassname ) + if(GetActiveWeapon() && FClassnameIs(GetActiveWeapon(), iszWeaponClassname.ToCStr())) { // I'm alone in my squad, but I do have this weapon. return 1; @@ -281,7 +281,7 @@ int CAI_BaseNPC::NumWeaponsInSquad( const char *pszWeaponClassname ) CAI_BaseNPC *pSquadmate = m_pSquad->GetFirstMember( &iter ); while ( pSquadmate ) { - if( pSquadmate->GetActiveWeapon() && pSquadmate->GetActiveWeapon()->m_iClassname == iszWeaponClassname ) + if(pSquadmate->GetActiveWeapon() && FClassnameIs(pSquadmate->GetActiveWeapon(), iszWeaponClassname.ToCStr())) { count++; } diff --git a/sp/src/game/server/basecombatweapon.cpp b/sp/src/game/server/basecombatweapon.cpp index 2863b747fdc..db6666018af 100644 --- a/sp/src/game/server/basecombatweapon.cpp +++ b/sp/src/game/server/basecombatweapon.cpp @@ -201,8 +201,13 @@ CBaseEntity* CBaseCombatWeapon::Respawn( void ) // will decide when to make the weapon visible and touchable. CBaseEntity *pNewWeapon = CBaseEntity::Create( GetClassname(), g_pGameRules->VecWeaponRespawnSpot( this ), GetLocalAngles(), GetOwnerEntity() ); - if ( pNewWeapon ) + if (pNewWeapon) { +#ifdef MAPBASE + pNewWeapon->KeyValue("weaponscriptname", GetClassname()); // pass along the script name + pNewWeapon->Precache(); // precache it here to avoid prediction errors + pNewWeapon->SetModel(GetWorldModel()); // fix bbox for world model +#endif // MAPBASE pNewWeapon->AddEffects( EF_NODRAW );// invisible for now pNewWeapon->SetTouch( NULL );// no touch pNewWeapon->SetThink( &CBaseCombatWeapon::AttemptToMaterialize ); @@ -215,7 +220,7 @@ CBaseEntity* CBaseCombatWeapon::Respawn( void ) } else { - Warning("Respawn failed to create %s!\n", GetClassname() ); + Warning("Respawn failed to create %s!\n", GetClassname()); } return pNewWeapon; diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index 77b7b46d898..ddeaf8fdf4c 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -645,9 +645,10 @@ class CBaseEntity : public IServerEntity const char* GetPreTemplateName(); // Not threadsafe. Get the name stripped of template unique decoration bool NameMatches( const char *pszNameOrWildcard ); - bool ClassMatches( const char *pszClassOrWildcard ); bool NameMatches( string_t nameStr ); - bool ClassMatches( string_t nameStr ); + + virtual bool ClassMatches( string_t nameStr ); + virtual bool ClassMatches( const char *pszClassOrWildcard ); private: bool NameMatchesComplex( const char *pszNameOrWildcard ); diff --git a/sp/src/game/server/gameweaponmanager.cpp b/sp/src/game/server/gameweaponmanager.cpp index 68bced8a0de..44a62266192 100644 --- a/sp/src/game/server/gameweaponmanager.cpp +++ b/sp/src/game/server/gameweaponmanager.cpp @@ -87,7 +87,7 @@ void WeaponManager_AmmoMod( CBaseCombatWeapon *pWeapon ) { for ( int i = 0; i < g_Managers.Count(); i++ ) { - if ( g_Managers[i]->m_iszWeaponName == pWeapon->m_iClassname ) + if (FClassnameIs(pWeapon, g_Managers[i]->m_iszWeaponName.ToCStr())) { int iNewClip = (int)(pWeapon->m_iClip1 * g_Managers[i]->m_flAmmoMod); int iNewRandomClip = iNewClip + RandomInt( -2, 2 ); @@ -111,7 +111,7 @@ void WeaponManager_AddManaged( CBaseEntity *pWeapon ) { for ( int i = 0; i < g_Managers.Count(); i++ ) { - if ( g_Managers[i]->m_iszWeaponName == pWeapon->m_iClassname ) + if (FClassnameIs(pWeapon, g_Managers[i]->m_iszWeaponName.ToCStr())) { Assert( g_Managers[i]->m_ManagedNonWeapons.Find( pWeapon ) == g_Managers[i]->m_ManagedNonWeapons.InvalidIndex() ); g_Managers[i]->m_ManagedNonWeapons.AddToTail( pWeapon ); @@ -124,7 +124,7 @@ void WeaponManager_RemoveManaged( CBaseEntity *pWeapon ) { for ( int i = 0; i < g_Managers.Count(); i++ ) { - if ( g_Managers[i]->m_iszWeaponName == pWeapon->m_iClassname ) + if (FClassnameIs(pWeapon, g_Managers[i]->m_iszWeaponName.ToCStr())) { int j = g_Managers[i]->m_ManagedNonWeapons.Find( pWeapon ); if ( j != g_Managers[i]->m_ManagedNonWeapons.InvalidIndex() ) @@ -213,7 +213,7 @@ void CGameWeaponManager::Think() CBaseEntity *pEntity = m_ManagedNonWeapons[i]; if ( pEntity ) { - Assert( pEntity->m_iClassname == m_iszWeaponName ); + Assert(FClassnameIs(pEntity, m_iszWeaponName.ToCStr())); if ( !pEntity->IsEffectActive( EF_NODRAW ) ) { candidates.AddToTail( pEntity ); diff --git a/sp/src/game/server/hl2/npc_alyx_episodic.cpp b/sp/src/game/server/hl2/npc_alyx_episodic.cpp index dd5a35b0dda..609bb67ed4b 100644 --- a/sp/src/game/server/hl2/npc_alyx_episodic.cpp +++ b/sp/src/game/server/hl2/npc_alyx_episodic.cpp @@ -2585,7 +2585,7 @@ void CNPC_Alyx::Weapon_Drop( CBaseCombatWeapon *pWeapon, const Vector *pvecTarge { BaseClass::Weapon_Drop( pWeapon, pvecTarget, pVelocity ); - if( pWeapon && pWeapon->ClassMatches( CLASSNAME_ALYXGUN ) ) + if(pWeapon && pWeapon->ClassMatches(CLASSNAME_ALYXGUN.ToCStr())) { pWeapon->SUB_Remove(); } @@ -3256,7 +3256,7 @@ void CNPC_Alyx::OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombat void CNPC_Alyx::OnGivenWeapon( CBaseCombatWeapon *pNewWeapon ) { // HACK: This causes Alyx to pull her gun from a holstered position - if ( pNewWeapon->ClassMatches( CLASSNAME_ALYXGUN ) ) + if (pNewWeapon->ClassMatches(CLASSNAME_ALYXGUN.ToCStr())) { // Put it away so we can pull it out properly GetActiveWeapon()->Holster(); @@ -3279,7 +3279,7 @@ void CNPC_Alyx::Weapon_Equip( CBaseCombatWeapon *pWeapon ) //----------------------------------------------------------------------------- bool CNPC_Alyx::Weapon_CanUse( CBaseCombatWeapon *pWeapon ) { - if( !pWeapon->ClassMatches( CLASSNAME_SHOTGUN ) ) + if(!pWeapon->ClassMatches(CLASSNAME_SHOTGUN.ToCStr())) return false; return BaseClass::Weapon_CanUse( pWeapon ); diff --git a/sp/src/game/server/hl2/npc_citizen17.cpp b/sp/src/game/server/hl2/npc_citizen17.cpp index c66ca4e5237..ad225385918 100644 --- a/sp/src/game/server/hl2/npc_citizen17.cpp +++ b/sp/src/game/server/hl2/npc_citizen17.cpp @@ -924,18 +924,19 @@ void CNPC_Citizen::FixupMattWeapon() if ( pWeapon && pWeapon->ClassMatches( "weapon_crowbar" ) && NameMatches( "matt" ) ) #endif { - Weapon_Drop( pWeapon ); - UTIL_Remove( pWeapon ); - pWeapon = (CBaseCombatWeapon *)CREATE_UNSAVED_ENTITY( CMattsPipe, "weapon_crowbar" ); - pWeapon->SetName( AllocPooledString( "matt_weapon" ) ); - DispatchSpawn( pWeapon ); + variant_t tmpVar; + + tmpVar.SetString(MAKE_STRING("weapon_mattpipe")); + pWeapon->AcceptInput("ChangeScript", this, this, tmpVar, 0); + + //weapon doesn't save the prevent pick up flag when dropped, set the flag when needed (death in this case) + tmpVar.SetString(MAKE_STRING("OnDeath matt_weapon:AddOutput:spawnflags 2:0.00:1")); + AcceptInput("AddOutput", this, this, tmpVar, 0); #ifdef DEBUG extern bool g_bReceivedChainedActivate; g_bReceivedChainedActivate = false; #endif - pWeapon->Activate(); - Weapon_Equip( pWeapon ); } } diff --git a/sp/src/game/server/hl2/npc_combine.cpp b/sp/src/game/server/hl2/npc_combine.cpp index c1375eb7348..833153ad59a 100644 --- a/sp/src/game/server/hl2/npc_combine.cpp +++ b/sp/src/game/server/hl2/npc_combine.cpp @@ -3876,7 +3876,7 @@ WeaponProficiency_t CNPC_Combine::CalcWeaponProficiency( CBaseCombatWeapon *pWea //----------------------------------------------------------------------------- bool CNPC_Combine::HasShotgun() { - if( GetActiveWeapon() && GetActiveWeapon()->m_iClassname == s_iszShotgunClassname ) + if (GetActiveWeapon() && FClassnameIs(GetActiveWeapon(), s_iszShotgunClassname.ToCStr())) { return true; } diff --git a/sp/src/game/server/hl2/npc_playercompanion.cpp b/sp/src/game/server/hl2/npc_playercompanion.cpp index 660cb218aec..c0653d59d3b 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.cpp +++ b/sp/src/game/server/hl2/npc_playercompanion.cpp @@ -398,11 +398,11 @@ Disposition_t CNPC_PlayerCompanion::IRelationType( CBaseEntity *pTarget ) pTarget->IsNPC() && ((CAI_BaseNPC *)pTarget)->GetActiveWeapon() && #ifdef MAPBASE - (EntIsClass( ((CAI_BaseNPC *)pTarget)->GetActiveWeapon(), gm_iszShotgunClassname ) && - ( !GetActiveWeapon() || !EntIsClass( GetActiveWeapon(), gm_iszShotgunClassname ) ) ) ) + (EntIsClass( ((CAI_BaseNPC *)pTarget)->GetActiveWeapon(), gm_iszShotgunClassname.ToCStr() ) && + ( !GetActiveWeapon() || !EntIsClass( GetActiveWeapon(), gm_iszShotgunClassname.ToCStr() ) ) ) ) #else - ((CAI_BaseNPC *)pTarget)->GetActiveWeapon()->ClassMatches( gm_iszShotgunClassname ) && - ( !GetActiveWeapon() || !GetActiveWeapon()->ClassMatches( gm_iszShotgunClassname ) ) ) + ((CAI_BaseNPC *)pTarget)->GetActiveWeapon()->ClassMatches( gm_iszShotgunClassname.ToCStr() ) && + ( !GetActiveWeapon() || !GetActiveWeapon()->ClassMatches( gm_iszShotgunClassname.ToCStr() ) ) ) #endif { if ( (pTarget->GetAbsOrigin() - GetAbsOrigin()).LengthSqr() < Square( 25 * 12 ) ) @@ -2816,7 +2816,7 @@ bool CNPC_PlayerCompanion::Weapon_CanUse( CBaseCombatWeapon *pWeapon ) #ifdef MAPBASE if (EntIsClass(pWeapon, gm_iszShotgunClassname)) #else - if( pWeapon->ClassMatches( gm_iszShotgunClassname ) ) + f(pWeapon->ClassMatches(gm_iszShotgunClassname.ToCStr())) #endif { return (NumWeaponsInSquad("weapon_shotgun") < 1 ); diff --git a/sp/src/game/server/mapbase/GlobalStrings.h b/sp/src/game/server/mapbase/GlobalStrings.h index 13c4775a6f8..c80d0415a1a 100644 --- a/sp/src/game/server/mapbase/GlobalStrings.h +++ b/sp/src/game/server/mapbase/GlobalStrings.h @@ -74,7 +74,7 @@ inline bool EntIsClass( CBaseEntity *ent, string_t str2 ) // Since classnames are pooled, the global string and the entity's classname should point to the same string in memory. // As long as this rule is preserved, we only need a pointer comparison. A string comparison isn't necessary. - return ent->m_iClassname == str2; + return ent->GetClassname() == str2.ToCStr(); } // ------------------------------------------------------------- diff --git a/sp/src/game/server/player_command.cpp b/sp/src/game/server/player_command.cpp index d5a6a1f08d8..7614babee02 100644 --- a/sp/src/game/server/player_command.cpp +++ b/sp/src/game/server/player_command.cpp @@ -393,7 +393,7 @@ void CPlayerMove::RunCommand ( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper if ( weapon ) { VPROF( "player->SelectItem()" ); - player->SelectItem( weapon->GetName(), ucmd->weaponsubtype ); + player->SelectItem( weapon->GetClassname(), ucmd->weaponsubtype ); } } diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index bfba16e3e04..c69ff190bcd 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -38,6 +38,10 @@ #endif +#ifdef MAPBASE + #include "gamestringpool.h" +#endif + // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -321,7 +325,11 @@ void CBaseCombatWeapon::Precache( void ) else { // Couldn't read data file, remove myself - Warning( "Error reading weapon data file for: %s\n", GetWeaponScriptName() ); +#ifdef MAPBASE + Warning( "Error reading weapon data file for classname \"%s\" with script \"%s\".\n", GetClassname(false), GetClassname()) +#else + Warning( "Error reading weapon data file for: %s\n", GetClassname() ); +#endif // Remove( ); //don't remove, this gets released soon! } } @@ -361,6 +369,19 @@ bool CBaseCombatWeapon::KeyValue( const char *szKeyName, const char *szValue ) { SetAmmoFromMapper(atof(szValue), true); } + if (FStrEq(szKeyName, "weaponscriptname")) + { + if (szValue[0] != '\0') //if not empty - use val, else get real classname + { + Q_strncpy(m_iszWeaponScriptName.GetForModify(), szValue, MAX_WEAPON_STRING); + } + else + { + Q_strncpy(m_iszWeaponScriptName.GetForModify(), GetClassname(false), MAX_WEAPON_STRING); + } + + return true; + } else if ( FStrEq(szKeyName, "spawnflags") ) { m_spawnflags = atoi(szValue); @@ -382,6 +403,31 @@ bool CBaseCombatWeapon::GetKeyValue( const char *szKeyName, char *szValue, int i { return BaseClass::GetKeyValue(szKeyName, szValue, iMaxLen); } + +//----------------------------------------------------------------------------- +// Purpose: Returns weaponscriptname to make weapons of the same classname working properly with the rest of the code. +// Putting false will return the real classname, instead of weaponscriptname. +//----------------------------------------------------------------------------- +inline const char* CBaseCombatWeapon::GetClassname(bool bUseWeaponScriptName) +{ + if (bUseWeaponScriptName && Q_strcmp(m_iszWeaponScriptName.Get(), "") > 0) + { + if (Q_strcmp(m_iszWeaponScriptName.Get(), "") > 0) + { + return m_iszWeaponScriptName.Get(); + } + } + + return BaseClass::GetClassname(); +} + +//----------------------------------------------------------------------------- +// Purpose: This is used by FClassnameIs to compare classname strings, we replace it with script name. +//----------------------------------------------------------------------------- +bool CBaseCombatWeapon::ClassMatches(const char* pszClassOrWildcard) +{ + return Matcher_NamesMatch(pszClassOrWildcard, GetClassname()); +} #endif //----------------------------------------------------------------------------- @@ -1966,6 +2012,109 @@ void CBaseCombatWeapon::InputHideWeapon( inputdata_t &inputdata ) SetWeaponVisible( false ); } } + +ConVar sv_weapon_clips_reset_mode("sv_weapon_clips_reset_mode", "1", + FCVAR_REPLICATED | FCVAR_CHEAT, + "Sets the way to reset clips:\n0 - No reset at all.\n1 - Set max clip value.\n2 - Set max clip value if more then max clip.", + true, 0.0f, true, 2.0f +); + +ConVar sv_weapon_vm_anim_reset_mode("sv_weapon_vm_anim_reset_mode", "0", + FCVAR_REPLICATED | FCVAR_CHEAT, + "Animation to set after weapon script change, 0 to use idle animation, 1 to use deploy animation.", + true, 0, true, 1 +); + +#ifndef CLIENT_DLL +//----------------------------------------------------------------------------- +// Purpose: Input to change the weapon script name and re-Precache +//----------------------------------------------------------------------------- +void CBaseCombatWeapon::InputChangeScript(inputdata_t& inputdata) +{ + const char* pszNewScript = inputdata.value.String(); + + //don't update if empty or already used this script + if (!pszNewScript || !pszNewScript[0] || FClassnameIs(this, pszNewScript)) + return; + + //don't update if other weapon that owns my owner uses the same script + if (GetOwner() && GetOwner()->Weapon_OwnsThisType(pszNewScript)) + return; + + //copy new data for networked and stored + Q_strncpy(m_iszWeaponScriptName.GetForModify(), pszNewScript, MAX_WEAPON_STRING); + + //finish reload before update + if (m_bInReload) + { + FinishReload(); + } + + m_iNeedsUpdate++; //trigger client update + + Precache(); //update with new script + + if (GetOwner() && GetOwner()->IsPlayer()) + { + //this updates wpn's vm at the same time as wpn's script, instead of waiting 2-6 seconds + if (GetOwner()->GetActiveWeapon() == this) + SetViewModel(); + + SetModel(GetViewModel()); //this fixes wrong sequence nums (DOESN'T AFFECT WORLD MODEL) + + //use deploy anim if we want + if (GetOwner()->GetActiveWeapon() == this) + { + if (sv_weapon_vm_anim_reset_mode.GetBool()) + { + Deploy(); + } + else + { + SendWeaponAnim(ACT_VM_IDLE); + } + } + } + + //if i have no owner - reset collsion model with bbox + check if my new wm has collision + //NOTE: no need if owned by NPC or plr as they update collision when drop weapons + if (!GetOwner()) + { + SetModel(GetWorldModel()); + VPhysicsDestroyObject(); + + if (!VPhysicsInitNormal(SOLID_BBOX, GetSolidFlags() | FSOLID_TRIGGER, false)) + { + SetMoveType(MOVETYPE_NONE); + SetSolid(SOLID_BBOX); + AddSolidFlags(FSOLID_TRIGGER); + } + } + + //we don't want to reset clips at all, return + if (sv_weapon_clips_reset_mode.GetInt() == 0) + return; + + //we want to set max clipw vals + if (sv_weapon_clips_reset_mode.GetInt() == 1) + { + if (UsesClipsForAmmo1()) + m_iClip1 = GetMaxClip1(); + + if (UsesClipsForAmmo2()) + m_iClip2 = GetMaxClip2(); + } + + //we want to set max clip only if this weapon has more ammo in clips than max + if (sv_weapon_clips_reset_mode.GetInt() == 2) + { + if (UsesClipsForAmmo1() && m_iClip1 > GetMaxClip1()) + m_iClip1 = GetMaxClip1(); + + if (UsesClipsForAmmo2() && m_iClip2 > GetMaxClip2()) + m_iClip2 = GetMaxClip2(); + } +} #endif //----------------------------------------------------------------------------- @@ -3243,6 +3392,11 @@ BEGIN_DATADESC( CBaseCombatWeapon ) DEFINE_FIELD( m_bAltFireHudHintDisplayed, FIELD_BOOLEAN ), DEFINE_FIELD( m_flHudHintPollTime, FIELD_TIME ), DEFINE_FIELD( m_flHudHintMinDisplayTime, FIELD_TIME ), + +#ifdef MAPBASE + DEFINE_AUTO_ARRAY( m_iszWeaponScriptName, FIELD_CHARACTER ), + DEFINE_FIELD( m_iNeedsUpdate, FIELD_INTEGER ), +#endif // Just to quiet classcheck.. this field exists only on the client // DEFINE_FIELD( m_iOldState, FIELD_INTEGER ), @@ -3270,6 +3424,7 @@ BEGIN_DATADESC( CBaseCombatWeapon ) DEFINE_INPUTFUNC( FIELD_VOID, "BreakConstraint", InputBreakConstraint ), DEFINE_INPUTFUNC( FIELD_VOID, "ForcePrimaryFire", InputForcePrimaryFire ), DEFINE_INPUTFUNC( FIELD_VOID, "ForceSecondaryFire", InputForceSecondaryFire ), + DEFINE_INPUTFUNC( FIELD_STRING, "ChangeScript", InputChangeScript ), #endif // Outputs @@ -3406,6 +3561,10 @@ BEGIN_NETWORK_TABLE_NOBASE( CBaseCombatWeapon, DT_LocalWeaponData ) SendPropInt( SENDINFO( m_nViewModelIndex ), VIEWMODEL_INDEX_BITS, SPROP_UNSIGNED ), SendPropInt( SENDINFO( m_bFlipViewModel ) ), + +#ifdef MAPBASE + SendPropInt( SENDINFO( m_iNeedsUpdate ) ), +#endif #if defined( TF_DLL ) SendPropExclude( "DT_AnimTimeMustBeFirst" , "m_flAnimTime" ), @@ -3420,6 +3579,10 @@ BEGIN_NETWORK_TABLE_NOBASE( CBaseCombatWeapon, DT_LocalWeaponData ) RecvPropInt( RECVINFO( m_nViewModelIndex ) ), RecvPropBool( RECVINFO( m_bFlipViewModel ) ), + +#ifdef MAPBASE + RecvPropInt( RECVINFO(m_iNeedsUpdate) ), +#endif #endif END_NETWORK_TABLE() @@ -3430,14 +3593,14 @@ BEGIN_NETWORK_TABLE(CBaseCombatWeapon, DT_BaseCombatWeapon) SendPropDataTable("LocalActiveWeaponData", 0, &REFERENCE_SEND_TABLE(DT_LocalActiveWeaponData), SendProxy_SendActiveLocalWeaponDataTable ), SendPropModelIndex( SENDINFO(m_iViewModelIndex) ), SendPropModelIndex( SENDINFO(m_iWorldModelIndex) ), -#ifdef MAPBASE - SendPropModelIndex( SENDINFO(m_iDroppedModelIndex) ), -#endif SendPropInt( SENDINFO(m_iState ), 8, SPROP_UNSIGNED ), SendPropEHandle( SENDINFO(m_hOwner) ), - + #ifdef MAPBASE + SendPropModelIndex( SENDINFO(m_iDroppedModelIndex) ), + SendPropString( SENDINFO(m_iszWeaponScriptName) ), SendPropInt( SENDINFO(m_spawnflags), 8, SPROP_UNSIGNED ), + SendPropInt( SENDINFO(m_iNeedsUpdate), 0, SPROP_UNSIGNED ), #endif #else @@ -3445,14 +3608,14 @@ BEGIN_NETWORK_TABLE(CBaseCombatWeapon, DT_BaseCombatWeapon) RecvPropDataTable("LocalActiveWeaponData", 0, 0, &REFERENCE_RECV_TABLE(DT_LocalActiveWeaponData)), RecvPropInt( RECVINFO(m_iViewModelIndex)), RecvPropInt( RECVINFO(m_iWorldModelIndex)), -#ifdef MAPBASE - RecvPropInt( RECVINFO(m_iDroppedModelIndex) ), -#endif RecvPropInt( RECVINFO(m_iState )), RecvPropEHandle( RECVINFO(m_hOwner ) ), - + #ifdef MAPBASE + RecvPropInt( RECVINFO(m_iDroppedModelIndex) ), RecvPropInt( RECVINFO( m_spawnflags ) ), + RecvPropInt( RECVINFO(m_iNeedsUpdate) ), + RecvPropString( RECVINFO(m_iszWeaponScriptName) ), #endif #endif diff --git a/sp/src/game/shared/basecombatweapon_shared.h b/sp/src/game/shared/basecombatweapon_shared.h index d7fd5c47d4e..514fc2eeff7 100644 --- a/sp/src/game/shared/basecombatweapon_shared.h +++ b/sp/src/game/shared/basecombatweapon_shared.h @@ -217,6 +217,8 @@ class CBaseCombatWeapon : public BASECOMBATWEAPON_DERIVED_FROM void SetAmmoFromMapper( float flAmmo, bool bSecondary = false ); virtual bool KeyValue( const char *szKeyName, const char *szValue ); virtual bool GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen ); + inline const char* GetClassname( bool bUseWeaponScriptName = true ); + virtual bool ClassMatches( const char* pszClassOrWildcard ); #endif void MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType ); @@ -569,6 +571,7 @@ class CBaseCombatWeapon : public BASECOMBATWEAPON_DERIVED_FROM void InputForceFire( inputdata_t &inputdata, bool bSecondary = false ); void InputForcePrimaryFire( inputdata_t &inputdata ); void InputForceSecondaryFire( inputdata_t &inputdata ); + void InputChangeScript(inputdata_t& inputdata); // Input to change the weapon script name and re-Precache #endif void InputHideWeapon( inputdata_t &inputdata ); void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); @@ -734,6 +737,14 @@ class CBaseCombatWeapon : public BASECOMBATWEAPON_DERIVED_FROM float m_fFireDuration; // The amount of time that the weapon has sustained firing int m_iSubType; +#ifdef MAPBASE +#ifdef CLIENT_DLL + int m_iOldNeedsUpdate = 0; //client's variable to compare with networked and decide if update is needed +#endif + CNetworkString( m_iszWeaponScriptName, MAX_WEAPON_STRING ); //networked weapon script name + CNetworkVar(int, m_iNeedsUpdate); //mark for client in case if weapon script update is wanted +#endif + float m_flUnlockTime; EHANDLE m_hLocker; // Who locked this weapon. diff --git a/sp/src/game/shared/weapon_parse.h b/sp/src/game/shared/weapon_parse.h index 0d74d95b2c3..1fed922c72f 100644 --- a/sp/src/game/shared/weapon_parse.h +++ b/sp/src/game/shared/weapon_parse.h @@ -105,6 +105,9 @@ class FileWeaponInfo_t // SHARED char szClassName[MAX_WEAPON_STRING]; char szPrintName[MAX_WEAPON_STRING]; // Name for showing in HUD, etc. +#ifdef MAPBASE + char szWeaponScriptName[MAX_WEAPON_STRING]; +#endif char szViewModel[MAX_WEAPON_STRING]; // View model of this weapon char szWorldModel[MAX_WEAPON_STRING]; // Model of this weapon seen carried by the player From 5a43eefcba56cca91d25850352e0fc2ce9114b65 Mon Sep 17 00:00:00 2001 From: "MyGamepedia (Sorry For My English)" <103366204+MyGamepedia@users.noreply.github.com> Date: Mon, 23 Feb 2026 10:03:58 +0200 Subject: [PATCH 2/8] fixes for prev commit --- sp/src/game/server/hl2/npc_citizen17.cpp | 8 +++ .../game/shared/basecombatweapon_shared.cpp | 53 ++++++++++--------- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/sp/src/game/server/hl2/npc_citizen17.cpp b/sp/src/game/server/hl2/npc_citizen17.cpp index ad225385918..f86a28e8d92 100644 --- a/sp/src/game/server/hl2/npc_citizen17.cpp +++ b/sp/src/game/server/hl2/npc_citizen17.cpp @@ -924,6 +924,7 @@ void CNPC_Citizen::FixupMattWeapon() if ( pWeapon && pWeapon->ClassMatches( "weapon_crowbar" ) && NameMatches( "matt" ) ) #endif { +#ifdef MAPBASE variant_t tmpVar; tmpVar.SetString(MAKE_STRING("weapon_mattpipe")); @@ -932,6 +933,13 @@ void CNPC_Citizen::FixupMattWeapon() //weapon doesn't save the prevent pick up flag when dropped, set the flag when needed (death in this case) tmpVar.SetString(MAKE_STRING("OnDeath matt_weapon:AddOutput:spawnflags 2:0.00:1")); AcceptInput("AddOutput", this, this, tmpVar, 0); +#else + Weapon_Drop( pWeapon ); + UTIL_Remove( pWeapon ); + pWeapon = (CBaseCombatWeapon *)CREATE_UNSAVED_ENTITY( CMattsPipe, "weapon_crowbar" ); + pWeapon->SetName( AllocPooledString( "matt_weapon" ) ); + DispatchSpawn( pWeapon ); +#endif #ifdef DEBUG extern bool g_bReceivedChainedActivate; diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index c69ff190bcd..550ba12f28e 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -64,6 +64,20 @@ ConVar tf_weapon_criticals_bucket_bottom( "tf_weapon_criticals_bucket_bottom", " ConVar tf_weapon_criticals_bucket_default( "tf_weapon_criticals_bucket_default", "300.0", FCVAR_REPLICATED | FCVAR_CHEAT ); #endif // TF +#ifdef MAPBASE +ConVar sv_weapon_clips_reset_mode("sv_weapon_clips_reset_mode", "1", + FCVAR_REPLICATED | FCVAR_CHEAT, + "Sets the way to reset clips:\n0 - No reset at all.\n1 - Set max clip value.\n2 - Set max clip value if more then max clip.", + true, 0.0f, true, 2.0f +); + +ConVar sv_weapon_vm_anim_reset_mode("sv_weapon_vm_anim_reset_mode", "0", + FCVAR_REPLICATED | FCVAR_CHEAT, + "Animation to set after weapon script change, 0 to use idle animation, 1 to use deploy animation.", + true, 0, true, 1 +); +#endif + CBaseCombatWeapon::CBaseCombatWeapon() { // Constructor must call this @@ -1999,33 +2013,7 @@ void CBaseCombatWeapon::InputForceSecondaryFire( inputdata_t &inputdata ) { InputForceFire(inputdata, true); } -#endif -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CBaseCombatWeapon::InputHideWeapon( inputdata_t &inputdata ) -{ - // Only hide if we're still the active weapon. If we're not the active weapon - if ( GetOwner() && GetOwner()->GetActiveWeapon() == this ) - { - SetWeaponVisible( false ); - } -} - -ConVar sv_weapon_clips_reset_mode("sv_weapon_clips_reset_mode", "1", - FCVAR_REPLICATED | FCVAR_CHEAT, - "Sets the way to reset clips:\n0 - No reset at all.\n1 - Set max clip value.\n2 - Set max clip value if more then max clip.", - true, 0.0f, true, 2.0f -); - -ConVar sv_weapon_vm_anim_reset_mode("sv_weapon_vm_anim_reset_mode", "0", - FCVAR_REPLICATED | FCVAR_CHEAT, - "Animation to set after weapon script change, 0 to use idle animation, 1 to use deploy animation.", - true, 0, true, 1 -); - -#ifndef CLIENT_DLL //----------------------------------------------------------------------------- // Purpose: Input to change the weapon script name and re-Precache //----------------------------------------------------------------------------- @@ -2117,6 +2105,19 @@ void CBaseCombatWeapon::InputChangeScript(inputdata_t& inputdata) } #endif +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseCombatWeapon::InputHideWeapon( inputdata_t &inputdata ) +{ + // Only hide if we're still the active weapon. If we're not the active weapon + if ( GetOwner() && GetOwner()->GetActiveWeapon() == this ) + { + SetWeaponVisible( false ); + } +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- From fdc902fbee40ed0a93f3c2fddbcd55ae5fcec41a Mon Sep 17 00:00:00 2001 From: "MyGamepedia (Sorry For My English)" <103366204+MyGamepedia@users.noreply.github.com> Date: Wed, 25 Feb 2026 03:18:57 +0200 Subject: [PATCH 3/8] added check if we have a valid script file for the input --- sp/src/game/shared/basecombatweapon_shared.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index 550ba12f28e..81a22e2251b 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -2028,6 +2028,24 @@ void CBaseCombatWeapon::InputChangeScript(inputdata_t& inputdata) //don't update if other weapon that owns my owner uses the same script if (GetOwner() && GetOwner()->Weapon_OwnsThisType(pszNewScript)) return; + + char sz[128]; + Q_snprintf(sz, sizeof(sz), "scripts/%s", pszNewScript); + + KeyValues* pKV = ReadEncryptedKVFile(filesystem, sz, GetEncryptionKey(), +#if defined( DOD_DLL ) + true // Only read .ctx files! +#else + false +#endif + ); + + //don't if file doesn't exists + if (!pKV) + { + Warning("Error reading weapon data file \"%s\".\n", pszNewScript); + return; + } //copy new data for networked and stored Q_strncpy(m_iszWeaponScriptName.GetForModify(), pszNewScript, MAX_WEAPON_STRING); From 6da6d8a7efabb05806833bea54f66cf45c3d8ddd Mon Sep 17 00:00:00 2001 From: "MyGamepedia (Sorry For My English)" <103366204+MyGamepedia@users.noreply.github.com> Date: Wed, 25 Feb 2026 16:54:31 +0200 Subject: [PATCH 4/8] Update basecombatweapon_shared.cpp --- sp/src/game/shared/basecombatweapon_shared.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index 81a22e2251b..3c041f95ba0 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -340,7 +340,7 @@ void CBaseCombatWeapon::Precache( void ) { // Couldn't read data file, remove myself #ifdef MAPBASE - Warning( "Error reading weapon data file for classname \"%s\" with script \"%s\".\n", GetClassname(false), GetClassname()) + Warning( "Error reading weapon data file for classname \"%s\" with script \"%s\".\n", GetClassname(false), GetClassname()); #else Warning( "Error reading weapon data file for: %s\n", GetClassname() ); #endif From 07f82386ebfa8268db9f21dc18ef35fc65a53aa0 Mon Sep 17 00:00:00 2001 From: "MyGamepedia (Sorry For My English)" <103366204+MyGamepedia@users.noreply.github.com> Date: Wed, 25 Feb 2026 17:05:28 +0200 Subject: [PATCH 5/8] Update npc_combine.cpp --- sp/src/game/server/hl2/npc_combine.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sp/src/game/server/hl2/npc_combine.cpp b/sp/src/game/server/hl2/npc_combine.cpp index 833153ad59a..d5781cf4adb 100644 --- a/sp/src/game/server/hl2/npc_combine.cpp +++ b/sp/src/game/server/hl2/npc_combine.cpp @@ -3824,7 +3824,7 @@ void CNPC_Combine::OnEndMoveAndShoot() WeaponProficiency_t CNPC_Combine::CalcWeaponProficiency( CBaseCombatWeapon *pWeapon ) { #ifdef MAPBASE - if( pWeapon->ClassMatches( gm_isz_class_AR2 ) ) + if( pWeapon->ClassMatches( gm_isz_class_AR2.ToCStr() ) ) #else if( FClassnameIs( pWeapon, "weapon_ar2" ) ) #endif @@ -3839,7 +3839,7 @@ WeaponProficiency_t CNPC_Combine::CalcWeaponProficiency( CBaseCombatWeapon *pWea } } #ifdef MAPBASE - else if( pWeapon->ClassMatches( gm_isz_class_Shotgun ) ) + else if( pWeapon->ClassMatches( gm_isz_class_Shotgun.ToCStr() ) ) #else else if( FClassnameIs( pWeapon, "weapon_shotgun" ) ) #endif @@ -3854,7 +3854,7 @@ WeaponProficiency_t CNPC_Combine::CalcWeaponProficiency( CBaseCombatWeapon *pWea return WEAPON_PROFICIENCY_PERFECT; } #ifdef MAPBASE - else if( pWeapon->ClassMatches( gm_isz_class_SMG1 ) ) + else if( pWeapon->ClassMatches( gm_isz_class_SMG1.ToCStr() ) ) #else else if( FClassnameIs( pWeapon, "weapon_smg1" ) ) #endif @@ -3862,7 +3862,7 @@ WeaponProficiency_t CNPC_Combine::CalcWeaponProficiency( CBaseCombatWeapon *pWea return WEAPON_PROFICIENCY_GOOD; } #ifdef MAPBASE - else if ( pWeapon->ClassMatches( gm_isz_class_Pistol ) ) + else if ( pWeapon->ClassMatches( gm_isz_class_Pistol.ToCStr() ) ) { // Mods which need a lower soldier pistol accuracy can either change this value or use proficiency override in Hammer. return WEAPON_PROFICIENCY_VERY_GOOD; From 4387dff61619e2eaa10604c840eb9e5aa6b66c1a Mon Sep 17 00:00:00 2001 From: "MyGamepedia (Sorry For My English)" <103366204+MyGamepedia@users.noreply.github.com> Date: Wed, 25 Feb 2026 17:14:28 +0200 Subject: [PATCH 6/8] included mapbase_matchers_base.h + npc_playercompanion.cpp fix --- sp/src/game/server/hl2/npc_playercompanion.cpp | 4 ++-- sp/src/game/shared/basecombatweapon_shared.cpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/hl2/npc_playercompanion.cpp b/sp/src/game/server/hl2/npc_playercompanion.cpp index c0653d59d3b..53dc8126fd6 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.cpp +++ b/sp/src/game/server/hl2/npc_playercompanion.cpp @@ -398,8 +398,8 @@ Disposition_t CNPC_PlayerCompanion::IRelationType( CBaseEntity *pTarget ) pTarget->IsNPC() && ((CAI_BaseNPC *)pTarget)->GetActiveWeapon() && #ifdef MAPBASE - (EntIsClass( ((CAI_BaseNPC *)pTarget)->GetActiveWeapon(), gm_iszShotgunClassname.ToCStr() ) && - ( !GetActiveWeapon() || !EntIsClass( GetActiveWeapon(), gm_iszShotgunClassname.ToCStr() ) ) ) ) + (EntIsClass( ((CAI_BaseNPC *)pTarget)->GetActiveWeapon(), gm_iszShotgunClassname ) && + ( !GetActiveWeapon() || !EntIsClass( GetActiveWeapon(), gm_iszShotgunClassname ) ) ) ) #else ((CAI_BaseNPC *)pTarget)->GetActiveWeapon()->ClassMatches( gm_iszShotgunClassname.ToCStr() ) && ( !GetActiveWeapon() || !GetActiveWeapon()->ClassMatches( gm_iszShotgunClassname.ToCStr() ) ) ) diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index 3c041f95ba0..40bb48a8a0c 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -40,6 +40,7 @@ #ifdef MAPBASE #include "gamestringpool.h" + #include "mapbase_matchers_base.h" #endif // memdbgon must be the last include file in a .cpp file!!! From 2a1df665582ae76b2870f4212b4d87575ee071ca Mon Sep 17 00:00:00 2001 From: "MyGamepedia (Sorry For My English)" <103366204+MyGamepedia@users.noreply.github.com> Date: Wed, 25 Feb 2026 17:36:37 +0200 Subject: [PATCH 7/8] now this should compile on both windows and linux --- sp/src/game/shared/basecombatweapon_shared.cpp | 7 ++----- sp/src/game/shared/basecombatweapon_shared.h | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index 40bb48a8a0c..89366a02709 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -423,14 +423,11 @@ bool CBaseCombatWeapon::GetKeyValue( const char *szKeyName, char *szValue, int i // Purpose: Returns weaponscriptname to make weapons of the same classname working properly with the rest of the code. // Putting false will return the real classname, instead of weaponscriptname. //----------------------------------------------------------------------------- -inline const char* CBaseCombatWeapon::GetClassname(bool bUseWeaponScriptName) +const char* CBaseCombatWeapon::GetClassname(bool bUseWeaponScriptName) { if (bUseWeaponScriptName && Q_strcmp(m_iszWeaponScriptName.Get(), "") > 0) { - if (Q_strcmp(m_iszWeaponScriptName.Get(), "") > 0) - { - return m_iszWeaponScriptName.Get(); - } + return m_iszWeaponScriptName.Get(); } return BaseClass::GetClassname(); diff --git a/sp/src/game/shared/basecombatweapon_shared.h b/sp/src/game/shared/basecombatweapon_shared.h index 514fc2eeff7..2caabde4746 100644 --- a/sp/src/game/shared/basecombatweapon_shared.h +++ b/sp/src/game/shared/basecombatweapon_shared.h @@ -217,7 +217,7 @@ class CBaseCombatWeapon : public BASECOMBATWEAPON_DERIVED_FROM void SetAmmoFromMapper( float flAmmo, bool bSecondary = false ); virtual bool KeyValue( const char *szKeyName, const char *szValue ); virtual bool GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen ); - inline const char* GetClassname( bool bUseWeaponScriptName = true ); + const char* GetClassname( bool bUseWeaponScriptName = true ); virtual bool ClassMatches( const char* pszClassOrWildcard ); #endif From ccada7b07768e7b69364e152cac4cf146fa94f2b Mon Sep 17 00:00:00 2001 From: "MyGamepedia (Sorry For My English)" <103366204+MyGamepedia@users.noreply.github.com> Date: Wed, 25 Feb 2026 18:17:23 +0200 Subject: [PATCH 8/8] fixes after changes for linux compile The inline was important for client, so we now override CBaseEntity's GetClassname() method, to get real classname for a weapon - use m_iClassname directly. --- sp/src/game/server/baseentity.h | 4 ++-- sp/src/game/shared/basecombatweapon_shared.cpp | 10 +++------- sp/src/game/shared/basecombatweapon_shared.h | 2 +- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index ddeaf8fdf4c..5e41f871857 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -821,8 +821,8 @@ class CBaseEntity : public IServerEntity bool ReadKeyField( const char *varName, variant_t *var ); // classname access - void SetClassname( const char *className ); - const char* GetClassname(); + void SetClassname( const char *className ); + virtual const char* GetClassname(); // Debug Overlays void EntityText( int text_offset, const char *text, float flDuration, int r = 255, int g = 255, int b = 255, int a = 255 ); diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index 89366a02709..e2fec69190c 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -341,7 +341,7 @@ void CBaseCombatWeapon::Precache( void ) { // Couldn't read data file, remove myself #ifdef MAPBASE - Warning( "Error reading weapon data file for classname \"%s\" with script \"%s\".\n", GetClassname(false), GetClassname()); + Warning( "Error reading weapon data file for classname \"%s\" with script \"%s\".\n", m_iClassname, GetClassname()); #else Warning( "Error reading weapon data file for: %s\n", GetClassname() ); #endif @@ -390,10 +390,6 @@ bool CBaseCombatWeapon::KeyValue( const char *szKeyName, const char *szValue ) { Q_strncpy(m_iszWeaponScriptName.GetForModify(), szValue, MAX_WEAPON_STRING); } - else - { - Q_strncpy(m_iszWeaponScriptName.GetForModify(), GetClassname(false), MAX_WEAPON_STRING); - } return true; } @@ -423,9 +419,9 @@ bool CBaseCombatWeapon::GetKeyValue( const char *szKeyName, char *szValue, int i // Purpose: Returns weaponscriptname to make weapons of the same classname working properly with the rest of the code. // Putting false will return the real classname, instead of weaponscriptname. //----------------------------------------------------------------------------- -const char* CBaseCombatWeapon::GetClassname(bool bUseWeaponScriptName) +const char* CBaseCombatWeapon::GetClassname() { - if (bUseWeaponScriptName && Q_strcmp(m_iszWeaponScriptName.Get(), "") > 0) + if (Q_strcmp(m_iszWeaponScriptName.Get(), "") > 0) { return m_iszWeaponScriptName.Get(); } diff --git a/sp/src/game/shared/basecombatweapon_shared.h b/sp/src/game/shared/basecombatweapon_shared.h index 2caabde4746..d3962d73783 100644 --- a/sp/src/game/shared/basecombatweapon_shared.h +++ b/sp/src/game/shared/basecombatweapon_shared.h @@ -217,7 +217,7 @@ class CBaseCombatWeapon : public BASECOMBATWEAPON_DERIVED_FROM void SetAmmoFromMapper( float flAmmo, bool bSecondary = false ); virtual bool KeyValue( const char *szKeyName, const char *szValue ); virtual bool GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen ); - const char* GetClassname( bool bUseWeaponScriptName = true ); + virtual const char* GetClassname(); virtual bool ClassMatches( const char* pszClassOrWildcard ); #endif