Skip to content

Commit b2a79bd

Browse files
committed
WIP
1 parent 000fa0d commit b2a79bd

15 files changed

+577
-396
lines changed

server/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ list(APPEND SVDLL_SOURCES
4848
"user_messages.cpp"
4949
"util.cpp"
5050
"weapons.cpp"
51+
"weapon_logic.cpp"
52+
"weapon_logic_funcs_impl.cpp"
5153
"world.cpp"
5254
)
5355

server/item_info.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#pragma once
2+
3+
#define ITEM_FLAG_SELECTONEMPTY 1
4+
#define ITEM_FLAG_NOAUTORELOAD 2
5+
#define ITEM_FLAG_NOAUTOSWITCHEMPTY 4
6+
#define ITEM_FLAG_LIMITINWORLD 8
7+
#define ITEM_FLAG_EXHAUSTIBLE 16 // A player can totally exhaust their ammo supply and lose this weapon
8+
9+
typedef struct
10+
{
11+
int iSlot;
12+
int iPosition;
13+
const char *pszAmmo1; // ammo 1 type
14+
int iMaxAmmo1; // max ammo 1
15+
const char *pszAmmo2; // ammo 2 type
16+
int iMaxAmmo2; // max ammo 2
17+
const char *pszName;
18+
int iMaxClip;
19+
int iId;
20+
int iFlags;
21+
int iWeight;// this value used to determine this weapon's importance in autoselection.
22+
} ItemInfo;

server/player.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4915,7 +4915,7 @@ void CBasePlayer::DropPlayerItem ( char *pszItemName )
49154915

49164916
UTIL_MakeVectors ( GetAbsAngles() );
49174917

4918-
RemoveWeapon( pWeapon->m_iId ); // take item off hud
4918+
RemoveWeapon( pWeapon->iWeaponID() ); // take item off hud
49194919

49204920
CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", GetAbsOrigin() + gpGlobals->v_forward * 10, GetAbsAngles(), edict() );
49214921
Vector vecAngles = pWeaponBox->GetAbsAngles();

server/stats.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ void UpdateStats( CBasePlayer *pPlayer )
109109

110110
int index = pPlayer->GetAmmoIndex(II.pszAmmo1);
111111
if ( index >= 0 )
112-
ammoCount[ index ] += ((CBasePlayerWeapon *)p)->m_iClip;
112+
ammoCount[ index ] += ((CBasePlayerWeapon *)p)->m_pWeaponLogic->m_iClip;
113113

114114
p = p->m_pNext;
115115
}

