Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
49943cb
custom weapon script loading
MyGamepedia Feb 22, 2026
5a43eef
fixes for prev commit
MyGamepedia Feb 23, 2026
fdc902f
added check if we have a valid script file for the input
MyGamepedia Feb 25, 2026
6da6d8a
Update basecombatweapon_shared.cpp
MyGamepedia Feb 25, 2026
07f8238
Update npc_combine.cpp
MyGamepedia Feb 25, 2026
4387dff
included mapbase_matchers_base.h + npc_playercompanion.cpp fix
MyGamepedia Feb 25, 2026
2a1df66
now this should compile on both windows and linux
MyGamepedia Feb 25, 2026
ccada7b
fixes after changes for linux compile
MyGamepedia Feb 25, 2026
14e9c1b
major fixes for custom weapon scripts
MyGamepedia Mar 7, 2026
b856318
prev commit fixes
MyGamepedia Mar 7, 2026
fb971e4
compile fix
MyGamepedia Mar 7, 2026
a83a1fa
more fixes
MyGamepedia Mar 7, 2026
e80cd4b
few more fixes
MyGamepedia Mar 7, 2026
3d3a046
reverts for ToCStr() + better wrn msg for weapon respawn
MyGamepedia Mar 7, 2026
0da4386
Update entitylist.cpp
MyGamepedia Mar 7, 2026
a281551
Update GlobalStrings.h
MyGamepedia Mar 7, 2026
00ce0c0
Update GlobalStrings.h
MyGamepedia Mar 7, 2026
b98790e
Update entitylist.cpp
MyGamepedia Mar 7, 2026
5561bc4
Update entitylist.cpp
MyGamepedia Mar 7, 2026
7f3ca9e
Update entitylist.cpp
MyGamepedia Mar 8, 2026
fd5ce27
Update entitylist.cpp
MyGamepedia Mar 8, 2026
9d5b43a
hope these are pre last fixes
MyGamepedia Mar 8, 2026
cb1ec16
prev commit impr
MyGamepedia Mar 8, 2026
fb3b7ff
final fix (maybe)
MyGamepedia Mar 9, 2026
efd465c
Update basecombatweapon_shared.cpp
MyGamepedia Mar 9, 2026
7c7575a
Update ai_basenpc.cpp
MyGamepedia Mar 9, 2026
34c254e
Update basecombatweapon_shared.cpp
MyGamepedia Mar 10, 2026
6007061
Update basecombatweapon_shared.cpp
MyGamepedia Mar 12, 2026
e6f41d0
Update multiplay_gamerules.cpp
MyGamepedia Mar 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions sp/src/game/client/c_basecombatweapon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,54 @@ 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, but not when restored (or it will cause hud issues)
if (m_iOldNeedsUpdate != m_iNeedsUpdate && !m_bJustRestored)
{
Precache();
m_iOldNeedsUpdate = m_iNeedsUpdate; //assign new value to prevent updates on client when we don't want

//don't reset local ammo value in mp, needed only for sp
if (gpGlobals->maxClients > 1)
return;

ConVarRef resetmode("sv_weapon_clips_reset_mode");

//we don't want to reset clips at all, return
if (!resetmode.IsValid() || resetmode.GetInt() == 0)
return;

//we want to set max clips vals
if (resetmode.GetInt() == 1)
{
if (UsesClipsForAmmo1())
m_iClip1 = GetMaxClip1();

if (UsesClipsForAmmo2())
m_iClip2 = GetMaxClip2();

return;
}

//we want to set max clip only if this weapon has more ammo in clips than max
if (resetmode.GetInt() == 2)
{
if (UsesClipsForAmmo1() && m_iClip1 > GetMaxClip1())
m_iClip1 = GetMaxClip1();

if (UsesClipsForAmmo2() && m_iClip2 > GetMaxClip2())
m_iClip2 = GetMaxClip2();

return;
}
}
#endif
}

//-----------------------------------------------------------------------------
Expand Down
58 changes: 57 additions & 1 deletion sp/src/game/client/hl2/hud_ammo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand All @@ -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
}

//-----------------------------------------------------------------------------
Expand All @@ -75,6 +81,9 @@ void CHudAmmo::Init( void )
{
m_iAmmo = -1;
m_iAmmo2 = -1;
#ifdef MAPBASE
m_iOldNeedsUpdate = -1; // Initialize
#endif

m_iconPrimaryAmmo = NULL;

Expand Down Expand Up @@ -107,6 +116,9 @@ void CHudAmmo::Reset()
m_hCurrentVehicle = NULL;
m_iAmmo = 0;
m_iAmmo2 = 0;
#ifdef MAPBASE
m_iOldNeedsUpdate = -1; // Initialize
#endif

UpdateAmmoDisplays();
}
Expand Down Expand Up @@ -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);
Expand All @@ -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 )
Expand Down Expand Up @@ -362,13 +383,20 @@ 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 );
}

void Init( void )
{
#ifndef HL2MP
#ifdef MAPBASE
m_iOldNeedsUpdate = -1;
#endif

wchar_t *tempString = g_pVGuiLocalize->Find("#Valve_Hud_AMMO_ALT");
if (tempString)
{
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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");
Expand All @@ -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 );
Expand Down
6 changes: 4 additions & 2 deletions sp/src/game/client/weapon_selection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() );
}


