Skip to content

Commit be753c1

Browse files
committed
WIP
1 parent b0b0b15 commit be753c1

19 files changed

+841
-475
lines changed

client/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ list(APPEND CLDLL_SOURCES
5757
"${CMAKE_SOURCE_DIR}/game_shared/stringlib.cpp"
5858
"${CMAKE_SOURCE_DIR}/game_shared/virtualfs.cpp"
5959
"${CMAKE_SOURCE_DIR}/game_shared/trace.cpp"
60+
"${CMAKE_SOURCE_DIR}/game_shared/weapon_context.cpp"
6061
"${CMAKE_SOURCE_DIR}/game_shared/filesystem_utils.cpp"
6162
"${CMAKE_SOURCE_DIR}/game_shared/filesystem_manager.cpp"
6263
"${CMAKE_SOURCE_DIR}/public/crclib.cpp"
@@ -68,6 +69,9 @@ file(GLOB RENDER_SOURCES "render/*.cpp")
6869
# entity wrappers source files
6970
file(GLOB ENTITIES_SOURCES "entities/*.cpp")
7071

72+
# weapon shared code source files
73+
file(GLOB WEAPONS_SHARED_SOURCES "${CMAKE_SOURCE_DIR}/game_shared/weapons/*.cpp")
74+
7175
# ImGui source files
7276
if(NOT ENABLE_VGUI_COMPATIBILITY)
7377
list(APPEND IMGUI_SOURCES
@@ -84,6 +88,7 @@ endif()
8488

8589
list(APPEND CLDLL_SOURCES ${RENDER_SOURCES})
8690
list(APPEND CLDLL_SOURCES ${ENTITIES_SOURCES})
91+
list(APPEND CLDLL_SOURCES ${WEAPONS_SHARED_SOURCES})
8792
add_library(${PROJECT_NAME} SHARED ${CLDLL_SOURCES})
8893

8994
target_include_directories(${PROJECT_NAME} PRIVATE

game_shared/item_info.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#pragma once
2+
#include "cdll_dll.h"
3+
4+
#define ITEM_FLAG_SELECTONEMPTY 1
5+
#define ITEM_FLAG_NOAUTORELOAD 2
6+
#define ITEM_FLAG_NOAUTOSWITCHEMPTY 4
7+
#define ITEM_FLAG_LIMITINWORLD 8
8+
#define ITEM_FLAG_EXHAUSTIBLE 16 // A player can totally exhaust their ammo supply and lose this weapon
9+
10+
#define WEAPON_NOCLIP -1
11+
#define WEAPON_ALLWEAPONS (~(1<<WEAPON_SUIT))
12+
13+
// weapon clip/carry ammo capacities
14+
#define URANIUM_MAX_CARRY 100
15+
#define _9MM_MAX_CARRY 250
16+
#define _357_MAX_CARRY 36
17+
#define BUCKSHOT_MAX_CARRY 125
18+
#define BOLT_MAX_CARRY 50
19+
#define ROCKET_MAX_CARRY 5
20+
#define HANDGRENADE_MAX_CARRY 10
21+
#define SATCHEL_MAX_CARRY 5
22+
#define TRIPMINE_MAX_CARRY 5
23+
#define SNARK_MAX_CARRY 15
24+
#define HORNET_MAX_CARRY 8
25+
#define M203_GRENADE_MAX_CARRY 10
26+
27+
typedef struct
28+
{
29+
int iSlot;
30+
int iPosition;
31+
const char *pszAmmo1; // ammo 1 type
32+
int iMaxAmmo1; // max ammo 1
33+
const char *pszAmmo2; // ammo 2 type
34+
int iMaxAmmo2; // max ammo 2
35+
const char *pszName;
36+
int iMaxClip;
37+
int iId;
38+
int iFlags;
39+
int iWeight;// this value used to determine this weapon's importance in autoselection.
40+
} ItemInfo;
41+
42+
typedef struct
43+
{
44+
const char *pszName;
45+
int iId;
46+
} AmmoInfo;

game_shared/weapon_context.cpp

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
/*
2+
weapon_context.cpp - part of weapons implementation common for client & server
3+
Copyright (C) 2024 SNMetamorph
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
*/
15+
16+
#include "weapon_context.h"
17+
#ifdef CLIENT_DLL
18+
#include "const.h"
19+
#else
20+
#include "extdll.h"
21+
#include "util.h"
22+
#include "cbase.h"
23+
#include "player.h"
24+
#include "monsters.h"
25+
#include "weapons.h"
26+
#include "nodes.h"
27+
#include "soundent.h"
28+
#include "decals.h"
29+
#include "gamerules.h"
30+
#endif
31+
32+
ItemInfo CBaseWeaponContext::ItemInfoArray[ MAX_WEAPONS ];
33+
AmmoInfo CBaseWeaponContext::AmmoInfoArray[ MAX_AMMO_SLOTS ];
34+
35+
CBaseWeaponContext::CBaseWeaponContext(IWeaponLayer *funcs) :
36+
m_pFuncs(funcs),
37+
m_pWeaponEntity(nullptr)
38+
{
39+
}
40+
41+
CBaseWeaponContext::~CBaseWeaponContext()
42+
{
43+
if (m_pFuncs) {
44+
delete m_pFuncs;
45+
}
46+
}
47+
48+
void CBaseWeaponContext::ItemPostFrame()
49+
{
50+
if ((m_fInReload) && m_pFuncs->GetPlayerNextAttackTime() <= m_pFuncs->GetWeaponTimeBase())
51+
{
52+
// complete the reload.
53+
int j = Q_min( iMaxClip() - m_iClip, m_pFuncs->GetPlayerAmmo(m_iPrimaryAmmoType) );
54+
55+
// Add them to the clip
56+
m_iClip += j;
57+
m_pFuncs->SetPlayerAmmo( m_iPrimaryAmmoType, m_pFuncs->GetPlayerAmmo(m_iPrimaryAmmoType) - j );
58+
59+
m_fInReload = FALSE;
60+
}
61+
62+
if (m_pFuncs->CheckPlayerButtonFlag(IN_ATTACK2) && m_flNextSecondaryAttack <= m_pFuncs->GetWeaponTimeBase() )
63+
{
64+
if ( pszAmmo2() && !m_pFuncs->GetPlayerAmmo(SecondaryAmmoIndex()) )
65+
{
66+
m_fFireOnEmpty = TRUE;
67+
}
68+
69+
SecondaryAttack();
70+
m_pFuncs->ClearPlayerButtonFlag(IN_ATTACK2);
71+
}
72+
else if (m_pFuncs->CheckPlayerButtonFlag(IN_ATTACK) && m_flNextPrimaryAttack <= m_pFuncs->GetWeaponTimeBase() )
73+
{
74+
if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pFuncs->GetPlayerAmmo(PrimaryAmmoIndex())) )
75+
{
76+
m_fFireOnEmpty = TRUE;
77+
}
78+
79+
PrimaryAttack();
80+
}
81+
else if ( m_pFuncs->CheckPlayerButtonFlag(IN_RELOAD) && iMaxClip() != WEAPON_NOCLIP && !m_fInReload )
82+
{
83+
// reload when reload is pressed, or if no buttons are down and weapon is empty.
84+
Reload();
85+
}
86+
else if ( !(m_pFuncs->CheckPlayerButtonFlag(IN_ATTACK|IN_ATTACK2) ) )
87+
{
88+
// no fire buttons down
89+
90+
m_fFireOnEmpty = FALSE;
91+
#ifndef CLIENT_DLL // we don't need this branch on client side, because client is not responsible for changing weapons
92+
if ( !IsUseable() && m_flNextPrimaryAttack < m_pFuncs->GetWeaponTimeBase() )
93+
{
94+
// weapon isn't useable, switch. GetNextBestWeapon exactly does weapon switching
95+
if ( !(iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && m_pFuncs->GetNextBestWeapon() )
96+
{
97+
m_flNextPrimaryAttack = m_pFuncs->GetWeaponTimeBase() + 0.3;
98+
return;
99+
}
100+
}
101+
else
102+
#endif
103+
{
104+
// weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
105+
if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < m_pFuncs->GetWeaponTimeBase() )
106+
{
107+
Reload();
108+
return;
109+
}
110+
}
111+
112+
WeaponIdle( );
113+
return;
114+
}
115+
116+
// catch all
117+
if ( ShouldWeaponIdle() )
118+
{
119+
WeaponIdle();
120+
}
121+
}
122+
123+
void CBaseWeaponContext::Holster()
124+
{
125+
m_fInReload = FALSE; // cancel any reload in progress.
126+
m_pFuncs->SetPlayerViewmodel(0);
127+
#ifndef CLIENT_DLL
128+
m_pWeaponEntity->m_pPlayer->pev->weaponmodel = 0;
129+
#endif
130+
}
131+
132+
//=========================================================
133+
// IsUseable - this function determines whether or not a
134+
// weapon is useable by the player in its current state.
135+
// (does it have ammo loaded? do I have any ammo for the
136+
// weapon?, etc)
137+
//=========================================================
138+
bool CBaseWeaponContext :: IsUseable()
139+
{
140+
if ( m_iClip <= 0 )
141+
{
142+
if ( m_pFuncs->GetPlayerAmmo( PrimaryAmmoIndex() ) <= 0 && iMaxAmmo1() != -1 )
143+
{
144+
// clip is empty (or nonexistant) and the player has no more ammo of this type.
145+
return FALSE;
146+
}
147+
}
148+
149+
return TRUE;
150+
}
151+
152+
bool CBaseWeaponContext :: CanDeploy()
153+
{
154+
BOOL bHasAmmo = 0;
155+
156+
if ( !pszAmmo1() )
157+
{
158+
// this weapon doesn't use ammo, can always deploy.
159+
return TRUE;
160+
}
161+
162+
if ( pszAmmo1() )
163+
{
164+
bHasAmmo |= (m_pFuncs->GetPlayerAmmo(m_iPrimaryAmmoType) != 0);
165+
}
166+
if ( pszAmmo2() )
167+
{
168+
bHasAmmo |= (m_pFuncs->GetPlayerAmmo(m_iSecondaryAmmoType) != 0);
169+
}
170+
if (m_iClip > 0)
171+
{
172+
bHasAmmo |= 1;
173+
}
174+
if (!bHasAmmo)
175+
{
176+
return FALSE;
177+
}
178+
179+
return TRUE;
180+
}
181+
182+
bool CBaseWeaponContext :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal /* = 0 */, int body )
183+
{
184+
if (!CanDeploy( ))
185+
return FALSE;
186+
187+
#ifndef CLIENT_DLL
188+
//m_pWeaponEntity->m_pPlayer->TabulateAmmo();
189+
m_pWeaponEntity->m_pPlayer->pev->viewmodel = MAKE_STRING(szViewModel);
190+
m_pWeaponEntity->m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel);
191+
strcpy( m_pWeaponEntity->m_pPlayer->m_szAnimExtention, szAnimExt );
192+
#else
193+
// gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel );
194+
#endif
195+
SendWeaponAnim( iAnim, skiplocal, body );
196+
197+
m_pFuncs->SetPlayerNextAttackTime(m_pFuncs->GetWeaponTimeBase() + 0.5);
198+
m_flTimeWeaponIdle = m_pFuncs->GetWeaponTimeBase() + 1.0;
199+
return TRUE;
200+
}
201+
202+
BOOL CBaseWeaponContext :: DefaultReload( int iClipSize, int iAnim, float fDelay, int body )
203+
{
204+
if (m_pFuncs->GetPlayerAmmo(m_iPrimaryAmmoType) <= 0)
205+
return FALSE;
206+
207+
int j = Q_min(iClipSize - m_iClip, m_pFuncs->GetPlayerAmmo(m_iPrimaryAmmoType));
208+
209+
if (j == 0)
210+
return FALSE;
211+
212+
m_pFuncs->SetPlayerNextAttackTime(m_pFuncs->GetWeaponTimeBase() + fDelay);
213+
214+
//!!UNDONE -- reload sound goes here !!!
215+
SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0, body );
216+
217+
m_fInReload = TRUE;
218+
219+
m_flTimeWeaponIdle = m_pFuncs->GetWeaponTimeBase() + 3;
220+
return TRUE;
221+
}
222+
223+
void CBaseWeaponContext::SendWeaponAnim( int iAnim, int skiplocal, int body )
224+
{
225+
m_pFuncs->SetPlayerWeaponAnim(iAnim);
226+
227+
#ifndef CLIENT_DLL
228+
if ( UseDecrement() )
229+
skiplocal = 1;
230+
else
231+
skiplocal = 0;
232+
233+
if ( skiplocal && ENGINE_CANSKIP( m_pWeaponEntity->m_pPlayer->edict() ) )
234+
return;
235+
236+
MESSAGE_BEGIN( MSG_ONE, SVC_WEAPONANIM, NULL, m_pWeaponEntity->m_pPlayer->pev );
237+
WRITE_BYTE( iAnim ); // sequence number
238+
WRITE_BYTE( m_pFuncs->GetWeaponBodygroup() ); // weaponmodel bodygroup.
239+
MESSAGE_END();
240+
#else
241+
// HUD_SendWeaponAnim( iAnim, body, 0 );
242+
#endif
243+
}
244+
245+
bool CBaseWeaponContext :: PlayEmptySound()
246+
{
247+
if (m_iPlayEmptySound)
248+
{
249+
#ifdef CLIENT_DLL
250+
// HUD_PlaySound( "weapons/357_cock1.wav", 0.8 );
251+
#else
252+
EMIT_SOUND(ENT(m_pWeaponEntity->m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM);
253+
#endif
254+
m_iPlayEmptySound = 0;
255+
return 0;
256+
}
257+
return 0;
258+
}
259+
260+
void CBaseWeaponContext :: ResetEmptySound()
261+
{
262+
m_iPlayEmptySound = 1;
263+
}
264+
265+
int CBaseWeaponContext::PrimaryAmmoIndex()
266+
{
267+
return m_iPrimaryAmmoType;
268+
}
269+
270+
int CBaseWeaponContext::SecondaryAmmoIndex()
271+
{
272+
return -1;
273+
}
274+
275+
int CBaseWeaponContext::iItemSlot() { return 0; } // return 0 to MAX_ITEMS_SLOTS, used in hud
276+
int CBaseWeaponContext::iItemPosition() { return CBaseWeaponContext::ItemInfoArray[ m_iId ].iPosition; }
277+
const char *CBaseWeaponContext::pszAmmo1() { return CBaseWeaponContext::ItemInfoArray[ m_iId ].pszAmmo1; }
278+
int CBaseWeaponContext::iMaxAmmo1() { return CBaseWeaponContext::ItemInfoArray[ m_iId ].iMaxAmmo1; }
279+
const char *CBaseWeaponContext::pszAmmo2() { return CBaseWeaponContext::ItemInfoArray[ m_iId ].pszAmmo2; }
280+
int CBaseWeaponContext::iMaxAmmo2() { return CBaseWeaponContext::ItemInfoArray[ m_iId ].iMaxAmmo2; }
281+
const char *CBaseWeaponContext::pszName() { return CBaseWeaponContext::ItemInfoArray[ m_iId ].pszName; }
282+
int CBaseWeaponContext::iMaxClip() { return CBaseWeaponContext::ItemInfoArray[ m_iId ].iMaxClip; }
283+
int CBaseWeaponContext::iWeight() { return CBaseWeaponContext::ItemInfoArray[ m_iId ].iWeight; }
284+
int CBaseWeaponContext::iFlags() { return CBaseWeaponContext::ItemInfoArray[ m_iId ].iFlags; }

0 commit comments

Comments
 (0)