diff --git a/server/entities/monster_snark.cpp b/server/entities/monster_snark.cpp new file mode 100644 index 000000000..286defd59 --- /dev/null +++ b/server/entities/monster_snark.cpp @@ -0,0 +1,364 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* 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 +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#include "monster_snark.h" +#include "squeakgrenade.h" + +#define SQUEEK_DETONATE_DELAY 15.0 + +LINK_ENTITY_TO_CLASS(monster_snark, CSqueakGrenade); + +BEGIN_DATADESC(CSqueakGrenade) + DEFINE_FIELD(m_flDie, FIELD_TIME), + DEFINE_FIELD(m_vecTarget, FIELD_VECTOR), + DEFINE_FIELD(m_flNextHunt, FIELD_TIME), + DEFINE_FIELD(m_flNextHit, FIELD_TIME), + DEFINE_FIELD(m_posPrev, FIELD_POSITION_VECTOR), + DEFINE_FIELD(m_hOwner, FIELD_EHANDLE), + DEFINE_FUNCTION(SuperBounceTouch), + DEFINE_FUNCTION(HuntThink), +END_DATADESC() + +float CSqueakGrenade::m_flNextBounceSoundTime = 0; + +int CSqueakGrenade::Classify(void) +{ + if (m_iClass) return m_iClass; + + if (m_iMyClass != 0) + return m_iMyClass; // protect against recursion + + if (m_hEnemy != NULL) + { + m_iMyClass = CLASS_INSECT; // no one cares about it + switch (m_hEnemy->Classify()) + { + case CLASS_PLAYER: + case CLASS_HUMAN_PASSIVE: + case CLASS_HUMAN_MILITARY: + m_iMyClass = 0; + return CLASS_ALIEN_MILITARY; // barney's get mad, grunts get mad at it + } + m_iMyClass = 0; + } + + return CLASS_ALIEN_BIOWEAPON; +} + +void CSqueakGrenade::Spawn(void) +{ + Precache(); + // motor + pev->movetype = MOVETYPE_BOUNCE; + pev->solid = SOLID_BBOX; + + SET_MODEL(ENT(pev), "models/w_squeak.mdl"); + UTIL_SetSize(pev, Vector(-4, -4, 0), Vector(4, 4, 8)); + + SetTouch(&CSqueakGrenade::SuperBounceTouch); + SetThink(&CSqueakGrenade::HuntThink); + pev->nextthink = gpGlobals->time + 0.1; + m_flNextHunt = gpGlobals->time + 1E6; + + pev->flags |= FL_MONSTER; + pev->takedamage = DAMAGE_AIM; + pev->health = gSkillData.snarkHealth; + pev->gravity = 0.5; + pev->friction = 0.5; + + pev->dmg = gSkillData.snarkDmgPop; + + m_flDie = gpGlobals->time + SQUEEK_DETONATE_DELAY; + + m_flFieldOfView = 0; // 180 degrees + + if (pev->owner) + m_hOwner = Instance(pev->owner); + + m_flNextBounceSoundTime = gpGlobals->time;// reset each time a snark is spawned. + + pev->sequence = WSQUEAK_RUN; + ResetSequenceInfo(); +} + +void CSqueakGrenade::Precache(void) +{ + PRECACHE_MODEL("models/w_squeak.mdl"); + PRECACHE_SOUND("squeek/sqk_blast1.wav"); + PRECACHE_SOUND("common/bodysplat.wav"); + PRECACHE_SOUND("squeek/sqk_die1.wav"); + PRECACHE_SOUND("squeek/sqk_hunt1.wav"); + PRECACHE_SOUND("squeek/sqk_hunt2.wav"); + PRECACHE_SOUND("squeek/sqk_hunt3.wav"); + PRECACHE_SOUND("squeek/sqk_deploy1.wav"); +} + +void CSqueakGrenade::Killed(entvars_t *pevAttacker, int iGib) +{ + pev->model = iStringNull;// make invisible + SetThink(&CBaseEntity::SUB_Remove); + SetTouch(NULL); + pev->nextthink = gpGlobals->time + 0.1; + + // since squeak grenades never leave a body behind, clear out their takedamage now. + // Squeaks do a bit of radius damage when they pop, and that radius damage will + // continue to call this function unless we acknowledge the Squeak's death now. (sjb) + pev->takedamage = DAMAGE_NO; + + // play squeek blast + EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "squeek/sqk_blast1.wav", 1, 0.5, 0, PITCH_NORM); + + CSoundEnt::InsertSound(bits_SOUND_COMBAT, GetAbsOrigin(), SMALL_EXPLOSION_VOLUME, 3.0); + + UTIL_BloodDrips(GetAbsOrigin(), g_vecZero, BloodColor(), 80); + + if (m_hOwner != NULL) + RadiusDamage(pev, m_hOwner->pev, pev->dmg, CLASS_NONE, DMG_BLAST); + else + RadiusDamage(pev, pev, pev->dmg, CLASS_NONE, DMG_BLAST); + + // reset owner so death message happens + if (m_hOwner != NULL) + pev->owner = m_hOwner->edict(); + + CBaseMonster::Killed(pevAttacker, GIB_ALWAYS); +} + +void CSqueakGrenade::GibMonster(void) +{ + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200); +} + +void CSqueakGrenade::HuntThink(void) +{ + // ALERT( at_console, "think\n" ); + + if (!IsInWorld()) + { + SetTouch(NULL); + UTIL_Remove(this); + return; + } + + StudioFrameAdvance(); + pev->nextthink = gpGlobals->time + 0.1; + + // explode when ready + if (gpGlobals->time >= m_flDie) + { + g_vecAttackDir = GetAbsVelocity().Normalize(); + pev->health = -1; + Killed(pev, 0); + return; + } + + // float + if (pev->waterlevel != 0) + { + if (pev->movetype == MOVETYPE_BOUNCE) + { + pev->movetype = MOVETYPE_FLY; + } + Vector vecVelocity = GetAbsVelocity() * 0.9f; + vecVelocity.z += 8.0f; + SetAbsVelocity(vecVelocity); + } + else if (pev->movetype == MOVETYPE_FLY) + { + pev->movetype = MOVETYPE_BOUNCE; + } + + // return if not time to hunt + if (m_flNextHunt > gpGlobals->time) + return; + + m_flNextHunt = gpGlobals->time + 2.0; + + CBaseEntity *pOther = NULL; + Vector vecDir; + TraceResult tr; + + Vector vecFlat = GetAbsVelocity(); + vecFlat.z = 0; + vecFlat = vecFlat.Normalize(); + + UTIL_MakeVectors(GetAbsAngles()); + + if (m_hEnemy == NULL || !m_hEnemy->IsAlive()) + { + // find target, bounce a bit towards it. + Look(512); + m_hEnemy = BestVisibleEnemy(); + } + + // squeek if it's about time blow up + if ((m_flDie - gpGlobals->time <= 0.5) && (m_flDie - gpGlobals->time >= 0.3)) + { + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_die1.wav", 1, ATTN_NORM, 0, 100 + RANDOM_LONG(0, 0x3F)); + CSoundEnt::InsertSound(bits_SOUND_COMBAT, GetAbsOrigin(), 256, 0.25); + } + + // higher pitch as squeeker gets closer to detonation time + float flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY); + if (flpitch < 80) + flpitch = 80; + + if (m_hEnemy != NULL) + { + if (FVisible(m_hEnemy)) + { + vecDir = m_hEnemy->EyePosition() - GetAbsOrigin(); + m_vecTarget = vecDir.Normalize(); + } + + float flVel = GetAbsVelocity().Length(); + float flAdj = 50.0 / (flVel + 10.0); + + if (flAdj > 1.2) + flAdj = 1.2; + + // ALERT( at_console, "think : enemy\n"); + + // ALERT( at_console, "%.0f %.2f %.2f %.2f\n", flVel, m_vecTarget.x, m_vecTarget.y, m_vecTarget.z ); + Vector vecVelocity = GetAbsVelocity(); + + SetAbsVelocity(vecVelocity * flAdj + m_vecTarget * 300); + } + + if (pev->flags & FL_ONGROUND) + { + SetLocalAvelocity(g_vecZero); + } + else + { + if (GetLocalAvelocity() == g_vecZero) + { + Vector vecAvelocity; + vecAvelocity.x = RANDOM_FLOAT(-100, 100); + vecAvelocity.z = RANDOM_FLOAT(-100, 100); + vecAvelocity.y = 0; + SetLocalAvelocity(vecAvelocity); + } + } + + if ((GetAbsOrigin() - m_posPrev).Length() < 1.0) + { + Vector vecVelocity; + vecVelocity.x = RANDOM_FLOAT(-100, 100); + vecVelocity.y = RANDOM_FLOAT(-100, 100); + vecVelocity.z = 0; + SetAbsVelocity(vecVelocity); + } + m_posPrev = GetAbsOrigin(); + + Vector vecAngles = UTIL_VecToAngles(GetAbsVelocity()); + vecAngles.z = 0; + vecAngles.x = 0; + SetAbsAngles(vecAngles); +} + +void CSqueakGrenade::SuperBounceTouch(CBaseEntity *pOther) +{ + float flpitch; + + TraceResult tr = UTIL_GetGlobalTrace(); + + // don't hit the guy that launched this grenade + if (pev->owner && pOther->edict() == pev->owner) + return; + + // at least until we've bounced once + pev->owner = NULL; + + Vector vecAngles = GetAbsAngles(); + + vecAngles.x = 0; + vecAngles.z = 0; + + SetAbsAngles(vecAngles); + + // avoid bouncing too much + if (m_flNextHit > gpGlobals->time) + return; + + // higher pitch as squeeker gets closer to detonation time + flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY); + + if (pOther->pev->takedamage && m_flNextAttack < gpGlobals->time) + { + // attack! + + // make sure it's me who has touched them + if (tr.pHit == pOther->edict()) + { + // and it's not another squeakgrenade + if (tr.pHit->v.modelindex != pev->modelindex) + { + // ALERT( at_console, "hit enemy\n"); + ClearMultiDamage(); + pOther->TraceAttack(pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH); + if (m_hOwner != NULL) + ApplyMultiDamage(pev, m_hOwner->pev); + else + ApplyMultiDamage(pev, pev); + + pev->dmg += gSkillData.snarkDmgPop; // add more explosion damage + // m_flDie += 2.0; // add more life + + // make bite sound + EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "squeek/sqk_deploy1.wav", 1.0, ATTN_NORM, 0, (int)flpitch); + m_flNextAttack = gpGlobals->time + 0.5; + } + } + else + { + // ALERT( at_console, "been hit\n"); + } + } + + m_flNextHit = gpGlobals->time + 0.1; + m_flNextHunt = gpGlobals->time; + + if (g_pGameRules->IsMultiplayer()) + { + // in multiplayer, we limit how often snarks can make their bounce sounds to prevent overflows. + if (gpGlobals->time < m_flNextBounceSoundTime) + { + // too soon! + return; + } + } + + if (!(pev->flags & FL_ONGROUND)) + { + // play bounce sound + float flRndSound = RANDOM_FLOAT(0, 1); + + if (flRndSound <= 0.33) + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt1.wav", 1, ATTN_NORM, 0, (int)flpitch); + else if (flRndSound <= 0.66) + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, (int)flpitch); + else + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, (int)flpitch); + CSoundEnt::InsertSound(bits_SOUND_COMBAT, GetAbsOrigin(), 256, 0.25); + } + else + { + // skittering sound + CSoundEnt::InsertSound(bits_SOUND_COMBAT, GetAbsOrigin(), 100, 0.1); + } + + m_flNextBounceSoundTime = gpGlobals->time + 0.5;// half second. +} \ No newline at end of file diff --git a/server/entities/monster_snark.h b/server/entities/monster_snark.h new file mode 100644 index 000000000..eb30d2177 --- /dev/null +++ b/server/entities/monster_snark.h @@ -0,0 +1,63 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* 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 +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#pragma once + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "soundent.h" +#include "gamerules.h" +#include "ggrenade.h" + +class CSqueakGrenade : public CGrenade +{ + DECLARE_CLASS(CSqueakGrenade, CGrenade); + + void Spawn(void); + void Precache(void); + int Classify(void); + void SuperBounceTouch(CBaseEntity *pOther); + void HuntThink(void); + int BloodColor(void) { return BLOOD_COLOR_YELLOW; } + void Killed(entvars_t *pevAttacker, int iGib); + void GibMonster(void); + + DECLARE_DATADESC(); + + static float m_flNextBounceSoundTime; + + float m_flDie; + Vector m_vecTarget; + float m_flNextHunt; + float m_flNextHit; + Vector m_posPrev; + EHANDLE m_hOwner; + int m_iMyClass; +}; + +enum squeak_e +{ + SQUEAK_IDLE1 = 0, + SQUEAK_FIDGETFIT, + SQUEAK_FIDGETNIP, + SQUEAK_DOWN, + SQUEAK_UP, + SQUEAK_THROW +}; \ No newline at end of file diff --git a/server/weapons/squeakgrenade.cpp b/server/weapons/squeakgrenade.cpp index cc3baef64..cc84d2d6f 100644 --- a/server/weapons/squeakgrenade.cpp +++ b/server/weapons/squeakgrenade.cpp @@ -13,423 +13,8 @@ * ****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "soundent.h" -#include "gamerules.h" -#include "ggrenade.h" - -#define SQUEEK_DETONATE_DELAY 15.0 - -enum w_squeak_e -{ - WSQUEAK_IDLE1 = 0, - WSQUEAK_FIDGET, - WSQUEAK_JUMP, - WSQUEAK_RUN, -}; - -enum squeak_e -{ - SQUEAK_IDLE1 = 0, - SQUEAK_FIDGETFIT, - SQUEAK_FIDGETNIP, - SQUEAK_DOWN, - SQUEAK_UP, - SQUEAK_THROW -}; - -class CSqueakGrenade : public CGrenade -{ - DECLARE_CLASS( CSqueakGrenade, CGrenade ); - - void Spawn( void ); - void Precache( void ); - int Classify( void ); - void SuperBounceTouch( CBaseEntity *pOther ); - void HuntThink( void ); - int BloodColor( void ) { return BLOOD_COLOR_YELLOW; } - void Killed( entvars_t *pevAttacker, int iGib ); - void GibMonster( void ); - - DECLARE_DATADESC(); - - static float m_flNextBounceSoundTime; - - float m_flDie; - Vector m_vecTarget; - float m_flNextHunt; - float m_flNextHit; - Vector m_posPrev; - EHANDLE m_hOwner; - int m_iMyClass; -}; - -float CSqueakGrenade::m_flNextBounceSoundTime = 0; - -LINK_ENTITY_TO_CLASS( monster_snark, CSqueakGrenade ); - -BEGIN_DATADESC( CSqueakGrenade ) - DEFINE_FIELD( m_flDie, FIELD_TIME ), - DEFINE_FIELD( m_vecTarget, FIELD_VECTOR ), - DEFINE_FIELD( m_flNextHunt, FIELD_TIME ), - DEFINE_FIELD( m_flNextHit, FIELD_TIME ), - DEFINE_FIELD( m_posPrev, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( m_hOwner, FIELD_EHANDLE ), - DEFINE_FUNCTION( SuperBounceTouch ), - DEFINE_FUNCTION( HuntThink ), -END_DATADESC() - -int CSqueakGrenade :: Classify( void ) -{ - if (m_iClass) return m_iClass; - - if (m_iMyClass != 0) - return m_iMyClass; // protect against recursion - - if (m_hEnemy != NULL) - { - m_iMyClass = CLASS_INSECT; // no one cares about it - switch( m_hEnemy->Classify( ) ) - { - case CLASS_PLAYER: - case CLASS_HUMAN_PASSIVE: - case CLASS_HUMAN_MILITARY: - m_iMyClass = 0; - return CLASS_ALIEN_MILITARY; // barney's get mad, grunts get mad at it - } - m_iMyClass = 0; - } - - return CLASS_ALIEN_BIOWEAPON; -} - -void CSqueakGrenade :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_BOUNCE; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/w_squeak.mdl"); - UTIL_SetSize(pev, Vector( -4, -4, 0), Vector(4, 4, 8)); - - SetTouch( &CSqueakGrenade::SuperBounceTouch ); - SetThink( &CSqueakGrenade::HuntThink ); - pev->nextthink = gpGlobals->time + 0.1; - m_flNextHunt = gpGlobals->time + 1E6; - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_AIM; - pev->health = gSkillData.snarkHealth; - pev->gravity = 0.5; - pev->friction = 0.5; - - pev->dmg = gSkillData.snarkDmgPop; - - m_flDie = gpGlobals->time + SQUEEK_DETONATE_DELAY; - - m_flFieldOfView = 0; // 180 degrees - - if ( pev->owner ) - m_hOwner = Instance( pev->owner ); - - m_flNextBounceSoundTime = gpGlobals->time;// reset each time a snark is spawned. - - pev->sequence = WSQUEAK_RUN; - ResetSequenceInfo( ); -} - -void CSqueakGrenade::Precache( void ) -{ - PRECACHE_MODEL("models/w_squeak.mdl"); - PRECACHE_SOUND("squeek/sqk_blast1.wav"); - PRECACHE_SOUND("common/bodysplat.wav"); - PRECACHE_SOUND("squeek/sqk_die1.wav"); - PRECACHE_SOUND("squeek/sqk_hunt1.wav"); - PRECACHE_SOUND("squeek/sqk_hunt2.wav"); - PRECACHE_SOUND("squeek/sqk_hunt3.wav"); - PRECACHE_SOUND("squeek/sqk_deploy1.wav"); -} - -void CSqueakGrenade :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->model = iStringNull;// make invisible - SetThink( &CBaseEntity::SUB_Remove ); - SetTouch( NULL ); - pev->nextthink = gpGlobals->time + 0.1; - - // since squeak grenades never leave a body behind, clear out their takedamage now. - // Squeaks do a bit of radius damage when they pop, and that radius damage will - // continue to call this function unless we acknowledge the Squeak's death now. (sjb) - pev->takedamage = DAMAGE_NO; - - // play squeek blast - EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "squeek/sqk_blast1.wav", 1, 0.5, 0, PITCH_NORM); - - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, GetAbsOrigin(), SMALL_EXPLOSION_VOLUME, 3.0 ); - - UTIL_BloodDrips( GetAbsOrigin(), g_vecZero, BloodColor(), 80 ); - - if (m_hOwner != NULL) - RadiusDamage ( pev, m_hOwner->pev, pev->dmg, CLASS_NONE, DMG_BLAST ); - else - RadiusDamage ( pev, pev, pev->dmg, CLASS_NONE, DMG_BLAST ); - - // reset owner so death message happens - if (m_hOwner != NULL) - pev->owner = m_hOwner->edict(); - - CBaseMonster :: Killed( pevAttacker, GIB_ALWAYS ); -} - -void CSqueakGrenade :: GibMonster( void ) -{ - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200); -} - -void CSqueakGrenade::HuntThink( void ) -{ - // ALERT( at_console, "think\n" ); - - if (!IsInWorld()) - { - SetTouch( NULL ); - UTIL_Remove( this ); - return; - } - - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - // explode when ready - if (gpGlobals->time >= m_flDie) - { - g_vecAttackDir = GetAbsVelocity().Normalize( ); - pev->health = -1; - Killed( pev, 0 ); - return; - } - - // float - if (pev->waterlevel != 0) - { - if (pev->movetype == MOVETYPE_BOUNCE) - { - pev->movetype = MOVETYPE_FLY; - } - Vector vecVelocity = GetAbsVelocity() * 0.9f; - vecVelocity.z += 8.0f; - SetAbsVelocity( vecVelocity ); - } - else if (pev->movetype == MOVETYPE_FLY) - { - pev->movetype = MOVETYPE_BOUNCE; - } - - // return if not time to hunt - if (m_flNextHunt > gpGlobals->time) - return; - - m_flNextHunt = gpGlobals->time + 2.0; - - CBaseEntity *pOther = NULL; - Vector vecDir; - TraceResult tr; - - Vector vecFlat = GetAbsVelocity(); - vecFlat.z = 0; - vecFlat = vecFlat.Normalize( ); - - UTIL_MakeVectors( GetAbsAngles() ); - - if (m_hEnemy == NULL || !m_hEnemy->IsAlive()) - { - // find target, bounce a bit towards it. - Look( 512 ); - m_hEnemy = BestVisibleEnemy( ); - } - - // squeek if it's about time blow up - if ((m_flDie - gpGlobals->time <= 0.5) && (m_flDie - gpGlobals->time >= 0.3)) - { - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_die1.wav", 1, ATTN_NORM, 0, 100 + RANDOM_LONG(0,0x3F)); - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, GetAbsOrigin(), 256, 0.25 ); - } - - // higher pitch as squeeker gets closer to detonation time - float flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY); - if (flpitch < 80) - flpitch = 80; - - if (m_hEnemy != NULL) - { - if (FVisible( m_hEnemy )) - { - vecDir = m_hEnemy->EyePosition() - GetAbsOrigin(); - m_vecTarget = vecDir.Normalize( ); - } - - float flVel = GetAbsVelocity().Length(); - float flAdj = 50.0 / (flVel + 10.0); - - if (flAdj > 1.2) - flAdj = 1.2; - - // ALERT( at_console, "think : enemy\n"); - - // ALERT( at_console, "%.0f %.2f %.2f %.2f\n", flVel, m_vecTarget.x, m_vecTarget.y, m_vecTarget.z ); - Vector vecVelocity = GetAbsVelocity(); - - SetAbsVelocity( vecVelocity * flAdj + m_vecTarget * 300 ); - } - - if (pev->flags & FL_ONGROUND) - { - SetLocalAvelocity( g_vecZero ); - } - else - { - if (GetLocalAvelocity() == g_vecZero) - { - Vector vecAvelocity; - vecAvelocity.x = RANDOM_FLOAT( -100, 100 ); - vecAvelocity.z = RANDOM_FLOAT( -100, 100 ); - vecAvelocity.y = 0; - SetLocalAvelocity( vecAvelocity ); - } - } - - if ((GetAbsOrigin() - m_posPrev).Length() < 1.0) - { - Vector vecVelocity; - vecVelocity.x = RANDOM_FLOAT( -100, 100 ); - vecVelocity.y = RANDOM_FLOAT( -100, 100 ); - vecVelocity.z = 0; - SetAbsVelocity( vecVelocity ); - } - m_posPrev = GetAbsOrigin(); - - Vector vecAngles = UTIL_VecToAngles( GetAbsVelocity() ); - vecAngles.z = 0; - vecAngles.x = 0; - SetAbsAngles( vecAngles ); -} - -void CSqueakGrenade::SuperBounceTouch( CBaseEntity *pOther ) -{ - float flpitch; - - TraceResult tr = UTIL_GetGlobalTrace( ); - - // don't hit the guy that launched this grenade - if ( pev->owner && pOther->edict() == pev->owner ) - return; - - // at least until we've bounced once - pev->owner = NULL; - - Vector vecAngles = GetAbsAngles(); - - vecAngles.x = 0; - vecAngles.z = 0; - - SetAbsAngles( vecAngles ); - - // avoid bouncing too much - if (m_flNextHit > gpGlobals->time) - return; - - // higher pitch as squeeker gets closer to detonation time - flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY); - - if ( pOther->pev->takedamage && m_flNextAttack < gpGlobals->time ) - { - // attack! - - // make sure it's me who has touched them - if (tr.pHit == pOther->edict()) - { - // and it's not another squeakgrenade - if (tr.pHit->v.modelindex != pev->modelindex) - { - // ALERT( at_console, "hit enemy\n"); - ClearMultiDamage( ); - pOther->TraceAttack(pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH ); - if (m_hOwner != NULL) - ApplyMultiDamage( pev, m_hOwner->pev ); - else - ApplyMultiDamage( pev, pev ); - - pev->dmg += gSkillData.snarkDmgPop; // add more explosion damage - // m_flDie += 2.0; // add more life - - // make bite sound - EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "squeek/sqk_deploy1.wav", 1.0, ATTN_NORM, 0, (int)flpitch); - m_flNextAttack = gpGlobals->time + 0.5; - } - } - else - { - // ALERT( at_console, "been hit\n"); - } - } - - m_flNextHit = gpGlobals->time + 0.1; - m_flNextHunt = gpGlobals->time; - - if ( g_pGameRules->IsMultiplayer() ) - { - // in multiplayer, we limit how often snarks can make their bounce sounds to prevent overflows. - if ( gpGlobals->time < m_flNextBounceSoundTime ) - { - // too soon! - return; - } - } - - if (!(pev->flags & FL_ONGROUND)) - { - // play bounce sound - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.33 ) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt1.wav", 1, ATTN_NORM, 0, (int)flpitch); - else if (flRndSound <= 0.66) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, (int)flpitch); - else - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, (int)flpitch); - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, GetAbsOrigin(), 256, 0.25 ); - } - else - { - // skittering sound - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, GetAbsOrigin(), 100, 0.1 ); - } - - m_flNextBounceSoundTime = gpGlobals->time + 0.5;// half second. -} - -class CSqueak : public CBasePlayerWeapon -{ - DECLARE_CLASS( CSqueak, CBasePlayerWeapon ); -public: - void Spawn( void ); - void Precache( void ); - int iItemSlot( void ) { return 5; } - int GetItemInfo(ItemInfo *p); - - void PrimaryAttack( void ); - BOOL Deploy( void ); - void Holster( void ); - void WeaponIdle( void ); - int m_fJustThrown; -}; +#include "squeakgrenade.h" +#include "monster_snark.h" LINK_ENTITY_TO_CLASS( weapon_snark, CSqueak ); diff --git a/server/weapons/squeakgrenade.h b/server/weapons/squeakgrenade.h new file mode 100644 index 000000000..ab21a4de5 --- /dev/null +++ b/server/weapons/squeakgrenade.h @@ -0,0 +1,50 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* 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 +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#pragma once + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "gamerules.h" +#include "ggrenade.h" + +class CSqueak : public CBasePlayerWeapon +{ + DECLARE_CLASS(CSqueak, CBasePlayerWeapon); +public: + void Spawn(void); + void Precache(void); + int iItemSlot(void) { return 5; } + int GetItemInfo(ItemInfo *p); + + void PrimaryAttack(void); + BOOL Deploy(void); + void Holster(void); + void WeaponIdle(void); + int m_fJustThrown; +}; + +enum w_squeak_e +{ + WSQUEAK_IDLE1 = 0, + WSQUEAK_FIDGET, + WSQUEAK_JUMP, + WSQUEAK_RUN, +}; \ No newline at end of file