forked from borzh/botrix
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathweapon.h
More file actions
382 lines (290 loc) · 16.2 KB
/
weapon.h
File metadata and controls
382 lines (290 loc) · 16.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
#ifndef __BOTRIX_WEAPON_H__
#define __BOTRIX_WEAPON_H__
#include "item.h"
#include "mod.h"
#include "source_engine.h"
#include "server_plugin.h"
#include <good/bitset.h>
#include <good/memory.h>
#include "vector.h"
//****************************************************************************************************************
/// Weapon abstract class. Used to get needed angles to aim.
//****************************************************************************************************************
class CWeapon
{
public:
/// Default constructor.
CWeapon()
{
memset(this, 0, sizeof(CWeapon));
iAttackBullets[0] = iAttackBullets[1] = 1;
fMaxDistanceSqr[0] = fMaxDistanceSqr[1] = CUtil::iMaxMapSizeSqr;
iBotPreference = EBotNormal;
}
static bool IsValid( TWeaponId iId ) { return iId != EWeaponIdInvalid; }
static const int PRIMARY = 0; ///< Index for primary ammo.
static const int SECONDARY = 1; ///< Index for secondary ammo.
TWeaponId iId; ///< Weapon id.
const CItemClass* pWeaponClass; ///< Pointer to weapon class.
TClass iClass; ///< Classes that can uses this weapon. Those are really flags.
TTeam iTeam; ///< Only this team can buy this weapon. Those are really flags.
TWeaponType iType; ///< Weapon type.
TWeaponAim iAim[2]; ///< Where to aim with this weapon.
TWeaponFlags iFlags[2]; ///< Attack flags.
float fMinDistanceSqr[2]; ///< Minimum distance to enemy to safely use this weapon (0 by default).
float fMaxDistanceSqr[2]; ///< Maximum distance to enemy to be able to use this weapon (0 by default).
float fHolsterTime; ///< Time from change weapon to be able to shoot.
float fHoldTime[2]; ///< Time to hold down attack button. Useful for grenades.
float fShotTime[2]; ///< Duration of shoot (primary and secondary).
float fReloadStartTime[2]; ///< Time to start reload (primary and secondary).
float fReloadTime[2]; ///< Duration of reload (primary and secondary).
float fDamage[2]; ///< How much damage one bullet does.
unsigned char iClipSize[2]; ///< How much bullets fit in one clip.
unsigned char iDefaultAmmo[2]; ///< Count of bullets this weapon gives by default.
unsigned char iMaxAmmo[2]; ///< Count of max bullets this weapon can have (besides the clip in the weapon).
unsigned char iAttackBullets[2]; ///< How many bullets are used in attack.
unsigned char iReloadBy[2]; ///< Bullets are used in one reload time.
int iParabolicDistance0[2]; ///< Distance that bullet does in straight line until falls.
int iParabolicDistance45[2]; ///< Distance that bullet does looking up 45grades until falls.
TBotIntelligence iBotPreference; ///< Smart bots will prefer weapons with higher preference.
bool bForbidden; ///< True if weapon is forbidden.
good::vector<const CItemClass*> aAmmos[2]; ///< Ammo item classes.
good::vector<int> aAmmosCount[2]; ///< Ammos count for ammo at same index.
};
//****************************************************************************************************************
/// Weapon with ammunition.
//****************************************************************************************************************
class CWeaponWithAmmo
{
public:
/// Constructor.
CWeaponWithAmmo( const CWeapon* pWeapon )
{
memset(this, 0, sizeof(CWeaponWithAmmo));
m_pWeapon = pWeapon;
}
/// Game frame.
void GameFrame( int& iButtons );
/// Return base weapon.
inline const CWeapon* GetBaseWeapon() const { return m_pWeapon; }
/// Return weapon's entity name.
inline const good::string& GetName() const { return m_pWeapon->pWeaponClass->sClassName; }
/// Return false if there is only ammo for this weapon, but without weapon itself.
inline bool IsPresent() const { return m_bWeaponPresent; }
/// Return true if this weapon is melee.
inline bool IsMelee() const { return (m_pWeapon->iType == EWeaponMelee); }
/// Return true if this weapon is ranged (not grenade).
inline bool IsRanged() const { return (m_pWeapon->iType > EWeaponGrenade); }
/// Return true if need to throw.
inline bool IsGrenade() const { return (m_pWeapon->iType == EWeaponGrenade); }
/// Return true if weapon is sniper.
inline bool IsSniper() const { return FLAG_SOME_SET(FWeaponZoom, m_pWeapon->iFlags[1]) != 0; }
/// Return true if weapon is medic.
inline bool IsMedic() const { return FLAG_SOME_SET(FWeaponCure, m_pWeapon->iFlags[0]) != 0; }
/// Return true if weapon is physics.
inline bool IsPhysics() const { return (m_pWeapon->iType == EWeaponPhysics); }
/// Return true if currently reloading.
inline bool IsReloading() const { return m_bReloading || m_bReloadingStart; }
/// Return true if currently shooting.
inline bool IsShooting() const { return m_bShooting || m_bHolding; }
/// Return true if currently changing to this weapon.
inline bool IsChanging() const { return m_bChanging; }
/// Return true if currently using zoom.
inline bool IsUsingZoom() const { return m_bUsingZoom; }
// Return true if can use this weapon for given distance to enemy (it is safe).
bool IsDistanceSafe( float fDistanceSqr, int iSecondary ) const
{
return (m_pWeapon->fMinDistanceSqr[iSecondary] <= fDistanceSqr) &&
(fDistanceSqr <= m_pWeapon->fMaxDistanceSqr[iSecondary]);
}
/// Return true if weapon has secondary function with different ammo than primary.
inline bool HasSecondary() const
{
return FLAG_CLEARED( FWeaponSameBullets, m_pWeapon->iFlags[1] );
}
/// Return true if weapon has ammo.
inline bool HasAmmoInClip( int iSecondary ) const { return m_iBulletsInClip[iSecondary] > 0; }
/// Return true if weapon has ammo, beside the ammo in clip.
inline bool HasAmmoExtra( int iSecondary ) const { return m_iBulletsExtra[iSecondary] > 0; }
/// Return true if weapon has full ammunition.
inline bool HasFullAmmo( int iSecondary ) const { return m_iBulletsExtra[iSecondary] == m_pWeapon->iMaxAmmo[iSecondary]; }
/// Return true if weapon has ammo.
inline bool HasAmmo( int iSecondary ) const { return HasAmmoInClip(iSecondary) || HasAmmoExtra(iSecondary); }
/// Return true if weapon has ammo.
inline bool HasAmmo() const { return HasAmmo(0) || HasAmmo(1); }
/// Return true if this weapon has no bullets.
inline bool Empty() const { return !IsMelee() && !IsPhysics() && !HasAmmo(); }
/// Return time when weapon can be used.
inline float GetEndTime() const { return m_fEndTime; }
/// Return true if weapon can be changed.
inline bool CanChange() const { return !IsShooting(); }
/// Return true if weapon is not reloading or shooting or changing zoom or changing to other weapon.
inline bool CanUse() const
{
// Shotgun and rocket types can stop reloading and shoot if weapon has bullets in clip.
return !IsShooting() && !IsChanging() && ( !IsReloading() || ( (m_pWeapon->iType >= EWeaponShotgun) && Bullets(0) ) );
}
/// Return true if weapon can be used from distance to enemy.
inline bool CanBeUsed( float fDistanceSqrToEnemy ) const
{
return ( HasAmmoInClip(CWeapon::PRIMARY) && IsDistanceSafe(fDistanceSqrToEnemy, CWeapon::PRIMARY) ) ||
( HasAmmoInClip(CWeapon::SECONDARY) && IsDistanceSafe(fDistanceSqrToEnemy, CWeapon::SECONDARY) );
}
//
inline bool NeedsToBeCloser( float fDistanceSqrToEnemy ) const
{
return ( HasAmmoInClip(CWeapon::PRIMARY) && (m_pWeapon->fMaxDistanceSqr[CWeapon::PRIMARY] < fDistanceSqrToEnemy) ) ||
( HasAmmoInClip(CWeapon::SECONDARY) && (m_pWeapon->fMaxDistanceSqr[CWeapon::SECONDARY] < fDistanceSqrToEnemy) );
}
/// Return true if can start shooting at enemy right away.
inline bool CanShoot( int iSecondary, float fDistanceSqr ) const
{
GoodAssert( CanUse() );
return HasAmmoInClip(iSecondary) && IsDistanceSafe(fDistanceSqr, iSecondary);
}
/// Set weapon presence.
inline void SetPresent( bool bPresent ) { m_bWeaponPresent = bPresent; }
/// Remove all bullets for this weapon.
inline void SetEmpty() { m_iBulletsInClip[0] = m_iBulletsInClip[1] = 0; m_iBulletsExtra[0] = m_iBulletsExtra[1] = 0; }
/// Return damage per second this weapon can do with primary ammo.
inline float DamagePerSecond() const { return m_pWeapon->fDamage[0] / m_pWeapon->fShotTime[0]; }
/// Return amount of bullets this weapon has for primary or secondary attacks.
inline int Bullets( int iSecondary ) const { return m_iBulletsInClip[iSecondary]; }
/// Return amount of extra bullets this weapon has for primary or secondary attacks.
inline int ExtraBullets( int iSecondary ) const { return m_iBulletsExtra[iSecondary]; }
/// Return approximate damage this weapon can do with bullets in clip.
inline float Damage( int iSecondary ) const { return m_pWeapon->fDamage[iSecondary]; }
/// Return approximate damage this weapon can do with bullets in clip.
inline float TotalDamage( int iSecondary ) const { return Bullets(iSecondary) * Damage(iSecondary); }
/// Return approximate damage this weapon can do without reload.
inline float TotalDamage() const { return TotalDamage(0) + TotalDamage(1); }
/// Return true if weapon needs to be reloaded.
bool NeedReload( int iSecondary ) const { return (m_iBulletsInClip[iSecondary] < m_pWeapon->iClipSize[iSecondary]) && HasAmmoExtra(iSecondary); }
/// Return true if weapon should be reloaded.
bool ShouldReload( int iSecondary ) const { return (m_iBulletsInClip[iSecondary] == 0) && HasAmmoExtra(iSecondary); }
/// Return true if need to use zoom.
bool ShouldZoom( float fDistanceToEnemySqr ) const
{
BASSERT( IsSniper(), return false );
return (fDistanceToEnemySqr >= m_pWeapon->fMinDistanceSqr[1]);
}
/// Start to shoot weapon.
void Shoot( int iSecondary );
/// Start to reload weapon.
void Reload( int iSecondary );
/// Remove this weapon (called when player's team is different from this weapons's team).
void RemoveWeapon() { m_bWeaponPresent = false; }
/// Called when bot picks up this weapon.
void AddWeapon();
/// Add bullets to this weapon.
void AddBullets( int iCount, int iSecondary )
{
m_iBulletsExtra[iSecondary] += iCount;
if ( m_iBulletsExtra[iSecondary] > m_pWeapon->iMaxAmmo[iSecondary] )
m_iBulletsExtra[iSecondary] = m_pWeapon->iMaxAmmo[iSecondary];
}
/// Change weapon.
static void Holster( CWeaponWithAmmo* pSwitchFrom, CWeaponWithAmmo& cSwitchTo );
/// Zoom in.
void ToggleZoom()
{
GoodAssert( CanUse() && IsSniper() );
Shoot(CWeapon::SECONDARY);
m_bUsingZoom = !m_bUsingZoom;
}
/// Get where to look at enemy according to aim.
void GetLook( const Vector& vFrom, const CPlayer* pTo, TBotIntelligence iIntelligence, int iSecondary, Vector& vResult ) const;
/**
* @brief Get vector to aim to.
*
* iBotIntelligence is used to get some errors in aim. Returns false if can't use
* (invalid distance). Will return vector, with random based error and bot intelligence.
*/
bool GetLook( const Vector& vFrom, const CPlayer* pTo, float fDistanceSqr,
TBotIntelligence iBotIntelligence, int iSecondary, Vector& vResult ) const;
protected:
// End reloading weapon.
void EndReload();
// End holding attack button.
void EndHold();
// End using weapon function.
void EndShoot();
const CWeapon* m_pWeapon; ///< Weapon itself.
int m_iBulletsInClip[2]; ///< Bullets in current clip (inside weapon).
int m_iBulletsExtra[2]; ///< Amount of bullets extra.
int m_iSecondary; ///< Reloading / shooting secondary ammo or using zoom.
float m_fEndTime; ///< Time to end reloading/shooting.
bool m_bWeaponPresent:1; ///< True, if weapon is present, false if only ammo is present.
bool m_bReloadingStart:1; ///< True, if started to reload weapon.
bool m_bReloading:1; ///< True, if continuing to reload weapon.
bool m_bHolding:1; ///< True, if currently holding attack button.
bool m_bShooting:1; ///< True, if currently shooting.
bool m_bChanging:1; ///< True, if started to change weapon.
bool m_bUsingZoom:1; ///< True, if started to zoom in / zoom out.
};
typedef good::unique_ptr<CWeaponWithAmmo> CWeaponWithAmmoPtr; ///< Unique pointer for weapon with ammo.
//****************************************************************************************************************
/// Available weapons.
//****************************************************************************************************************
class CWeapons
{
public:
/// Return weapons count.
static int Size() { return m_aWeapons.size(); }
/// Get weapon from weapon id.
static const CWeaponWithAmmo& Get( TWeaponId iWeaponId ) { return m_aWeapons[iWeaponId]; }
/// Add weapon.
static TWeaponId Add( CWeaponWithAmmo& cWeapon ) { m_aWeapons.push_back(cWeapon); return m_aWeapons.size()-1; }
/// Clear all weapons.
static void Clear()
{
m_aWeapons.reserve(16);
for ( int i=0; i < m_aWeapons.size(); ++i )
delete m_aWeapons[i].GetBaseWeapon();
m_aWeapons.clear();
}
/// Get default weapons with which player respawns.
static void GetRespawnWeapons( good::vector<CWeaponWithAmmo>& aWeapons, TTeam iTeam, TClass iClass );
/// Get weapon from weapon name.
static TWeaponId GetIdFromWeaponName( const good::string& sName )
{
for ( int i=0; i < m_aWeapons.size(); ++i )
if ( m_aWeapons[i].GetName() == sName )
return i;
return EWeaponIdInvalid;
}
/// Get weapon from weapon class. Faster.
static TWeaponId GetIdFromWeaponClass( const CItemClass* pWeaponClass )
{
for ( int i=0; i < m_aWeapons.size(); ++i )
if ( m_aWeapons[i].GetBaseWeapon()->pWeaponClass == pWeaponClass )
return i;
return EWeaponIdInvalid;
}
/// Add weapon to weapons.
static TWeaponId AddWeapon( const CItemClass* pWeaponClass, good::vector<CWeaponWithAmmo>& aWeapons )
{
for ( TWeaponId iWeapon = 0; iWeapon < aWeapons.size(); ++iWeapon )
{
if ( aWeapons[iWeapon].GetBaseWeapon()->pWeaponClass == pWeaponClass )
{
aWeapons[iWeapon].AddWeapon();
return iWeapon;
}
}
return EWeaponIdInvalid;
}
/// Add ammo to weapons.
static bool AddAmmo( const CItemClass* pAmmoClass, good::vector<CWeaponWithAmmo>& aWeapons );
/// Allow given weapon.
static void Allow( TWeaponId iWeaponId ) { ((CWeapon*)m_aWeapons[iWeaponId].GetBaseWeapon())->bForbidden = false; }
/// Forbid given weapon.
static void Forbid( TWeaponId iWeaponId ) { ((CWeapon*)m_aWeapons[iWeaponId].GetBaseWeapon())->bForbidden = true; }
/// Get best ranged weapon.
static TWeaponId GetBestWeapon( const good::vector<CWeaponWithAmmo>& aWeapons );
/// Get random weapon, based on bot intelligence.
static TWeaponId GetRandomWeapon( TBotIntelligence iIntelligence, const good::bitset& cSkipWeapons );
protected:
static good::vector< CWeaponWithAmmo > m_aWeapons; // Array of available weapons for this mod.
};
#endif // __BOTRIX_WEAPONS_H__