server/weapon_logic.cpp

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
#include "weapon_logic.h"
2+
#include "extdll.h"
3+
#include "util.h"
4+
#include "cbase.h"
5+
#include "player.h"
6+
#include "monsters.h"
7+
#include "weapons.h"
8+
#include "nodes.h"
9+
#include "soundent.h"
10+
#include "decals.h"
11+
#include "gamerules.h"
12+
13+
BOOL CanAttack( float attack_time, float curtime, BOOL isPredicted )
14+
{
15+
return ( attack_time <= curtime ) ? TRUE : FALSE;
16+
}
17+
18+
CBaseWeaponLogic::CBaseWeaponLogic(IWeaponLogicFuncs *funcs) :
19+
m_pFuncs(funcs),
20+
m_pPlayer(nullptr)
21+
{
22+
}
23+
24+
CBaseWeaponLogic::~CBaseWeaponLogic()
25+
{
26+
if (m_pFuncs) {
27+
delete m_pFuncs;
28+
}
29+
}
30+
31+
void CBaseWeaponLogic::ItemPostFrame()
32+
{
33+
if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= gpGlobals->time ))
34+
{
35+
// complete the reload.
36+
int j = Q_min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]);
37+
38+
// Add them to the clip
39+
m_iClip += j;
40+
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j;
41+
42+
m_fInReload = FALSE;
43+
}
44+
45+
if ((m_pPlayer->pev->button & IN_ATTACK2) && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, UseDecrement() ) )
46+
{
47+
if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] )
48+
{
49+
m_fFireOnEmpty = TRUE;
50+
}
51+
52+
SecondaryAttack();
53+
m_pPlayer->pev->button &= ~IN_ATTACK2;
54+
}
55+
else if ((m_pPlayer->pev->button & IN_ATTACK) && CanAttack( m_flNextPrimaryAttack, gpGlobals->time, UseDecrement() ) )
56+
{
57+
if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) )
58+
{
59+
m_fFireOnEmpty = TRUE;
60+
}
61+
62+
PrimaryAttack();
63+
}
64+
else if ( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload )
65+
{
66+
// reload when reload is pressed, or if no buttons are down and weapon is empty.
67+
Reload();
68+
}
69+
else if ( !(m_pPlayer->pev->button & (IN_ATTACK|IN_ATTACK2) ) )
70+
{
71+
// no fire buttons down
72+
73+
m_fFireOnEmpty = FALSE;
74+
75+
if ( !IsUseable() && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) )
76+
{
77+
// weapon isn't useable, switch.
78+
if ( !(iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && m_pFuncs->GetNextBestWeapon() )
79+
{
80+
m_flNextPrimaryAttack = ( UseDecrement() ? 0.0 : gpGlobals->time ) + 0.3;
81+
return;
82+
}
83+
}
84+
else
85+
{
86+
// weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
87+
if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) )
88+
{
89+
Reload();
90+
return;
91+
}
92+
}
93+
94+
WeaponIdle( );
95+
return;
96+
}
97+
98+
// catch all
99+
if ( ShouldWeaponIdle() )
100+
{
101+
WeaponIdle();
102+
}
103+
}
104+
105+
void CBaseWeaponLogic::Holster( void )
106+
{
107+
m_fInReload = FALSE; // cancel any reload in progress.
108+
m_pPlayer->pev->viewmodel = 0;
109+
m_pPlayer->pev->weaponmodel = 0;
110+
}
111+
112+
//=========================================================
113+
// IsUseable - this function determines whether or not a
114+
// weapon is useable by the player in its current state.
115+
// (does it have ammo loaded? do I have any ammo for the
116+
// weapon?, etc)
117+
//=========================================================
118+
BOOL CBaseWeaponLogic :: IsUseable( void )
119+
{
120+
if ( m_iClip <= 0 )
121+
{
122+
if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] <= 0 && iMaxAmmo1() != -1 )
123+
{
124+
// clip is empty (or nonexistant) and the player has no more ammo of this type.
125+
return FALSE;
126+
}
127+
}
128+
129+
return TRUE;
130+
}
131+
132+
BOOL CBaseWeaponLogic :: CanDeploy( void )
133+
{
134+
BOOL bHasAmmo = 0;
135+
136+
if ( !pszAmmo1() )
137+
{
138+
// this weapon doesn't use ammo, can always deploy.
139+
return TRUE;
140+
}
141+
142+
if ( pszAmmo1() )
143+
{
144+
bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0);
145+
}
146+
if ( pszAmmo2() )
147+
{
148+
bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0);
149+
}
150+
if (m_iClip > 0)
151+
{
152+
bHasAmmo |= 1;
153+
}
154+
if (!bHasAmmo)
155+
{
156+
return FALSE;
157+
}
158+
159+
return TRUE;
160+
}
161+
162+
BOOL CBaseWeaponLogic :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal /* = 0 */, int body )
163+
{
164+
if (!CanDeploy( ))
165+
return FALSE;
166+
167+
m_pPlayer->pev->viewmodel = MAKE_STRING(szViewModel);
168+
m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel);
169+
strcpy( m_pPlayer->m_szAnimExtention, szAnimExt );
170+
SendWeaponAnim( iAnim, skiplocal, body );
171+
172+
m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5;
173+
m_flTimeWeaponIdle = gpGlobals->time + 1.0;
174+
175+
return TRUE;
176+
}
177+
178+
BOOL CBaseWeaponLogic :: DefaultReload( int iClipSize, int iAnim, float fDelay, int body )
179+
{
180+
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
181+
return FALSE;
182+
183+
int j = Q_min(iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]);
184+
185+
if (j == 0)
186+
return FALSE;
187+
188+
m_pPlayer->m_flNextAttack = gpGlobals->time + fDelay;
189+
190+
//!!UNDONE -- reload sound goes here !!!
191+
SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0 );
192+
193+
m_fInReload = TRUE;
194+
195+
m_flTimeWeaponIdle = gpGlobals->time + 3;
196+
return TRUE;
197+
}
198+
199+
void CBaseWeaponLogic::SendWeaponAnim( int iAnim, int skiplocal, int body )
200+
{
201+
if ( UseDecrement() )
202+
skiplocal = 1;
203+
else
204+
skiplocal = 0;
205+
206+
m_pPlayer->pev->weaponanim = iAnim;
207+
208+
MESSAGE_BEGIN( MSG_ONE, SVC_WEAPONANIM, NULL, m_pPlayer->pev );
209+
WRITE_BYTE( iAnim ); // sequence number
210+
WRITE_BYTE( m_pFuncs->GetWeaponBodygroup() ); // weaponmodel bodygroup.
211+
MESSAGE_END();
212+
}
213+
214+
BOOL CBaseWeaponLogic :: PlayEmptySound( void )
215+
{
216+
if (m_iPlayEmptySound)
217+
{
218+
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM);
219+
m_iPlayEmptySound = 0;
220+
return 0;
221+
}
222+
return 0;
223+
}
224+
225+
void CBaseWeaponLogic :: ResetEmptySound( void )
226+
{
227+
m_iPlayEmptySound = 1;
228+
}
229+
230+
int CBaseWeaponLogic::PrimaryAmmoIndex( void )
231+
{
232+
return m_iPrimaryAmmoType;
233+
}
234+
235+
int CBaseWeaponLogic::SecondaryAmmoIndex( void )
236+
{
237+
return -1;
238+
}
239+
240+
int CBaseWeaponLogic::iItemSlot(void) { return 0; } // return 0 to MAX_ITEMS_SLOTS, used in hud
241+
int CBaseWeaponLogic::iItemPosition( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].iPosition; }
242+
const char *CBaseWeaponLogic::pszAmmo1( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].pszAmmo1; }
243+
int CBaseWeaponLogic::iMaxAmmo1( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].iMaxAmmo1; }
244+
const char *CBaseWeaponLogic::pszAmmo2( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].pszAmmo2; }
245+
int CBaseWeaponLogic::iMaxAmmo2( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].iMaxAmmo2; }
246+
const char *CBaseWeaponLogic::pszName( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].pszName; }
247+
int CBaseWeaponLogic::iMaxClip( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].iMaxClip; }
248+
int CBaseWeaponLogic::iWeight( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].iWeight; }
249+
int CBaseWeaponLogic::iFlags( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].iFlags; }

