Adding a new weapon to your mod: Difference between revisions
mNo edit summary |
No edit summary |
||
Line 23: | Line 23: | ||
#include "npcevent.h" | #include "npcevent.h" | ||
#include "in_buttons.h" | #include "in_buttons.h" | ||
#ifdef CLIENT_DLL | #ifdef CLIENT_DLL | ||
#include "c_hl2mp_player.h" | #include "c_hl2mp_player.h" | ||
#else | #else | ||
#include "hl2mp_player.h" | #include "hl2mp_player.h" | ||
#endif | #endif | ||
Line 33: | Line 33: | ||
//modify this to alter the rate of fire | //modify this to alter the rate of fire | ||
#define ROF 0.075f //800 | #define ROF 0.075f //RPS, 60 Sec / 800 Rounds = 0.075f | ||
// | |||
//The gun will fire up to this number of bullets while you hold the fire button. | |||
//If you set it to 1 the gun will be semi auto. If you set it to 3 the gun will fire three round bursts | |||
#define BURST 500; | #define BURST 500; | ||
Line 47: | Line 49: | ||
class CWeaponAK47 : public CBaseHL2MPCombatWeapon | class CWeaponAK47 : public CBaseHL2MPCombatWeapon | ||
{ | { | ||
public: | public: | ||
DECLARE_CLASS( CWeaponAK47, CBaseHL2MPCombatWeapon ); | |||
DECLARE_CLASS( CWeaponAK47, CBaseHL2MPCombatWeapon ); | |||
CWeaponAK47(void); | |||
DECLARE_NETWORKCLASS(); | |||
DECLARE_PREDICTABLE(); | |||
void Precache( void ); | |||
void ItemPostFrame( void ); | |||
void ItemPreFrame( void ); | |||
void ItemBusyFrame( void ); | |||
void PrimaryAttack( void ); | |||
void AddViewKick( void ); | |||
void DryFire( void ); | |||
void GetStance( void ); | |||
bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); // Required so that you un-zoom when switching weapons | |||
Activity GetPrimaryAttackActivity( void ); | |||
virtual bool Reload( void ); | |||
int GetMinBurst() { return 2; } | |||
int GetMaxBurst() { return 5; } | |||
float GetFireRate( void ) { return ROF; } | |||
//modify this part to control the general accuracy of the gun | |||
//modify this part to control the accuracy | |||
if | virtual const Vector& GetBulletSpread( void ) | ||
if (m_iStance==E_STAND) { cone = | { | ||
if (m_iStance==E_MOVE) { cone = | Vector cone = VECTOR_CONE_1DEGREES; | ||
if (m_iStance==E_RUN) { cone = | |||
if (m_iStance==E_INJURED) { cone = | // if you don't need stance and health dependent accuracy, you can just remove this. | ||
if (m_iStance==E_JUMP) { cone = | if ( m_iStance == E_DUCK ) | ||
if (m_iStance==E_DYING) { cone = VECTOR_CONE_10DEGREES;} | { cone = VECTOR_CONE_1DEGREES;} | ||
if ( m_iStance == E_STAND ) | |||
{ cone = VECTOR_CONE_2DEGREES;} | |||
if ( m_iStance == E_MOVE ) | |||
{ cone = VECTOR_CONE_3DEGREES;} | |||
if ( m_iStance == E_RUN ) | |||
{ cone = VECTOR_CONE_4DEGREES;} | |||
if ( m_iStance == E_INJURED ) | |||
{ cone = VECTOR_CONE_3DEGREES;} | |||
if ( m_iStance == E_JUMP ) | |||
{ cone = VECTOR_CONE_4DEGREES;} | |||
if ( m_iStance == E_DYING ) | |||
{ cone = VECTOR_CONE_10DEGREES;} | |||
if (m_iBurst!=BURST) | //This part simlates recoil. Each successive shot will have increased spread. | ||
{ | if (m_iBurst!=BURST) | ||
for (int i= | { | ||
{ | for (int i = m_iBurst; i < BURST; i++) | ||
cone+=VECTOR_CONE_1DEGREES;} | { | ||
} | cone += VECTOR_CONE_1DEGREES; | ||
} | |||
return cone; | } | ||
} | |||
void ToggleZoom( void ); | //This part is the zoom modifier. If in zoom, lower the bullet spread. | ||
void CheckZoomToggle( void ); | if (m_bInZoom) | ||
{ | |||
cone -= VECTOR_CONE_1DEGREES; | |||
} | |||
return cone; | |||
} | |||
void ToggleZoom( void ); | |||
void CheckZoomToggle( void ); | |||
DECLARE_ACTTABLE(); | |||
private: | |||
CNetworkVar( int, m_iBurst ); | |||
CNetworkVar( bool, m_bInZoom ); | |||
private: | CNetworkVar( float, m_flAttackEnds ); | ||
CNetworkVar( int, m_iBurst ); | CNetworkVar( int, m_iStance); | ||
CNetworkVar( bool, m_bInZoom ); | |||
CNetworkVar( float, m_flAttackEnds ); | |||
CNetworkVar( int, m_iStance); | |||
private: | private: | ||
CWeaponAK47( const CWeaponAK47 & ); | CWeaponAK47( const CWeaponAK47 & ); | ||
}; | }; | ||
Line 115: | Line 131: | ||
BEGIN_NETWORK_TABLE( CWeaponAK47, DT_WeaponAK47 ) | BEGIN_NETWORK_TABLE( CWeaponAK47, DT_WeaponAK47 ) | ||
#ifdef CLIENT_DLL | #ifdef CLIENT_DLL | ||
RecvPropInt( RECVINFO( m_iBurst) ), | RecvPropInt( RECVINFO( m_iBurst) ), | ||
RecvPropBool( RECVINFO( m_bInZoom ) ), | RecvPropBool( RECVINFO( m_bInZoom ) ), | ||
RecvPropTime( RECVINFO( m_flAttackEnds ) ), | RecvPropTime( RECVINFO( m_flAttackEnds ) ), | ||
RecvPropInt( RECVINFO( m_iStance ) ), | RecvPropInt( RECVINFO( m_iStance ) ), | ||
#else | #else | ||
SendPropInt( SENDINFO( m_iBurst ) ), | SendPropInt( SENDINFO( m_iBurst ) ), | ||
SendPropBool( SENDINFO( m_bInZoom ) ), | SendPropBool( SENDINFO( m_bInZoom ) ), | ||
SendPropTime( SENDINFO( m_flAttackEnds ) ), | SendPropTime( SENDINFO( m_flAttackEnds ) ), | ||
SendPropInt( SENDINFO( m_iStance ) ), | SendPropInt( SENDINFO( m_iStance ) ), | ||
#endif | #endif | ||
END_NETWORK_TABLE() | END_NETWORK_TABLE() | ||
Line 132: | Line 148: | ||
LINK_ENTITY_TO_CLASS( weapon_AK47, CWeaponAK47 ); | LINK_ENTITY_TO_CLASS( weapon_AK47, CWeaponAK47 ); | ||
PRECACHE_WEAPON_REGISTER( weapon_AK47 ); | PRECACHE_WEAPON_REGISTER( weapon_AK47 ); | ||
acttable_t CWeaponAK47::m_acttable[] = | acttable_t CWeaponAK47::m_acttable[] = | ||
{ | { | ||
{ ACT_MP_STAND_IDLE, ACT_HL2MP_IDLE_AR2, false }, | |||
{ ACT_MP_CROUCH_IDLE, ACT_HL2MP_IDLE_CROUCH_AR2, false }, | |||
{ ACT_MP_RUN, ACT_HL2MP_RUN_AR2, false }, | |||
{ ACT_MP_CROUCHWALK, ACT_HL2MP_WALK_CROUCH_AR2, false }, | |||
{ ACT_MP_ATTACK_STAND_PRIMARYFIRE, ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false }, | |||
{ ACT_MP_ATTACK_CROUCH_PRIMARYFIRE, ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false }, | |||
{ ACT_MP_RELOAD_STAND, ACT_HL2MP_GESTURE_RELOAD_AR2, false }, | |||
{ ACT_MP_RELOAD_CROUCH, ACT_HL2MP_GESTURE_RELOAD_AR2, false }, | |||
{ ACT_MP_JUMP, ACT_HL2MP_JUMP_AR2, false }, | |||
}; | }; | ||
IMPLEMENT_ACTTABLE( CWeaponAK47 ); | IMPLEMENT_ACTTABLE( CWeaponAK47 ); | ||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
Line 162: | Line 169: | ||
CWeaponAK47::CWeaponAK47( void ) | CWeaponAK47::CWeaponAK47( void ) | ||
{ | { | ||
m_iBurst=BURST; | |||
m_iBurst=BURST; | m_iStance=10; | ||
m_iStance=10; | m_fMinRange1 = 1; | ||
m_fMaxRange1 = 1500; | |||
m_fMinRange1 = 1; | m_fMinRange2 = 1; | ||
m_fMaxRange1 = 1500; | m_fMaxRange2 = 200; | ||
m_fMinRange2 = 1; | m_bFiresUnderwater = false; | ||
m_fMaxRange2 = 200; | |||
m_bFiresUnderwater = false; | |||
} | } | ||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
// Purpose: | // Purpose: Required for caching the entity during loading | ||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
void CWeaponAK47::Precache( void ) | void CWeaponAK47::Precache( void ) | ||
{ | { | ||
BaseClass::Precache(); | BaseClass::Precache(); | ||
} | } | ||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
// Purpose: | // Purpose: The gun is empty, plays a clicking noise with a dryfire anim | ||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
void CWeaponAK47::DryFire( void ) | void CWeaponAK47::DryFire( void ) | ||
{ | { | ||
WeaponSound( EMPTY ); | WeaponSound( EMPTY ); | ||
SendWeaponAnim( ACT_VM_DRYFIRE ); | SendWeaponAnim( ACT_VM_DRYFIRE ); | ||
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); | |||
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); | |||
} | } | ||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
// Purpose: | // Purpose: Click and hold the primary fire button | ||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
void CWeaponAK47::PrimaryAttack( void ) | void CWeaponAK47::PrimaryAttack( void ) | ||
{ | { | ||
if (m_iBurst!=0) | //do we have any bullets left from the current burst cycle? | ||
{ | if (m_iBurst!=0) | ||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); | { | ||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); | CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); | ||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); | |||
if ( !pPlayer ) | |||
{ return; } | |||
WeaponSound( SINGLE ); | |||
pPlayer->DoMuzzleFlash(); | |||
SendWeaponAnim( ACT_VM_PRIMARYATTACK ); | |||
pPlayer->SetAnimation( PLAYER_ATTACK1 ); | |||
ToHL2MPPlayer(pPlayer)->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_PRIMARY ); | |||
// Each time the player fires the gun, reset the view punch. | |||
if ( pOwner ) | |||
{ pOwner->ViewPunchReset(); } | |||
BaseClass::PrimaryAttack(); | |||
// We fired one shot, decrease the number of bullets available for this burst cycle | |||
m_iBurst--; | |||
// | m_flNextPrimaryAttack =gpGlobals->curtime + ROF; | ||
m_flAttackEnds = gpGlobals->curtime + SequenceDuration(); | |||
} | |||
} | } | ||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
Line 244: | Line 234: | ||
void CWeaponAK47::ItemPreFrame( void ) | void CWeaponAK47::ItemPreFrame( void ) | ||
{ | { | ||
GetStance(); | |||
GetStance(); | BaseClass::ItemPreFrame(); | ||
BaseClass::ItemPreFrame(); | |||
} | } | ||
Line 254: | Line 243: | ||
void CWeaponAK47::ItemBusyFrame( void ) | void CWeaponAK47::ItemBusyFrame( void ) | ||
{ | { | ||
// Allow zoom toggling even when we're reloading | |||
CheckZoomToggle(); | |||
BaseClass::ItemBusyFrame(); | |||
} | } | ||
Line 265: | Line 253: | ||
void CWeaponAK47::ItemPostFrame( void ) | void CWeaponAK47::ItemPostFrame( void ) | ||
{ | { | ||
BaseClass::ItemPostFrame(); | BaseClass::ItemPostFrame(); | ||
if ( m_bInReload ) | |||
if ( m_bInReload ) | { return; } | ||
return; | |||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); | |||
if ( pOwner == NULL ) | |||
{ return; } | |||
if ( pOwner->m_nButtons & IN_ATTACK ) | |||
{ | |||
if (m_flAttackEnds<gpGlobals->curtime) | |||
{ SendWeaponAnim(ACT_VM_IDLE); } | |||
} | |||
else | |||
{ | |||
//The firing cycle ended. Reset the burst counter to the max value | |||
m_iBurst=BURST; | |||
if ( ( pOwner->m_nButtons & IN_ATTACK ) && ( m_flNextPrimaryAttack < gpGlobals->curtime ) && ( m_iClip1 <= 0 ) ) | |||
{ DryFire(); } | |||
} | |||
CheckZoomToggle(); | |||
//check the character's current stance for the accuracy calculation | |||
GetStance(); | |||
} | } | ||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
// Purpose: | // Purpose: If we have bullets left then play the attack anim otherwise idle | ||
// Output : int | // Output : int | ||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
Activity CWeaponAK47::GetPrimaryAttackActivity( void ) | Activity CWeaponAK47::GetPrimaryAttackActivity( void ) | ||
{ | { | ||
if (m_iBurst!=0) | if (m_iBurst!=0) | ||
{ | { return ACT_VM_PRIMARYATTACK; } | ||
return ACT_VM_PRIMARYATTACK; | else | ||
} | { return ACT_VM_IDLE; } | ||
else | |||
{ | |||
return ACT_VM_IDLE; | |||
} | |||
} | } | ||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
// Purpose: The gun is being reloaded | |||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
bool CWeaponAK47::Reload( void ) | bool CWeaponAK47::Reload( void ) | ||
{ | { | ||
bool fRet = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD ); | bool fRet = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD ); | ||
if ( fRet ) | if ( fRet ) | ||
{ | { | ||
WeaponSound( RELOAD ); | WeaponSound( RELOAD ); | ||
ToHL2MPPlayer(GetOwner())->DoAnimationEvent( PLAYERANIMEVENT_RELOAD ); | ToHL2MPPlayer(GetOwner())->DoAnimationEvent( PLAYERANIMEVENT_RELOAD ); | ||
m_iBurst=BURST; | //reset the burst counter to the default | ||
m_iBurst=BURST; | |||
} | |||
return fRet; | |||
} | } | ||
//----------------------------------------------------------------------------- | |||
// Purpose: Put away the gun and disable zoom if needed | |||
//----------------------------------------------------------------------------- | |||
bool CWeaponAK47::Holster(CBaseCombatWeapon *pSwitchingTo /* = NULL */) | bool CWeaponAK47::Holster(CBaseCombatWeapon *pSwitchingTo /* = NULL */) | ||
{ | { | ||
if ( m_bInZoom ) | if ( m_bInZoom ) | ||
{ | { ToggleZoom(); } | ||
ToggleZoom(); | return BaseClass::Holster( pSwitchingTo ); | ||
} | |||
return BaseClass::Holster( pSwitchingTo ); | |||
} | } | ||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
// Purpose: | // Purpose: Calculate the viewkick | ||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
void CWeaponAK47::AddViewKick( void ) | void CWeaponAK47::AddViewKick( void ) | ||
{ | { | ||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); | CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); | ||
if ( pPlayer == NULL ) | |||
{ return; } | |||
int iSeed = CBaseEntity::GetPredictionRandomSeed() & 255; | |||
RandomSeed( iSeed ); | |||
QAngle viewPunch; | |||
viewPunch.x = random->RandomFloat( 0.25f, 0.5f ); | |||
viewPunch.y = random->RandomFloat( -.6f, .6f ); | |||
viewPunch.z = 0.0f; | |||
//Add it to the view punch | |||
viewPunch | pPlayer->ViewPunch( viewPunch ); | ||
} | |||
//----------------------------------------------------------------------------- | |||
// Purpose: Toggle the zoom by changing the client's FOV | |||
//----------------------------------------------------------------------------- | |||
void CWeaponAK47::ToggleZoom( void ) | void CWeaponAK47::ToggleZoom( void ) | ||
{ | { | ||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); | CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); | ||
if ( pPlayer == NULL ) | if ( pPlayer == NULL ) | ||
return; | { return; } | ||
#ifndef CLIENT_DLL | |||
if ( m_bInZoom ) | #ifndef CLIENT_DLL | ||
{ | if ( m_bInZoom ) | ||
// Narrowing the Field Of View here is what gives us the zoomed effect | { | ||
if ( pPlayer->SetFOV( this, 0, 0.2f ) ) | // Narrowing the Field Of View here is what gives us the zoomed effect | ||
{ | if ( pPlayer->SetFOV( this, 0, 0.2f ) ) | ||
m_bInZoom = false; | { | ||
m_bInZoom = false; | |||
// Send a message to hide the scope | // Send a message to hide the scope | ||
/* CSingleUserRecipientFilter filter(pPlayer); | /* CSingleUserRecipientFilter filter(pPlayer); | ||
UserMessageBegin(filter, "ShowScope"); | UserMessageBegin(filter, "ShowScope"); | ||
WRITE_BYTE(0); | WRITE_BYTE(0); | ||
MessageEnd();*/ | MessageEnd();*/ | ||
} | } | ||
} | } | ||
else | else | ||
{ | { | ||
if ( pPlayer->SetFOV( this, 45, 0.1f ) ) | if ( pPlayer->SetFOV( this, 45, 0.1f ) ) | ||
{ | { | ||
m_bInZoom = true; | m_bInZoom = true; | ||
// Send a message to Show the scope | // Send a message to Show the scope | ||
/* CSingleUserRecipientFilter filter(pPlayer); | /* CSingleUserRecipientFilter filter(pPlayer); | ||
UserMessageBegin(filter, "ShowScope"); | UserMessageBegin(filter, "ShowScope"); | ||
WRITE_BYTE(1); | WRITE_BYTE(1); | ||
MessageEnd();*/ | MessageEnd();*/ | ||
} | } | ||
} | } | ||
#endif | #endif | ||
} | } | ||
//----------------------------------------------------------------------------- | |||
// Purpose: Toggle the zoom if the Sec attack button was pressed | |||
//----------------------------------------------------------------------------- | |||
void CWeaponAK47::CheckZoomToggle( void ) | void CWeaponAK47::CheckZoomToggle( void ) | ||
{ | { | ||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); | CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); | ||
if ( pPlayer && (pPlayer->m_afButtonPressed & IN_ATTACK2)) | |||
if ( pPlayer && (pPlayer->m_afButtonPressed & IN_ATTACK2)) | { ToggleZoom(); } | ||
{ | |||
ToggleZoom(); | |||
} | } | ||
//----------------------------------------------------------------------------- | |||
// Purpose: Get the current stance/status of the player | |||
//----------------------------------------------------------------------------- | |||
void CWeaponAK47::GetStance( void ) | void CWeaponAK47::GetStance( void ) | ||
{ | { | ||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); | |||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); | if ( pPlayer == NULL ) | ||
if ( pPlayer == NULL ) | { return; } | ||
return; | |||
m_iStance= E_STAND; | |||
if (pPlayer->m_nButtons & IN_DUCK) { m_iStance= E_DUCK | |||
if (pPlayer->m_nButtons & IN_FORWARD) { m_iStance= E_MOVE;} | // movement based stance | ||
if (pPlayer->m_nButtons & IN_BACK) { m_iStance= E_MOVE;} | if ( pPlayer->m_nButtons & IN_DUCK) | ||
if (pPlayer->m_nButtons & IN_MOVERIGHT) { m_iStance= E_MOVE;} | { m_iStance= E_DUCK;} | ||
if (pPlayer->m_nButtons & IN_MOVELEFT) { m_iStance= E_MOVE;} | if ( pPlayer->m_nButtons & IN_FORWARD) | ||
if (pPlayer->m_nButtons & IN_RUN) { m_iStance= E_RUN;} | { m_iStance= E_MOVE;} | ||
if (pPlayer->m_nButtons & IN_SPEED) { m_iStance= E_RUN;} | if ( pPlayer->m_nButtons & IN_BACK) | ||
if (pPlayer->m_nButtons & IN_JUMP) { m_iStance= E_JUMP;} | { m_iStance= E_MOVE;} | ||
if ( pPlayer->GetHealth()<25) { m_iStance= E_INJURED;} | if ( pPlayer->m_nButtons & IN_MOVERIGHT) | ||
if ( pPlayer->GetHealth()<10) { m_iStance= E_DYING;} | { m_iStance= E_MOVE;} | ||
if ( pPlayer->m_nButtons & IN_MOVELEFT) | |||
{ m_iStance= E_MOVE;} | |||
if ( pPlayer->m_nButtons & IN_RUN) | |||
{ m_iStance= E_RUN;} | |||
if ( pPlayer->m_nButtons & IN_SPEED) | |||
{ m_iStance= E_RUN;} | |||
if ( pPlayer->m_nButtons & IN_JUMP) | |||
{ m_iStance= E_JUMP;} | |||
//health based status | |||
if ( pPlayer->GetHealth()<25) | |||
{ m_iStance= E_INJURED;} | |||
if ( pPlayer->GetHealth()<10) | |||
{ m_iStance= E_DYING;} | |||
} | } | ||
Line 434: | Line 437: | ||
enum stances | enum stances | ||
{ | { | ||
E_STAND = 0, | E_STAND = 0, | ||
E_DUCK = 1, | E_DUCK = 1, | ||
E_MOVE = 2, | E_MOVE = 2, | ||
E_RUN = 3, | E_RUN = 3, | ||
E_INJURED = 4, | E_INJURED = 4, | ||
E_JUMP = 5, | E_JUMP = 5, | ||
E_DYING = 6, | E_DYING = 6, | ||
}; | }; | ||
</source> | </source> | ||
Line 450: | Line 453: | ||
<source lang=cpp> | <source lang=cpp> | ||
def.AddAmmoType("Rifle", | def.AddAmmoType("Rifle", DMG_BULLET, TRACER_LINE_AND_WHIZ, 0, 0, 500, BULLET_IMPULSE(200, 1225), 0 ); | ||
</source> | </source> | ||
Line 593: | Line 596: | ||
if (m_bInZoom) | if (m_bInZoom) | ||
{ | { | ||
if (m_iStance==E_DUCK) { cone = | if (m_iStance==E_DUCK) | ||
if (m_iStance==E_STAND) { cone = VECTOR_CONE_1DEGREES;} | { cone = VECTOR_CONE_0DEGREES;} | ||
if (m_iStance==E_MOVE) { cone = | if (m_iStance==E_STAND) | ||
if (m_iStance==E_RUN) { cone = VECTOR_CONE_3DEGREES;} | { cone = VECTOR_CONE_1DEGREES;} | ||
if (m_iStance==E_INJURED) { cone = VECTOR_CONE_4DEGREES;} | if (m_iStance==E_MOVE) | ||
if (m_iStance==E_JUMP) { cone = VECTOR_CONE_5DEGREES;} | { cone = VECTOR_CONE_1DEGREES;} | ||
if (m_iStance==E_DYING) { cone = VECTOR_CONE_10DEGREES;} | if (m_iStance==E_RUN) | ||
{ cone = VECTOR_CONE_3DEGREES;} | |||
if (m_iStance==E_INJURED) | |||
{ cone = VECTOR_CONE_4DEGREES;} | |||
if (m_iStance==E_JUMP) | |||
{ cone = VECTOR_CONE_5DEGREES;} | |||
if (m_iStance==E_DYING) | |||
{ cone = VECTOR_CONE_10DEGREES;} | |||
} | } | ||
if (!m_bInZoom) | if (!m_bInZoom) | ||
{ | { | ||
if (m_iStance==E_DUCK) { cone = VECTOR_CONE_1DEGREES;} | if (m_iStance==E_DUCK) | ||
if (m_iStance==E_STAND) { cone = VECTOR_CONE_1DEGREES;} | { cone = VECTOR_CONE_1DEGREES;} | ||
if (m_iStance==E_MOVE) { cone = VECTOR_CONE_2DEGREES;} | if (m_iStance==E_STAND) | ||
if (m_iStance==E_RUN) { cone = VECTOR_CONE_3DEGREES;} | { cone = VECTOR_CONE_1DEGREES;} | ||
if (m_iStance==E_INJURED) { cone = VECTOR_CONE_4DEGREES;} | if (m_iStance==E_MOVE) | ||
if (m_iStance==E_JUMP) { cone = VECTOR_CONE_5DEGREES;} | { cone = VECTOR_CONE_2DEGREES;} | ||
if (m_iStance==E_DYING) { cone = VECTOR_CONE_10DEGREES;} | if (m_iStance==E_RUN) | ||
{ cone = VECTOR_CONE_3DEGREES;} | |||
if (m_iStance==E_INJURED) | |||
{ cone = VECTOR_CONE_4DEGREES;} | |||
if (m_iStance==E_JUMP) | |||
{ cone = VECTOR_CONE_5DEGREES;} | |||
if (m_iStance==E_DYING) | |||
{ cone = VECTOR_CONE_10DEGREES;} | |||
} | } | ||
int bs=BURST; | int bs=BURST; | ||
if (m_iBurst!=bs) | if (m_iBurst!=bs) | ||
{ | { | ||
for (int i=0;i<(bs-m_iBurst);i++) | //for (int i=0;i<(bs-m_iBurst);i++) | ||
{cone=cone+VECTOR_CONE_1DEGREES;} | for (int i = m_iBurst; i < bs; i++) | ||
{ | |||
cone=cone+VECTOR_CONE_1DEGREES; | |||
} | |||
} | } | ||
</source> | </source> | ||
Line 627: | Line 647: | ||
//modify this to alter the rate of fire | //modify this to alter the rate of fire | ||
#define ROF 0.080f //800 rounds/min | #define ROF 0.080f //800 rounds/min | ||
</source> | </source> | ||
Line 636: | Line 654: | ||
acttable_t CWeaponAK47::m_acttable[] = | acttable_t CWeaponAK47::m_acttable[] = | ||
{ | { | ||
{ ACT_MP_STAND_IDLE, ACT_HL2MP_IDLE_AR2, false }, | |||
{ ACT_MP_CROUCH_IDLE, ACT_HL2MP_IDLE_CROUCH_AR2, false }, | |||
{ ACT_MP_RUN, ACT_HL2MP_RUN_AR2, false }, | |||
{ ACT_MP_CROUCHWALK, ACT_HL2MP_WALK_CROUCH_AR2, false }, | |||
{ ACT_MP_ATTACK_STAND_PRIMARYFIRE, ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false }, | |||
{ ACT_MP_ATTACK_CROUCH_PRIMARYFIRE,ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false }, | |||
{ ACT_MP_RELOAD_STAND, ACT_HL2MP_GESTURE_RELOAD_AR2, false }, | |||
{ ACT_MP_RELOAD_CROUCH, ACT_HL2MP_GESTURE_RELOAD_AR2, false }, | |||
{ ACT_MP_JUMP, ACT_HL2MP_JUMP_AR2, false }, | |||
}; | }; | ||
Line 663: | Line 676: | ||
You have now successfully implemented a new weapon into your mod, I hope that this was understandable and easy to follow! | You have now successfully implemented a new weapon into your mod, I hope that this was understandable and easy to follow! | ||
Disclaimer: | |||
This piece of code was originally created by Pendra for the mod X-Com - Last Hope 2 | |||
[[Category:Weapons programming]] {{DISPLAYTITLE:Adding a new weapon for your mod}} | [[Category:Weapons programming]] {{DISPLAYTITLE:Adding a new weapon for your mod}} | ||
[[Category:Tutorials]] | [[Category:Tutorials]] |
Revision as of 15:52, 20 October 2012
This article will deal with creating a default weapon for your mod. This was based on an existing article which recently was removed:


The Code
Before you start you have to create two new files. Call them "weapon_<yourweaponname>.cpp", place it both in the Client and Server side of your project. In this example I will use "weapon_ak47"


WEAPON_AK47.CPP
#include "cbase.h"
#include "npcevent.h"
#include "in_buttons.h"
#ifdef CLIENT_DLL
#include "c_hl2mp_player.h"
#else
#include "hl2mp_player.h"
#endif
#include "weapon_hl2mpbasehlmpcombatweapon.h"
//modify this to alter the rate of fire
#define ROF 0.075f //RPS, 60 Sec / 800 Rounds = 0.075f
//The gun will fire up to this number of bullets while you hold the fire button.
//If you set it to 1 the gun will be semi auto. If you set it to 3 the gun will fire three round bursts
#define BURST 500;
#ifdef CLIENT_DLL
#define CWeaponAK47 C_WeaponAK47
#endif
//-----------------------------------------------------------------------------
// CWeaponAK47
//-----------------------------------------------------------------------------
class CWeaponAK47 : public CBaseHL2MPCombatWeapon
{
public:
DECLARE_CLASS( CWeaponAK47, CBaseHL2MPCombatWeapon );
CWeaponAK47(void);
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
void Precache( void );
void ItemPostFrame( void );
void ItemPreFrame( void );
void ItemBusyFrame( void );
void PrimaryAttack( void );
void AddViewKick( void );
void DryFire( void );
void GetStance( void );
bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); // Required so that you un-zoom when switching weapons
Activity GetPrimaryAttackActivity( void );
virtual bool Reload( void );
int GetMinBurst() { return 2; }
int GetMaxBurst() { return 5; }
float GetFireRate( void ) { return ROF; }
//modify this part to control the general accuracy of the gun
virtual const Vector& GetBulletSpread( void )
{
Vector cone = VECTOR_CONE_1DEGREES;
// if you don't need stance and health dependent accuracy, you can just remove this.
if ( m_iStance == E_DUCK )
{ cone = VECTOR_CONE_1DEGREES;}
if ( m_iStance == E_STAND )
{ cone = VECTOR_CONE_2DEGREES;}
if ( m_iStance == E_MOVE )
{ cone = VECTOR_CONE_3DEGREES;}
if ( m_iStance == E_RUN )
{ cone = VECTOR_CONE_4DEGREES;}
if ( m_iStance == E_INJURED )
{ cone = VECTOR_CONE_3DEGREES;}
if ( m_iStance == E_JUMP )
{ cone = VECTOR_CONE_4DEGREES;}
if ( m_iStance == E_DYING )
{ cone = VECTOR_CONE_10DEGREES;}
//This part simlates recoil. Each successive shot will have increased spread.
if (m_iBurst!=BURST)
{
for (int i = m_iBurst; i < BURST; i++)
{
cone += VECTOR_CONE_1DEGREES;
}
}
//This part is the zoom modifier. If in zoom, lower the bullet spread.
if (m_bInZoom)
{
cone -= VECTOR_CONE_1DEGREES;
}
return cone;
}
void ToggleZoom( void );
void CheckZoomToggle( void );
DECLARE_ACTTABLE();
private:
CNetworkVar( int, m_iBurst );
CNetworkVar( bool, m_bInZoom );
CNetworkVar( float, m_flAttackEnds );
CNetworkVar( int, m_iStance);
private:
CWeaponAK47( const CWeaponAK47 & );
};
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponAK47, DT_WeaponAK47 )
BEGIN_NETWORK_TABLE( CWeaponAK47, DT_WeaponAK47 )
#ifdef CLIENT_DLL
RecvPropInt( RECVINFO( m_iBurst) ),
RecvPropBool( RECVINFO( m_bInZoom ) ),
RecvPropTime( RECVINFO( m_flAttackEnds ) ),
RecvPropInt( RECVINFO( m_iStance ) ),
#else
SendPropInt( SENDINFO( m_iBurst ) ),
SendPropBool( SENDINFO( m_bInZoom ) ),
SendPropTime( SENDINFO( m_flAttackEnds ) ),
SendPropInt( SENDINFO( m_iStance ) ),
#endif
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponAK47 )
END_PREDICTION_DATA()
LINK_ENTITY_TO_CLASS( weapon_AK47, CWeaponAK47 );
PRECACHE_WEAPON_REGISTER( weapon_AK47 );
acttable_t CWeaponAK47::m_acttable[] =
{
{ ACT_MP_STAND_IDLE, ACT_HL2MP_IDLE_AR2, false },
{ ACT_MP_CROUCH_IDLE, ACT_HL2MP_IDLE_CROUCH_AR2, false },
{ ACT_MP_RUN, ACT_HL2MP_RUN_AR2, false },
{ ACT_MP_CROUCHWALK, ACT_HL2MP_WALK_CROUCH_AR2, false },
{ ACT_MP_ATTACK_STAND_PRIMARYFIRE, ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false },
{ ACT_MP_ATTACK_CROUCH_PRIMARYFIRE, ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false },
{ ACT_MP_RELOAD_STAND, ACT_HL2MP_GESTURE_RELOAD_AR2, false },
{ ACT_MP_RELOAD_CROUCH, ACT_HL2MP_GESTURE_RELOAD_AR2, false },
{ ACT_MP_JUMP, ACT_HL2MP_JUMP_AR2, false },
};
IMPLEMENT_ACTTABLE( CWeaponAK47 );
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CWeaponAK47::CWeaponAK47( void )
{
m_iBurst=BURST;
m_iStance=10;
m_fMinRange1 = 1;
m_fMaxRange1 = 1500;
m_fMinRange2 = 1;
m_fMaxRange2 = 200;
m_bFiresUnderwater = false;
}
//-----------------------------------------------------------------------------
// Purpose: Required for caching the entity during loading
//-----------------------------------------------------------------------------
void CWeaponAK47::Precache( void )
{
BaseClass::Precache();
}
//-----------------------------------------------------------------------------
// Purpose: The gun is empty, plays a clicking noise with a dryfire anim
//-----------------------------------------------------------------------------
void CWeaponAK47::DryFire( void )
{
WeaponSound( EMPTY );
SendWeaponAnim( ACT_VM_DRYFIRE );
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
}
//-----------------------------------------------------------------------------
// Purpose: Click and hold the primary fire button
//-----------------------------------------------------------------------------
void CWeaponAK47::PrimaryAttack( void )
{
//do we have any bullets left from the current burst cycle?
if (m_iBurst!=0)
{
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
if ( !pPlayer )
{ return; }
WeaponSound( SINGLE );
pPlayer->DoMuzzleFlash();
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
pPlayer->SetAnimation( PLAYER_ATTACK1 );
ToHL2MPPlayer(pPlayer)->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_PRIMARY );
// Each time the player fires the gun, reset the view punch.
if ( pOwner )
{ pOwner->ViewPunchReset(); }
BaseClass::PrimaryAttack();
// We fired one shot, decrease the number of bullets available for this burst cycle
m_iBurst--;
m_flNextPrimaryAttack =gpGlobals->curtime + ROF;
m_flAttackEnds = gpGlobals->curtime + SequenceDuration();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponAK47::ItemPreFrame( void )
{
GetStance();
BaseClass::ItemPreFrame();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponAK47::ItemBusyFrame( void )
{
// Allow zoom toggling even when we're reloading
CheckZoomToggle();
BaseClass::ItemBusyFrame();
}
//-----------------------------------------------------------------------------
// Purpose: Allows firing as fast as button is pressed
//-----------------------------------------------------------------------------
void CWeaponAK47::ItemPostFrame( void )
{
BaseClass::ItemPostFrame();
if ( m_bInReload )
{ return; }
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner == NULL )
{ return; }
if ( pOwner->m_nButtons & IN_ATTACK )
{
if (m_flAttackEnds<gpGlobals->curtime)
{ SendWeaponAnim(ACT_VM_IDLE); }
}
else
{
//The firing cycle ended. Reset the burst counter to the max value
m_iBurst=BURST;
if ( ( pOwner->m_nButtons & IN_ATTACK ) && ( m_flNextPrimaryAttack < gpGlobals->curtime ) && ( m_iClip1 <= 0 ) )
{ DryFire(); }
}
CheckZoomToggle();
//check the character's current stance for the accuracy calculation
GetStance();
}
//-----------------------------------------------------------------------------
// Purpose: If we have bullets left then play the attack anim otherwise idle
// Output : int
//-----------------------------------------------------------------------------
Activity CWeaponAK47::GetPrimaryAttackActivity( void )
{
if (m_iBurst!=0)
{ return ACT_VM_PRIMARYATTACK; }
else
{ return ACT_VM_IDLE; }
}
//-----------------------------------------------------------------------------
// Purpose: The gun is being reloaded
//-----------------------------------------------------------------------------
bool CWeaponAK47::Reload( void )
{
bool fRet = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD );
if ( fRet )
{
WeaponSound( RELOAD );
ToHL2MPPlayer(GetOwner())->DoAnimationEvent( PLAYERANIMEVENT_RELOAD );
//reset the burst counter to the default
m_iBurst=BURST;
}
return fRet;
}
//-----------------------------------------------------------------------------
// Purpose: Put away the gun and disable zoom if needed
//-----------------------------------------------------------------------------
bool CWeaponAK47::Holster(CBaseCombatWeapon *pSwitchingTo /* = NULL */)
{
if ( m_bInZoom )
{ ToggleZoom(); }
return BaseClass::Holster( pSwitchingTo );
}
//-----------------------------------------------------------------------------
// Purpose: Calculate the viewkick
//-----------------------------------------------------------------------------
void CWeaponAK47::AddViewKick( void )
{
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
if ( pPlayer == NULL )
{ return; }
int iSeed = CBaseEntity::GetPredictionRandomSeed() & 255;
RandomSeed( iSeed );
QAngle viewPunch;
viewPunch.x = random->RandomFloat( 0.25f, 0.5f );
viewPunch.y = random->RandomFloat( -.6f, .6f );
viewPunch.z = 0.0f;
//Add it to the view punch
pPlayer->ViewPunch( viewPunch );
}
//-----------------------------------------------------------------------------
// Purpose: Toggle the zoom by changing the client's FOV
//-----------------------------------------------------------------------------
void CWeaponAK47::ToggleZoom( void )
{
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
if ( pPlayer == NULL )
{ return; }
#ifndef CLIENT_DLL
if ( m_bInZoom )
{
// Narrowing the Field Of View here is what gives us the zoomed effect
if ( pPlayer->SetFOV( this, 0, 0.2f ) )
{
m_bInZoom = false;
// Send a message to hide the scope
/* CSingleUserRecipientFilter filter(pPlayer);
UserMessageBegin(filter, "ShowScope");
WRITE_BYTE(0);
MessageEnd();*/
}
}
else
{
if ( pPlayer->SetFOV( this, 45, 0.1f ) )
{
m_bInZoom = true;
// Send a message to Show the scope
/* CSingleUserRecipientFilter filter(pPlayer);
UserMessageBegin(filter, "ShowScope");
WRITE_BYTE(1);
MessageEnd();*/
}
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Toggle the zoom if the Sec attack button was pressed
//-----------------------------------------------------------------------------
void CWeaponAK47::CheckZoomToggle( void )
{
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
if ( pPlayer && (pPlayer->m_afButtonPressed & IN_ATTACK2))
{ ToggleZoom(); }
}
//-----------------------------------------------------------------------------
// Purpose: Get the current stance/status of the player
//-----------------------------------------------------------------------------
void CWeaponAK47::GetStance( void )
{
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
if ( pPlayer == NULL )
{ return; }
m_iStance= E_STAND;
// movement based stance
if ( pPlayer->m_nButtons & IN_DUCK)
{ m_iStance= E_DUCK;}
if ( pPlayer->m_nButtons & IN_FORWARD)
{ m_iStance= E_MOVE;}
if ( pPlayer->m_nButtons & IN_BACK)
{ m_iStance= E_MOVE;}
if ( pPlayer->m_nButtons & IN_MOVERIGHT)
{ m_iStance= E_MOVE;}
if ( pPlayer->m_nButtons & IN_MOVELEFT)
{ m_iStance= E_MOVE;}
if ( pPlayer->m_nButtons & IN_RUN)
{ m_iStance= E_RUN;}
if ( pPlayer->m_nButtons & IN_SPEED)
{ m_iStance= E_RUN;}
if ( pPlayer->m_nButtons & IN_JUMP)
{ m_iStance= E_JUMP;}
//health based status
if ( pPlayer->GetHealth()<25)
{ m_iStance= E_INJURED;}
if ( pPlayer->GetHealth()<10)
{ m_iStance= E_DYING;}
}
WEAPON_HL2MPBASEHLMPCOMBATWEAPON.h
Here you will declare the m_istance's. Add this below CBaseHL2MPCombatWeapon( const CBaseHL2MPCombatWeapon & ); - around line 60:
enum stances
{
E_STAND = 0,
E_DUCK = 1,
E_MOVE = 2,
E_RUN = 3,
E_INJURED = 4,
E_JUMP = 5,
E_DYING = 6,
};
HL2MP_GAMERULES.CPP
Here we need to declare the ammo type of our new weapon, as well as max ammo, etc... Add this below def.AddAmmoType("AR2" -=- around line 931:
def.AddAmmoType("Rifle", DMG_BULLET, TRACER_LINE_AND_WHIZ, 0, 0, 500, BULLET_IMPULSE(200, 1225), 0 );
Change "Rifle" to the ammotype you have added in your weapon_yourweaponname.txt in your mod/script folder, or you could use an existing ammotype like the SMG1 ammotype rather than creating a new ammotype. If so, then you can skip this step, as the existing ammotype already is implemented in this code. And if you want to change max ammo then change 500 to another value.
C_WEAPON__STUBS_HL2.CPP
In order to use the weapon at all you need to declare your new weapon here. Below STUB_WEAPON_CLASS( weapon_ar2, WeaponAR2, C_HLMachineGun ); add this:
STUB_WEAPON_CLASS( weapon_ak47, WeaponAK47, C_BaseHLCombatWeapon );
SCRIPT FILE
Now you have to tell your weapon which ammotype, model, weight, flags, damage, anim prefix and what bucket in the weapon selection HUD it will use. To do this you need to create a script file in your "mod/scripts" folder. Call it "weapon_<yourweaponname>" in this case I called mine "weapon_ak47" Here is an example:
WeaponData
{
// Weapon data is loaded by both the Game and Client DLLs.
"printname" "AK47"
"viewmodel" "models/weapons/v_rif_ak47.mdl" // Client view model
"playermodel" "models/weapons/w_rif_ak47.mdl" // Server world model
"anim_prefix" "ar2" // The HUD icon which will be shown when browsing for this weapon in the weapon selection hud, most likely loaded from halflife2.ttf or hl2mp.ttf.
"bucket" "5" // The horizontal direction.
"bucket_position" "3" // The vertical direction.
"clip_size" "30" // How many bullets you can fire before you have to reload.
"default_clip" "500" // How much ammo this weapon can carry.
"clip2_size" "-1"
"default_clip2" "-1"
"primary_ammo" "Rifle" // The ammotype for the weapon, this can be found in hl2mp_gamerules.cpp: def.AddAmmoType(
"secondary_ammo" "None"
"weight" "6" // If the weight is higher than your current weapon you will automatically switch to that weapon when you pick it up.
"item_flags" "0"
"BuiltRightHanded" "1"
"AllowFlipping" "1"
"damage" "75" // Damage per bullet, if it is a higher value then you will more likely die by one bullet.
// Sounds for the weapon. There is a max of 16 sounds per category (i.e. max 16 "single_shot" sounds)
SoundData
{
"special1" "Weapon_CombineGuard.Special1"
"empty" "Weapon_IRifle.Empty"
"double_shot" "Weapon_AK47.Single"
"reload" "Weapon_AK47.Reload" // Sound triggered when reloading. Activate this in the game_sounds_weapons.
"single_shot" "Weapon_AK47.Single" // Sound triggered when shooting. -=-
// NPC SECTION
"single_shot_npc" "Weapon_AK47.NPC_Single"
"reload_npc" "Weapon_AR2.NPC_Reload"
"double_shot_npc" "Weapon_AK47.NPC_Double"
}
// Weapon Sprite data is loaded by the Client DLL.
TextureData
{
"weapon"
{
"font" "WeaponIcons"
"character" "l"
}
"weapon_s"
{
"font" "WeaponIconsSelected"
"character" "l"
}
"weapon_small"
{
"font" "WeaponIconsSmall"
"character" "l"
}
"ammo"
{
"font" "WeaponIconsSmall"
"character" "u"
}
"ammo2"
{
"font" "WeaponIconsSmall"
"character" "z"
}
"crosshair"
{
"font" "Crosshairs"
"character" "Q"
}
"autoaim"
{
"file" "sprites/crosshairs"
"x" "0"
"y" "48"
"width" "24"
"height" "24"
}
}
}
EXTRA
You can now use the weapon in-game. Compile your mod and type this in console:
sv_cheats 1
give weapon_<yourweaponname>
You should now be wielding your new weapon.
If you want to spawn with your new weapon add this in HL2MP_PLAYER.CPP below void CHL2MP_Player::GiveDefaultItems( void ):
GiveNamedItem( "weapon_ak47" );
And if you want to get your new weapon by the impulse101 cheat command then add this in the same file but below void CHL2MP_Player::GiveAllItems( void ):
GiveNamedItem( "weapon_ak47" );
And you probably want to create default maps for your mod and add this weapon as a pickup, then add this into the .FGD file for your mod:
@PointClass base(Weapon) studio("models/weapons/w_rif_ak47.mdl") = weapon_ak47 : "AK47" []
To change the accuracy of your weapon then edit this part of the "WEAPON_YOURWEAPONNAME.CPP" file:
static Vector cone=VECTOR_CONE_1DEGREES;
if (m_bInZoom)
{
if (m_iStance==E_DUCK)
{ cone = VECTOR_CONE_0DEGREES;}
if (m_iStance==E_STAND)
{ cone = VECTOR_CONE_1DEGREES;}
if (m_iStance==E_MOVE)
{ cone = VECTOR_CONE_1DEGREES;}
if (m_iStance==E_RUN)
{ cone = VECTOR_CONE_3DEGREES;}
if (m_iStance==E_INJURED)
{ cone = VECTOR_CONE_4DEGREES;}
if (m_iStance==E_JUMP)
{ cone = VECTOR_CONE_5DEGREES;}
if (m_iStance==E_DYING)
{ cone = VECTOR_CONE_10DEGREES;}
}
if (!m_bInZoom)
{
if (m_iStance==E_DUCK)
{ cone = VECTOR_CONE_1DEGREES;}
if (m_iStance==E_STAND)
{ cone = VECTOR_CONE_1DEGREES;}
if (m_iStance==E_MOVE)
{ cone = VECTOR_CONE_2DEGREES;}
if (m_iStance==E_RUN)
{ cone = VECTOR_CONE_3DEGREES;}
if (m_iStance==E_INJURED)
{ cone = VECTOR_CONE_4DEGREES;}
if (m_iStance==E_JUMP)
{ cone = VECTOR_CONE_5DEGREES;}
if (m_iStance==E_DYING)
{ cone = VECTOR_CONE_10DEGREES;}
}
int bs=BURST;
if (m_iBurst!=bs)
{
//for (int i=0;i<(bs-m_iBurst);i++)
for (int i = m_iBurst; i < bs; i++)
{
cone=cone+VECTOR_CONE_1DEGREES;
}
}
A higher value means more imprecise accuracy, and bullets will more likely spread in all angles. A lower value is recommended.
To change the rate of fire edit this part of the "WEAPON_YOURWEAPONNAME.CPP" file:
//modify this to alter the rate of fire
#define ROF 0.080f //800 rounds/min
To add different animations to your weapon (not default ones, but other animations implemented by Valve) edit this part of the "WEAPON_YOURWEAPONNAME.CPP" file:
acttable_t CWeaponAK47::m_acttable[] =
{
{ ACT_MP_STAND_IDLE, ACT_HL2MP_IDLE_AR2, false },
{ ACT_MP_CROUCH_IDLE, ACT_HL2MP_IDLE_CROUCH_AR2, false },
{ ACT_MP_RUN, ACT_HL2MP_RUN_AR2, false },
{ ACT_MP_CROUCHWALK, ACT_HL2MP_WALK_CROUCH_AR2, false },
{ ACT_MP_ATTACK_STAND_PRIMARYFIRE, ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false },
{ ACT_MP_ATTACK_CROUCH_PRIMARYFIRE,ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false },
{ ACT_MP_RELOAD_STAND, ACT_HL2MP_GESTURE_RELOAD_AR2, false },
{ ACT_MP_RELOAD_CROUCH, ACT_HL2MP_GESTURE_RELOAD_AR2, false },
{ ACT_MP_JUMP, ACT_HL2MP_JUMP_AR2, false },
};
IMPLEMENT_ACTTABLE( CWeaponAK47 );
If you would rather have the SMG1 animations then change _AR2 to _SMG1 instead. And if you want to use the pistol animations change _AR2 to _PISTOL... etc...
Finish
You have now successfully implemented a new weapon into your mod, I hope that this was understandable and easy to follow!
Disclaimer: This piece of code was originally created by Pendra for the mod X-Com - Last Hope 2