/*** * * Copyright (C) 2002 The Wastes Project, All Rights Reserved. * * This product contains software technology from Valve Software, LLC, * Copyright © 1996-2001, Valve LLC, All rights reserved. * * Use, distribution, and modification of this source code and/or resulting * object code is restricted to non-commercial enhancements to products from * The Wastes Project. All other use, distribution, or modification is prohibited * without written permission from The Wastes Project. * ***/ #include "extdll.h" #include "util.h" #include "cbase.h" #include "weapons.h" #include "weaponinfo.h" #include "player.h" #include "soundent.h" #include "thewastes.h" #include "game.h" #include "gamerules.h" // Entity Linkage LINK_ENTITY_TO_CLASS( weapon_akimboberettas, CAkimboBerettas ); LINK_ENTITY_TO_CLASS( weapon_akimbocolts, CAkimboColts ); LINK_ENTITY_TO_CLASS( weapon_akimbodeagles, CAkimboDeagles ); LINK_ENTITY_TO_CLASS( weapon_akimbosawedoffs, CAkimboSawedOffs ); /************* Akimbo weapon *************/ void CAkimboWeapon::Spawn() { CWasteWeapon::Spawn(); Precache(); m_bSlowFire = FALSE; m_iCurrentHand = AH_LEFT; FallInit(); } int CAkimboWeapon::GetItemInfo(ItemInfo *p) { p->pszName = STRING(pev->classname); p->iSlot = 5; p->iFlags = 0; p->iPosition = iItemSlot() - 1; return 1; } void CAkimboWeapon::PackWeapon(void *weapon_data) { weapon_data_t *local_data = (weapon_data_t*)weapon_data; local_data->m_iWeaponState = m_iCurrentHand; } void CAkimboWeapon::UnpackWeapon(void *weapon_data) { weapon_data_t *local_data = (weapon_data_t*)weapon_data; m_iCurrentHand = local_data->m_iWeaponState; } void CAkimboWeapon::ItemPostFrame() { if( ( m_fInReload ) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) ) { // complete the reload. int j = Q_min( iMaxClip(), m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ); // For animations sake, if we are putting an odd number of bullets in, // swap the current hand to the right hand if ( j % 2 != 0 ) m_iCurrentHand = AH_RIGHT; m_iClip = 0; // Add them to the clip m_iClip += j; m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j; #ifndef CLIENT_DLL m_pPlayer->TabulateAmmo(); #endif m_fInReload = FALSE; } CWasteWeapon::ItemPostFrame(); } void CAkimboWeapon::PrimaryAttack() { if( m_iClip <= 0 ) { if( m_fFireOnEmpty ) { PlayEmptySound(); m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3f; } SendWeaponAnim( (m_iCurrentHand == AH_RIGHT) ? AKIMBO_RSHOOTEMPTY : AKIMBO_LSHOOTEMPTY, UseDecrement() ? 1 : 0 ); ( m_iCurrentHand == AH_LEFT ) ? m_iCurrentHand = AH_RIGHT : m_iCurrentHand = AH_LEFT; return; } m_iClip--; m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; Vector vecSrc = m_pPlayer->GetGunPosition(); Vector vecAiming = gpGlobals->v_forward; Vector dir; float spread = m_fAccuracy; if( m_bSlowFire ) spread = m_fAccuracy * 0.50f; // Accuracy modifiers if(m_pPlayer->pev->flags & FL_DUCKING) dir = m_pPlayer->FireBulletsPlayer(this, 1, vecSrc, vecAiming, Vector(spread*SIDEARM_DUCKPENALTY,spread*SIDEARM_DUCKPENALTY,spread*SIDEARM_DUCKPENALTY), 8192, m_iBulletType, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed, P_HANDCANNON ); else if(m_pPlayer->pev->flags & FL_ONGROUND) dir = m_pPlayer->FireBulletsPlayer(this, 1, vecSrc, vecAiming, Vector(spread,spread,spread), 8192, m_iBulletType, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed, P_HANDCANNON ); else dir = m_pPlayer->FireBulletsPlayer(this, 1, vecSrc, vecAiming, Vector(spread*SIDEARM_JUMPPENALTY,spread*SIDEARM_JUMPPENALTY,spread*SIDEARM_JUMPPENALTY), 8192, m_iBulletType, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed, P_HANDCANNON ); int flags; #if defined( CLIENT_WEAPONS ) flags = FEV_NOTHOST; #else flags = 0; #endif // Fire off the event PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usFire1, 0.0, (float*)&g_vecZero, (float*)&g_vecZero, dir.x, dir.y, m_iCurrentHand, m_iClip, 0, 0 ); ( m_iCurrentHand == AH_LEFT ) ? m_iCurrentHand = AH_RIGHT : m_iCurrentHand = AH_LEFT; m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + m_fRateOfFire; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_FLOAT( 10, 15 ); } void CAkimboWeapon::SecondaryAttack() { m_bSlowFire = TRUE; PrimaryAttack(); m_bSlowFire = FALSE; m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + ( m_fRateOfFire * 2.0f ); } void CAkimboWeapon::Reload() { if(m_flNextPrimaryAttack > UTIL_WeaponTimeBase() || m_flNextSecondaryAttack > UTIL_WeaponTimeBase()) return; int iResult; // See if we need to reload if(m_iClip == m_iClipSize) return; // player "reload" animation m_pPlayer->SetAnimation( PLAYER_RELOAD ); if (m_iClip == 0) iResult = DefaultReload( m_iClipSize, AKIMBO_RELOAD2_EMPTY, 4.78f ); else iResult = DefaultReload( m_iClipSize, AKIMBO_RELOAD, 1.0f ); if (iResult) { m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_FLOAT ( 10, 15 ); // Reset hand m_iCurrentHand = AH_LEFT; } } BOOL CAkimboWeapon::PlayEmptySound() { if (m_iPlayEmptySound) { m_iPlayEmptySound = 0; return 0; } return 0; } void CAkimboWeapon::WeaponIdle() { ResetEmptySound(); } /************* Dual Berettas - John Woo meets Mad Max *************/ void CAkimboBerettas::Spawn() { pev->classname = MAKE_STRING( "weapon_akimboberettas" ); m_iBulletType = BULLET_9MMP; m_iId = WEAPON_AKIMBOBERETTAS; m_iDefaultAmmo = AMMO_GIVE_BERETTA * 2; m_iClipSize = CLIP_BERETTA * 2; m_fAccuracy = 0.078; m_fRateOfFire = 0.18; CAkimboWeapon::Spawn(); } void CAkimboBerettas::Precache() { PRECACHE_MODEL("models/v_akimbo_berettas.mdl"); PRECACHE_MODEL("models/p_akimbo_berettas.mdl"); PRECACHE_MODEL("models/shells/shell_9x18mm_lo.mdl"); PRECACHE_MODEL("models/shells/shell_9x18mm_hi.mdl"); PRECACHE_MODEL("models/shells/mag_beretta.mdl"); PRECACHE_SOUND("weapons/beretta_fire.wav"); PRECACHE_SOUND("weapons/beretta_fire_empty.wav"); m_usFire1 = PRECACHE_EVENT(1, "events/akimboberettas.sc" ); } int CAkimboBerettas::GetItemInfo( ItemInfo *p ) { p->pszAmmo1 = "9mm Parabellum"; p->iMaxAmmo1 = AMMO_MAX_BERETTA; p->pszAmmo2 = NULL; p->iMaxAmmo2 = -1; p->iMaxClip = CLIP_BERETTA * 2; p->iId = m_iId = WEAPON_AKIMBOBERETTAS; p->iWeight = WEIGHT_BERETTA * 2; return CAkimboWeapon::GetItemInfo( p ); } float CAkimboBerettas::flGetTiltedDamage() { return RANDOM_FLOAT( 38, 48 ); } const char *CAkimboBerettas::szGetDeathNoticeString() { return RANDOM_LONG(0,1) ? DEATH_AKIMBOBERETTAS_1 : DEATH_AKIMBOBERETTAS_2; } BOOL CAkimboBerettas::Deploy() { if(!DefaultDeploy("models/v_akimbo_berettas.mdl","models/p_akimbo_berettas.mdl",AKIMBO_DRAW,"akimbo")) return FALSE; return CWasteWeapon::Deploy(); } /************* Dual Colt Enforcers *************/ void CAkimboColts::Spawn() { pev->classname = MAKE_STRING( "weapon_akimbocolts" ); m_iBulletType = BULLET_10MM; m_iId = WEAPON_AKIMBOCOLTS; m_iDefaultAmmo = AMMO_GIVE_COLT * 2; m_iClipSize = CLIP_COLT * 2; m_fAccuracy = 0.080; m_fRateOfFire = 0.240; CAkimboWeapon::Spawn(); } void CAkimboColts::Precache() { PRECACHE_MODEL("models/v_akimbo_colts.mdl"); PRECACHE_MODEL("models/p_akimbo_colts.mdl"); PRECACHE_MODEL("models/shells/shell_10mm_lo.mdl"); PRECACHE_MODEL("models/shells/shell_10mm_hi.mdl"); PRECACHE_MODEL("models/shells/mag_colt.mdl"); PRECACHE_SOUND("weapons/colt_fire.wav"); PRECACHE_SOUND("weapons/colt_fire_empty.wav"); m_usFire1 = PRECACHE_EVENT(1, "events/akimbocolts.sc" ); } int CAkimboColts::GetItemInfo( ItemInfo *p ) { p->pszAmmo1 = ".40 S&W"; p->iMaxAmmo1 = AMMO_MAX_COLT; p->pszAmmo2 = NULL; p->iMaxAmmo2 = -1; p->iMaxClip = CLIP_COLT * 2; p->iId = m_iId = WEAPON_AKIMBOCOLTS; p->iWeight = WEIGHT_COLT * 2; return CAkimboWeapon::GetItemInfo( p ); } float CAkimboColts::flGetTiltedDamage() { return RANDOM_FLOAT( 45, 55 ); } const char *CAkimboColts::szGetDeathNoticeString() { return RANDOM_LONG(0,1) ? DEATH_AKIMBOCOLTS_1 : DEATH_AKIMBOCOLTS_2; } BOOL CAkimboColts::Deploy() { if(!DefaultDeploy("models/v_akimbo_colts.mdl","models/p_akimbo_colts.mdl",AKIMBO_DRAW,"akimbo")) return FALSE; return CWasteWeapon::Deploy(); } /************* Dual Desert Eagles *************/ void CAkimboDeagles::Spawn() { pev->classname = MAKE_STRING( "weapon_akimbodeagles" ); m_iBulletType = BULLET_50AE; m_iId = WEAPON_AKIMBODEAGLES; m_iDefaultAmmo = AMMO_GIVE_DEAGLE * 2; m_iClipSize = CLIP_DEAGLE * 2; m_fAccuracy = 0.078; m_fRateOfFire = 0.308; CAkimboWeapon::Spawn(); } void CAkimboDeagles::Precache() { PRECACHE_MODEL("models/v_akimbo_deagles.mdl"); PRECACHE_MODEL("models/p_akimbo_deagles.mdl"); PRECACHE_MODEL("models/shells/shell_50AE_lo.mdl"); PRECACHE_MODEL("models/shells/shell_50AE_hi.mdl"); PRECACHE_MODEL("models/shells/mag_deagle.mdl"); PRECACHE_SOUND("weapons/deagle_fire.wav"); PRECACHE_SOUND("weapons/deagle_fire_empty.wav"); m_usFire1 = PRECACHE_EVENT(1, "events/akimbodeagles.sc" ); } int CAkimboDeagles::GetItemInfo( ItemInfo *p ) { p->pszAmmo1 = ".50 AE"; p->iMaxAmmo1 = AMMO_MAX_DEAGLE; p->pszAmmo2 = NULL; p->iMaxAmmo2 = -1; p->iMaxClip = CLIP_DEAGLE * 2; p->iId = m_iId = WEAPON_AKIMBODEAGLES; p->iWeight = WEIGHT_DEAGLE * 2; return CAkimboWeapon::GetItemInfo( p ); } float CAkimboDeagles::flGetTiltedDamage() { return RANDOM_FLOAT( 50, 60 ); } const char *CAkimboDeagles::szGetDeathNoticeString() { return RANDOM_LONG(0,1) ? DEATH_AKIMBODEAGLES_1 : DEATH_AKIMBODEAGLES_2; } BOOL CAkimboDeagles::Deploy() { if(!DefaultDeploy("models/v_akimbo_deagles.mdl","models/p_akimbo_deagles.mdl",AKIMBO_DRAW,"akimbo")) return FALSE; return CWasteWeapon::Deploy(); } /************* Dual Sawed Off's *************/ void CAkimboSawedOffs::Spawn() { pev->classname = MAKE_STRING( "weapon_akimbosawedoffs" ); m_iBulletType = BULLET_20GAUGE; m_iId = WEAPON_AKIMBOSAWEDOFFS; m_iDefaultAmmo = AMMO_GIVE_BUCKSHOT; m_iClipSize = CLIP_SAWEDOFF * 2; CAkimboWeapon::Spawn(); } void CAkimboSawedOffs::Precache() { PRECACHE_MODEL("models/v_akimbo_sawedoffs.mdl"); PRECACHE_MODEL("models/p_akimbo_sawedoffs.mdl"); PRECACHE_MODEL("models/shells/shell_buckshot_lo.mdl"); PRECACHE_MODEL("models/shells/shell_buckshot_hi.mdl"); PRECACHE_SOUND("weapons/sawedoff_fire1.wav"); PRECACHE_SOUND("weapons/sawedoff_fire2.wav"); PRECACHE_SOUND("weapons/sawedoff_fire_empty.wav"); m_usFire1 = PRECACHE_EVENT(1, "events/akimbosawedoffs.sc" ); } int CAkimboSawedOffs::GetItemInfo( ItemInfo *p ) { p->pszAmmo1 = "Buckshot"; p->iMaxAmmo1 = AMMO_MAX_BUCKSHOT; p->pszAmmo2 = NULL; p->iMaxAmmo2 = -1; p->iMaxClip = CLIP_SAWEDOFF * 2; p->iId = m_iId = WEAPON_AKIMBOSAWEDOFFS; p->iWeight = WEIGHT_SAWEDOFF * 2; return CAkimboWeapon::GetItemInfo( p ); } float CAkimboSawedOffs::flGetTiltedDamage() { return RANDOM_FLOAT( 16, 19 ); } const char *CAkimboSawedOffs::szGetDeathNoticeString() { return RANDOM_LONG(0,1) ? DEATH_SAWEDOFF_1 : DEATH_SAWEDOFF_2; } void CAkimboSawedOffs::ItemPostFrame() { // We call CWasteWeapon instead of CAkimboWeapon because // akimboweapon has special reload code for magazine based weapons. CWasteWeapon::ItemPostFrame(); if( !( m_pPlayer->pev->button & IN_ATTACK ) ) m_iAllowFire = TRUE; } void CAkimboSawedOffs::FireSawedOffs( int iShellsFired ) { if( !m_iAllowFire ) return; // don't fire underwater if (m_pPlayer->pev->waterlevel == 3) { PlayEmptySound( ); m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; return; } if( !m_iClip ) { // SendWeaponAnim( SAWED_SHOOT_EMPTY, UseDecrement() ? 1 : 0 ); PlayEmptySound(); m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.3f; return; } m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; m_iClip -= iShellsFired; // OMG kickback! #ifndef CLIENT_DLL float flZVel = m_pPlayer->pev->velocity.z; float kickback = 175 * iShellsFired; m_pPlayer->pev->velocity = m_pPlayer->pev->velocity - gpGlobals->v_forward * kickback; // clamp the z velocity so people // cant sawnoff jump with the gun :) m_pPlayer->pev->velocity.z = flZVel; #endif m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; Vector vecSrc = m_pPlayer->GetGunPosition(); Vector vecAiming = gpGlobals->v_forward; Vector vecDir; int shotCount = 7 * iShellsFired; float spread; if( iShellsFired == 1 ) spread = 0.15; else spread = 0.25 * (iShellsFired / 2); Vector vecSpread = Vector( spread, spread, spread ); vecDir = m_pPlayer->FireBulletsPlayer( this, shotCount, vecSrc, vecAiming, vecSpread, 1280, m_iBulletType, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); int flags; #if defined( CLIENT_WEAPONS ) flags = FEV_NOTHOST; #else flags = 0; #endif PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usFire1, 0.0f, (float*)&g_vecZero, (float*)&g_vecZero, spread, spread, m_iCurrentHand, 0, (iShellsFired > 1) ? 1 : 0, // True if both sawed offs were fired at once 0 ); m_iAllowFire = FALSE; ( m_iCurrentHand == AH_LEFT ) ? m_iCurrentHand = AH_RIGHT : m_iCurrentHand = AH_LEFT; } void CAkimboSawedOffs::PrimaryAttack() { FireSawedOffs( 1 ); } void CAkimboSawedOffs::SecondaryAttack() { FireSawedOffs( m_iClip ); } void CAkimboSawedOffs::Reload() { if(m_flNextPrimaryAttack > 0.0 || m_flNextSecondaryAttack > 0.0) return; int iResult; // See if we need to reload if(m_iClip == m_iClipSize) return; // player "reload" animation m_pPlayer->SetAnimation( PLAYER_RELOAD ); iResult = DefaultReload( m_iClipSize, AKIMBOSS_RELOAD, 3.0f ); if(iResult) { // m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.6f; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_FLOAT ( 10, 15 ); } } BOOL CAkimboSawedOffs::Deploy() { if(!DefaultDeploy("models/v_akimbo_sawedoffs.mdl","models/p_akimbo_sawedoffs.mdl",AKIMBOSS_DRAW,"akimbo")) return FALSE; return CWasteWeapon::Deploy(); }