server/weapon_logic.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#pragma once
2+
#include "weapon_logic_funcs.h"
3+
#include "vector.h"
4+
#include "item_info.h"
5+
6+
class CBasePlayer;
7+
8+
class CBaseWeaponLogic
9+
{
10+
public:
11+
CBaseWeaponLogic(IWeaponLogicFuncs *funcs);
12+
virtual ~CBaseWeaponLogic();
13+
void ItemPostFrame();
14+
15+
// called by CBasePlayerWeapons ItemPostFrame()
16+
virtual void PrimaryAttack( void ) { return; } // do "+ATTACK"
17+
virtual void SecondaryAttack( void ) { return; } // do "+ATTACK2"
18+
virtual void Reload( void ) { return; } // do "+RELOAD"
19+
virtual void WeaponIdle( void ) { return; } // called when no buttons pressed
20+
21+
virtual BOOL ShouldWeaponIdle( void ) {return FALSE; };
22+
virtual BOOL CanDeploy( void );
23+
virtual BOOL Deploy( ) { return TRUE; }; // returns is deploy was successful
24+
virtual BOOL CanHolster( void ) { return TRUE; }; // can this weapon be put away right nxow?
25+
virtual void Holster(void);
26+
virtual BOOL IsUseable( void );
27+
virtual BOOL UseDecrement( void ) { return FALSE; };
28+
29+
virtual int GetItemInfo(ItemInfo *p) { return 0; }; // returns 0 if struct not filled out
30+
virtual int PrimaryAmmoIndex();
31+
virtual int SecondaryAmmoIndex();
32+
33+
virtual int iItemSlot(void);
34+
virtual int iItemPosition(void);
35+
virtual const char *pszAmmo1(void);
36+
virtual int iMaxAmmo1(void);
37+
virtual const char *pszAmmo2(void);
38+
virtual int iMaxAmmo2(void);
39+
virtual const char *pszName(void);
40+
virtual int iMaxClip(void);
41+
virtual int iWeight(void);
42+
virtual int iFlags(void);
43+
44+
BOOL DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal = 0, int body = 0 );
45+
int DefaultReload( int iClipSize, int iAnim, float fDelay, int body = 0 );
46+
void SendWeaponAnim( int iAnim, int skiplocal = 1, int body = 0 ); // skiplocal is 1 if client is predicting weapon animations
47+
BOOL PlayEmptySound( void );
48+
void ResetEmptySound( void );
49+
50+
int m_iId; // WEAPON_???
51+
int m_iPlayEmptySound;
52+
int m_fFireOnEmpty; // True when the gun is empty and the player is still holding down the attack key(s)
53+
float m_flPumpTime;
54+
int m_fInSpecialReload; // Are we in the middle of a reload for the shotguns
55+
float m_flNextPrimaryAttack; // soonest time ItemPostFrame will call PrimaryAttack
56+
float m_flNextSecondaryAttack; // soonest time ItemPostFrame will call SecondaryAttack
57+
float m_flTimeWeaponIdle; // soonest time ItemPostFrame will call WeaponIdle
58+
int m_iPrimaryAmmoType; // "primary" ammo index into players m_rgAmmo[]
59+
int m_iSecondaryAmmoType; // "secondary" ammo index into players m_rgAmmo[]
60+
int m_iClip; // number of shots left in the primary weapon clip, -1 it not used
61+
int m_iClientClip; // the last version of m_iClip sent to hud dll
62+
int m_iClientWeaponState; // the last version of the weapon state sent to hud dll (is current weapon, is on target)
63+
int m_fInReload; // Are we in the middle of a reload;
64+
int m_iDefaultAmmo;// how much ammo you get when you pick up this weapon as placed by a level designer.
65+
CBasePlayer *m_pPlayer;
66+
IWeaponLogicFuncs *m_pFuncs;
67+
};
68+

server/weapon_logic_funcs.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#pragma once
2+
3+
class IWeaponLogicFuncs
4+
{
5+
public:
6+
virtual ~IWeaponLogicFuncs() {};
7+
virtual const char *GetWeaponClassname() = 0;
8+
virtual int GetWeaponBodygroup() = 0;
9+
virtual bool GetNextBestWeapon() = 0;
10+
};

0 commit comments

Comments
 (0)