|
|
|
Editor: YELLOW is original code. RED is new code. In this tutorial you will learn how to make the flashbang like in CStrike. Goto ggrenade.cpp and somewhere in the file create the function CGrenade * CGrenade:: ShootFlash( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ) { CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); pGrenade->Spawn(); UTIL_SetOrigin( pGrenade->pev, vecStart ); pGrenade->pev->velocity = vecVelocity; pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity); pGrenade->pev->owner = ENT(pevOwner); pGrenade->SetTouch( BounceTouch ); // Bounce if touched // Take one second off of the desired detonation time and set the think to PreDetonate. PreDetonate // will insert a DANGER sound into the world sound list and delay detonation for one second so that // the grenade explodes after the exact amount of time specified in the call to ShootTimed(). pGrenade->pev->dmgtime = gpGlobals->time + time; pGrenade->SetThink( FlashThink ); pGrenade->pev->nextthink = gpGlobals->time + 0.1; if (time < 0.1) { pGrenade->pev->nextthink = gpGlobals->time; pGrenade->pev->velocity = Vector( 0, 0, 0 ); } pGrenade->pev->sequence = RANDOM_LONG( 3, 6 ); pGrenade->pev->framerate = 1.0; // Tumble through the air // pGrenade->pev->avelocity.x = -400; pGrenade->pev->gravity = 0.5; pGrenade->pev->friction = 0.8; SET_MODEL(ENT(pGrenade->pev), "models/w_grenade.mdl"); pGrenade->pev->dmg = 0; return pGrenade; } and you also need a new think function so make this void CGrenade :: FlashThink( void ) { if (!IsInWorld()) { UTIL_Remove( this ); return; } StudioFrameAdvance( ); pev->nextthink = gpGlobals->time + 0.1; if (pev->dmgtime - 1 < gpGlobals->time) { CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * (pev->dmgtime - gpGlobals->time), 400, 0.1 ); } if (pev->dmgtime <= gpGlobals->time) { UTIL_MakeVectors( Vector( 0, pev->v_angle.y, 0 ) ); Create("info_flash", pev->origin, pev->angles); UTIL_Remove( this ); } if (pev->waterlevel != 0) { pev->velocity = pev->velocity * 0.5; pev->framerate = 0.2; } } The only thing that is changed from the ShootTimed in the ShootFlash function is that it calls FlashThink as its think. The FlashThink spawns a flash when the time says it can. That will make it so you can shoot the flashbang. Now you just have to say that the function exist, go into weapons.h and insert the lines static CGrenade *ShootFlash( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ); void EXPORT FlashThink( void ); right above static CGrenade *ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ); The next thing to make is the actual flash function. Basing it on the code already in items.cpp will making coding the flash easier. So go into items.cpp and insert the lines class CFlash : public CItem { void Spawn( void ) { Precache( ); CItem::Spawn(); UTIL_SetSize(pev, Vector(-400, -400, 0), Vector(400, 400, 400)); SetThink( Think ); pev->nextthink = gpGlobals->time + 0.1; } void Precache( void ) { } BOOL MyTouch( CBasePlayer *pPlayer ) // was My Touch { UTIL_ScreenFade( pPlayer, Vector(255,255,255), 5.0, 0.5, 255, FFADE_IN ); pev->nextthink = gpGlobals->time + 0.1; return TRUE; } void Think( void ) { UTIL_Remove( this ); } }; LINK_ENTITY_TO_CLASS(info_flash, CFlash); That causes the actual flash and blinding of a person that is in the 400unit radius, to change the radius just change all the 400s in the UTIL_SetSize to whatever radius you want. If you are in the radius you touch it and it does a screen fade for 5 seconds (the number after the Vector(255,255,255) is the duration and the Vector(255,255,255) is the color in RGB take a look at BigGuys tutorial about Screen Fading and Shaking for more inforation on screen fading). It stays in the world for 0.1 seconds then it is removed. Also make sure to include the shake.h in items.cpp.Now go into weapons.cpp goto the W_Precache function and insert the line UTIL_PrecacheOther( "info_flash" ); under the line UTIL_PrecacheOther( "item_longjump" ); to precache the flash entity and it wont give you a BadIndexOfEdict. That is everything to shoot a flashbang and have it explode. Now onto the actual weapon coding! Make a new weapon called flashbang.cpp and insert all this code into that file. /*** * * Flashbang by Gavin * ****/ #include "extdll.h" #include "util.h" #include "cbase.h" #include "monsters.h" #include "weapons.h" #include "nodes.h" #include "player.h" #define FLASHBANG_PRIMARY_VOLUME 450 enum handgrenade_e { FLASHBANG_IDLE = 0, FLASHBANG_FIDGET, FLASHBANG_PINPULL, FLASHBANG_THROW1, // toss FLASHBANG_THROW2, // medium FLASHBANG_THROW3, // hard FLASHBANG_HOLSTER, FLASHBANG_DRAW }; class CFlashBang : public CBasePlayerWeapon { public: void Spawn( void ); void Precache( void ); int iItemSlot( void ) { return 5; } int GetItemInfo(ItemInfo *p); void PrimaryAttack( void ); BOOL Deploy( void ); BOOL CanHolster( void ); void Holster( void ); void WeaponIdle( void ); float m_flStartThrow; float m_flReleaseThrow; }; LINK_ENTITY_TO_CLASS( weapon_flashbang, CFlashBang ); void CFlashBang::Spawn( ) { Precache( ); m_iId = WEAPON_FLASHBANG; SET_MODEL(ENT(pev), "models/w_grenade.mdl"); m_iDefaultAmmo = HANDGRENADE_DEFAULT_GIVE; FallInit();// get ready to fall down. } void CFlashBang::Precache( void ) { PRECACHE_MODEL("models/w_grenade.mdl"); PRECACHE_MODEL("models/v_grenade.mdl"); PRECACHE_MODEL("models/p_grenade.mdl"); } int CFlashBang::GetItemInfo(ItemInfo *p) { p->pszName = STRING(pev->classname); p->pszAmmo1 = "Flashbang"; p->iMaxAmmo1 = HANDGRENADE_MAX_CARRY; p->pszAmmo2 = NULL; p->iMaxAmmo2 = -1; p->iMaxClip = WEAPON_NOCLIP; p->iSlot = 4; p->iPosition = 0; p->iId = m_iId = WEAPON_FLASHBANG; p->iWeight = HANDGRENADE_WEIGHT; p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE; return 1; } BOOL CFlashBang::Deploy( ) { m_flReleaseThrow = -1; return DefaultDeploy( "models/v_grenade.mdl", "models/p_grenade.mdl", FLASHBANG_DRAW, "crowbar" ); } BOOL CFlashBang::CanHolster( void ) { // can only holster hand grenades when not primed! return ( m_flStartThrow == 0 ); } void CFlashBang::Holster( ) { m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) { SendWeaponAnim( FLASHBANG_HOLSTER ); } else { // no more grenades! m_pPlayer->pev->weapons &= ~(1<< WEAPON_FLASHBANG); SetThink( DestroyItem ); pev->nextthink = gpGlobals->time + 0.1; } EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); } void CFlashBang::PrimaryAttack() { if (!m_flStartThrow && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0) { m_flStartThrow = gpGlobals->time; m_flReleaseThrow = 0; SendWeaponAnim( FLASHBANG_PINPULL ); m_flTimeWeaponIdle = gpGlobals->time + 0.5; } } void CFlashBang::WeaponIdle( void ) { if (m_flReleaseThrow == 0) m_flReleaseThrow = gpGlobals->time; if (m_flTimeWeaponIdle > gpGlobals->time) return; if (m_flStartThrow) { Vector angThrow = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle; if (angThrow.x < 0) angThrow.x = -10 + angThrow.x * ((90 - 10) / 90.0); else angThrow.x = -10 + angThrow.x * ((90 + 10) / 90.0); float flVel = (90 - angThrow.x) * 4; if (flVel > 500) flVel = 500; UTIL_MakeVectors( angThrow ); Vector vecSrc = m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16; Vector vecThrow = gpGlobals->v_forward * flVel + m_pPlayer->pev->velocity; // alway explode 3 seconds after the pin was pulled float time = m_flStartThrow - gpGlobals->time + 3.0; if (time < 0) time = 0; CGrenade::ShootFlash( m_pPlayer->pev, vecSrc, vecThrow, time ); if (flVel < 500) { SendWeaponAnim( FLASHBANG_THROW1 ); } else if (flVel < 1000) { SendWeaponAnim( FLASHBANG_THROW2 ); } else { SendWeaponAnim( FLASHBANG_THROW3 ); } // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); m_flStartThrow = 0; m_flNextPrimaryAttack = gpGlobals->time + 0.5; m_flTimeWeaponIdle = gpGlobals->time + 0.5; m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; if ( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { // just threw last grenade // set attack times in the future, and weapon idle in the future so we can see the //whole throw // animation, weapon idle will automatically retire the weapon for us. m_flTimeWeaponIdle = m_flNextSecondaryAttack = m_flNextPrimaryAttack = gpGlobals->time + 0.5;// ensure that the animation can finish playing } return; } else if (m_flReleaseThrow > 0) { // we've finished the throw, restart. m_flStartThrow = 0; if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) { SendWeaponAnim( FLASHBANG_DRAW ); } else { RetireWeapon(); return; } m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); m_flReleaseThrow = -1; return; } if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) { int iAnim; float flRand = RANDOM_FLOAT(0, 1); if (flRand <= 0.75) { iAnim = FLASHBANG_IDLE; m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );// how long till we do this again. } else { iAnim = FLASHBANG_FIDGET; m_flTimeWeaponIdle = gpGlobals->time + 75.0 / 30.0; } SendWeaponAnim( iAnim ); } } WOW! That was alot of code! Go into the weapons.h file under #define WEAPON_SNARK 15 add #define WEAPON_FLASHBANG 16 Now just goto weapons.cpp the W_Precache function and under the info_flash we precached insert the line UTIL_PrecacheOtherWeapon( "weapon_flashbang" ); Now thats it! Just start up a new game give yourself the weapon_flashbang and have fun =).
Any questions or suggestions should be sent to me:
british@epix.net