Expand Down
10 changes: 4 additions & 6 deletions sp/src/game/server/ai_basenpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8349,8 +8349,7 @@ void CAI_BaseNPC::InputUnholsterWeapon( inputdata_t &inputdata )
{
for (int i=0;i<MAX_WEAPONS;i++)
{
// These are both pooled, so if they're the same classname they should point to the same address
if ( m_hMyWeapons[i].Get() && m_hMyWeapons[i]->m_iClassname == inputdata.value.StringID() )
if ( m_hMyWeapons[i].Get() && FClassnameIs(m_hMyWeapons[i], inputdata.value.StringID().ToCStr()) )
{
//Weapon_Switch(m_hMyWeapons[i]);
//DoHolster();
Expand Down Expand Up @@ -8504,8 +8503,7 @@ void CAI_BaseNPC::InputChangeWeapon( inputdata_t &inputdata )
int iSwitchTo; // Index in m_hMyWeapons
for (int i=0;i<MAX_WEAPONS;i++)
{
// These are both pooled, so if they're the same classname they should point to the same address
if ( m_hMyWeapons[i].Get() && m_hMyWeapons[i]->m_iClassname == inputdata.value.StringID() )
if ( m_hMyWeapons[i].Get() && FClassnameIs(m_hMyWeapons[i], inputdata.value.StringID().ToCStr()) )
{
pSwitchTo = m_hMyWeapons[i];
iSwitchTo = i;
Expand Down Expand Up @@ -15976,7 +15974,7 @@ void CAI_BaseNPC::CalculateValidEnemyInteractions( void )
if (Q_strstr(myweapon, "WEPCLASS"))
pass = (GetActiveWeapon()->WeaponClassFromString(myweapon) == GetActiveWeapon()->WeaponClassify()) ? !pass : pass;
else
pass = (GetActiveWeapon()->m_iClassname == pInteraction->iszMyWeapon) ? !pass : pass;
pass = (FClassnameIs(GetActiveWeapon(), pInteraction->iszMyWeapon.ToCStr())) ? !pass : pass;

if (!pass)
continue;
Expand Down Expand Up @@ -16005,7 +16003,7 @@ void CAI_BaseNPC::CalculateValidEnemyInteractions( void )
if (Q_strstr(theirweapon, "WEPCLASS"))
pass = (pNPC->GetActiveWeapon()->WeaponClassFromString(theirweapon) == pNPC->GetActiveWeapon()->WeaponClassify()) ? !pass : pass;
else
pass = (pNPC->GetActiveWeapon()->m_iClassname == pInteraction->iszTheirWeapon) ? !pass : pass;
pass = (FClassnameIs(pNPC->GetActiveWeapon(), pInteraction->iszTheirWeapon.ToCStr())) ? !pass : pass;

if (!pass)
continue;
Expand Down
4 changes: 2 additions & 2 deletions sp/src/game/server/ai_basenpc_squad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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++;
}
Expand Down
11 changes: 8 additions & 3 deletions sp/src/game/server/basecombatweapon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,15 @@ CBaseEntity* CBaseCombatWeapon::Respawn( void )
{
// make a copy of this weapon that is invisible and inaccessible to players (no touch function). The weapon spawn/respawn code
// will decide when to make the weapon visible and touchable.
CBaseEntity *pNewWeapon = CBaseEntity::Create( GetClassname(), g_pGameRules->VecWeaponRespawnSpot( this ), GetLocalAngles(), GetOwnerEntity() );
CBaseEntity *pNewWeapon = CBaseEntity::Create( STRING(m_iClassname), 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 );
Expand All @@ -215,7 +220,7 @@ CBaseEntity* CBaseCombatWeapon::Respawn( void )
}
else
{
Warning("Respawn failed to create %s!\n", GetClassname() );
Warning("Respawn failed to create weapon \"%s\" with script \"%s\"!\n", STRING(m_iClassname), GetClassname());
}

return pNewWeapon;
Expand Down
9 changes: 5 additions & 4 deletions sp/src/game/server/baseentity.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down Expand Up @@ -820,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 );
Expand Down
9 changes: 7 additions & 2 deletions sp/src/game/server/entitylist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,12 @@ CBaseEntity *CGlobalEntityList::FindEntityByClassnameFast( CBaseEntity *pStartEn
continue;
}

if ( pEntity->m_iClassname == iszClassname)
if (!pEntity->IsBaseCombatWeapon() || static_cast<CBaseCombatWeapon*>(pEntity)->m_iszWeaponScript.Get()[0] == '\0')
{
if (pEntity->m_iClassname == iszClassname)
return pEntity;
}
else if (FClassnameIs(pEntity, iszClassname.ToCStr()))
{
return pEntity;
}
Expand Down Expand Up @@ -1370,7 +1375,7 @@ CBaseEntity *CGlobalEntityList::FindEntityClassNearestFacing( const Vector &orig
if (FClassnameIs(ent,classname))
{
// Ignore if worldspawn
if (!FClassnameIs( ent, "worldspawn" ) && !FClassnameIs( ent, "soundent"))
if (!FStrEq( STRING(ent->m_iClassname), "worldspawn") && !FStrEq( STRING(ent->m_iClassname), "soundent"))
{
bestDot = dot;
best_ent = ent;
Expand Down
8 changes: 4 additions & 4 deletions sp/src/game/server/gameweaponmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand All @@ -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 );
Expand All @@ -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() )
Expand Down Expand Up @@ -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 );
Expand Down
Loading