Add monster_shocktrooper.
This commit is contained in:
@@ -39,9 +39,13 @@ OBJ = \
|
||||
otis.o \
|
||||
pitdrone.o \
|
||||
scientist.o \
|
||||
shock.o \
|
||||
shockroach.o \
|
||||
skill.o \
|
||||
sound.o \
|
||||
sporegrenade.o \
|
||||
squeakgrenade.o \
|
||||
strooper.o \
|
||||
subs.o \
|
||||
talkmonster.o \
|
||||
turret.o \
|
||||
|
||||
@@ -347,7 +347,7 @@ public:
|
||||
|
||||
virtual float GetDamageAmount( void ) { return gSkillData.headcrabDmgBite; }
|
||||
virtual int GetVoicePitch( void ) { return 100; }
|
||||
virtual float GetSoundVolue( void ) { return 1.0; }
|
||||
virtual float GetSoundVolume( void ) { return 1.0; }
|
||||
Schedule_t* GetScheduleOfType ( int Type );
|
||||
|
||||
CUSTOM_SCHEDULES;
|
||||
@@ -370,7 +370,7 @@ public:
|
||||
BOOL CheckRangeAttack1 ( float flDot, float flDist );
|
||||
Schedule_t* GetScheduleOfType ( int Type );
|
||||
virtual int GetVoicePitch( void ) { return PITCH_NORM + RANDOM_LONG(40,50); }
|
||||
virtual float GetSoundVolue( void ) { return 0.8; }
|
||||
virtual float GetSoundVolume( void ) { return 0.8; }
|
||||
};
|
||||
|
||||
|
||||
@@ -1416,4 +1416,78 @@ public:
|
||||
static const char *pAttackMissSounds[];
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// Shock Roach
|
||||
//=========================================================
|
||||
class CMShockRoach : public CMHeadCrab
|
||||
{
|
||||
public:
|
||||
void Spawn(void);
|
||||
void Precache(void);
|
||||
void EXPORT LeapTouch(edict_t *pOther);
|
||||
void PainSound(void);
|
||||
void DeathSound(void);
|
||||
void IdleSound(void);
|
||||
void AlertSound(void);
|
||||
void MonsterThink(void);
|
||||
void StartTask(Task_t* pTask);
|
||||
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
|
||||
|
||||
static const char *pIdleSounds[];
|
||||
static const char *pAlertSounds[];
|
||||
static const char *pPainSounds[];
|
||||
static const char *pAttackSounds[];
|
||||
static const char *pDeathSounds[];
|
||||
static const char *pBiteSounds[];
|
||||
|
||||
float m_flBirthTime;
|
||||
BOOL m_fRoachSolid;
|
||||
|
||||
protected:
|
||||
void AttackSound();
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// Shock Trooper
|
||||
//=========================================================
|
||||
class CMStrooper : public CMHGrunt
|
||||
{
|
||||
public:
|
||||
void Spawn(void);
|
||||
void MonsterThink();
|
||||
void Precache(void);
|
||||
int Classify(void);
|
||||
BOOL CheckRangeAttack1(float flDot, float flDist);
|
||||
BOOL CheckRangeAttack2(float flDot, float flDist);
|
||||
void HandleAnimEvent(MonsterEvent_t *pEvent);
|
||||
void SetObjectCollisionBox( void )
|
||||
{
|
||||
pev->absmin = pev->origin + Vector( -24, -24, 0 );
|
||||
pev->absmax = pev->origin + Vector( 24, 24, 72 );
|
||||
}
|
||||
|
||||
void SetActivity(Activity NewActivity);
|
||||
|
||||
void DeathSound(void);
|
||||
void PainSound(void);
|
||||
void IdleSound(void);
|
||||
void GibMonster(void);
|
||||
|
||||
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
|
||||
|
||||
void DropShockRoach(bool gibbed);
|
||||
|
||||
Schedule_t *GetSchedule(void);
|
||||
Schedule_t *GetScheduleOfType(int Type);
|
||||
|
||||
void SpeakSentence();
|
||||
|
||||
BOOL m_fRightClaw;
|
||||
float m_rechargeTime;
|
||||
float m_blinkTime;
|
||||
float m_eyeChangeTime;
|
||||
|
||||
static const char *pGruntSentences[];
|
||||
};
|
||||
|
||||
#endif // BASEMONSTER_H
|
||||
|
||||
@@ -156,6 +156,8 @@ monster_type_t monster_types[]=
|
||||
"monster_male_assassin", FALSE,
|
||||
"monster_otis", FALSE,
|
||||
"monster_pitdrone", FALSE,
|
||||
"monster_shockroach", FALSE,
|
||||
"monster_shocktrooper", FALSE,
|
||||
"info_node", FALSE, // Nodes
|
||||
"info_node_air", FALSE,
|
||||
"", FALSE
|
||||
@@ -620,6 +622,8 @@ bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_i
|
||||
case 19: monsters[monster_index].pMonster = CreateClassPtr((CMMassn *)NULL); break;
|
||||
case 20: monsters[monster_index].pMonster = CreateClassPtr((CMOtis *)NULL); break;
|
||||
case 21: monsters[monster_index].pMonster = CreateClassPtr((CMPitdrone *)NULL); break;
|
||||
case 22: monsters[monster_index].pMonster = CreateClassPtr((CMShockRoach *)NULL); break;
|
||||
case 23: monsters[monster_index].pMonster = CreateClassPtr((CMStrooper *)NULL); break;
|
||||
}
|
||||
|
||||
if (monsters[monster_index].pMonster == NULL)
|
||||
@@ -711,6 +715,7 @@ void check_respawn(void)
|
||||
|
||||
DLL_GLOBAL short g_sModelIndexFireball;// holds the index for the fireball
|
||||
DLL_GLOBAL short g_sModelIndexSmoke;// holds the index for the smoke cloud
|
||||
DLL_GLOBAL short g_sModelIndexTinySpit;// holds the index for the spore grenade explosion
|
||||
DLL_GLOBAL short g_sModelIndexWExplosion;// holds the index for the underwater explosion
|
||||
DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model
|
||||
DLL_GLOBAL short g_sModelIndexBloodDrop;// holds the sprite index for the initial blood
|
||||
@@ -723,6 +728,7 @@ void world_precache(void)
|
||||
{
|
||||
g_sModelIndexFireball = PRECACHE_MODEL ("sprites/zerogxplode.spr");// fireball
|
||||
g_sModelIndexSmoke = PRECACHE_MODEL ("sprites/steam1.spr");// smoke
|
||||
g_sModelIndexTinySpit = PRECACHE_MODEL ("sprites/tinyspit.spr");// spore
|
||||
g_sModelIndexWExplosion = PRECACHE_MODEL ("sprites/WXplo1.spr");// underwater fireball
|
||||
g_sModelIndexBubbles = PRECACHE_MODEL ("sprites/bubble.spr");//bubbles
|
||||
g_sModelIndexBloodSpray = PRECACHE_MODEL ("sprites/bloodspray.spr"); // initial blood
|
||||
@@ -1299,6 +1305,8 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
||||
CMMassn massn;
|
||||
CMOtis otis;
|
||||
CMPitdrone pitdrone;
|
||||
CMShockRoach shockroach;
|
||||
CMStrooper strooper;
|
||||
|
||||
g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" );
|
||||
|
||||
@@ -1338,6 +1346,8 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
||||
case 19: massn.Precache(); break;
|
||||
case 20: otis.Precache(); break;
|
||||
case 21: pitdrone.Precache(); break;
|
||||
case 22: shockroach.Precache(); break;
|
||||
case 23: strooper.Precache(); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
#define SF_ENVEXPLOSION_NODECAL ( 1 << 4 ) // don't make a scorch mark
|
||||
#define SF_ENVEXPLOSION_NOSPARKS ( 1 << 5 ) // don't make a scorch mark
|
||||
|
||||
extern DLL_GLOBAL short g_sModelIndexFireball;
|
||||
extern DLL_GLOBAL short g_sModelIndexSmoke;
|
||||
|
||||
extern DLL_GLOBAL short g_sModelIndexFireball;
|
||||
extern DLL_GLOBAL short g_sModelIndexSmoke;
|
||||
extern DLL_GLOBAL short g_sModelIndexTinySpit;
|
||||
|
||||
extern void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, int flags, float delay );
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ void CMHeadCrab :: HandleAnimEvent( MonsterEvent_t *pEvent )
|
||||
|
||||
int iSound = RANDOM_LONG(0,2);
|
||||
if ( iSound != 0 )
|
||||
EMIT_SOUND_DYN( edict(), CHAN_VOICE, pAttackSounds[iSound], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||
EMIT_SOUND_DYN( edict(), CHAN_VOICE, pAttackSounds[iSound], GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||
|
||||
pev->velocity = vecJumpDir;
|
||||
m_flNextAttack = gpGlobals->time + 2;
|
||||
@@ -325,7 +325,7 @@ void CMHeadCrab :: LeapTouch ( edict_t *pOther )
|
||||
// Don't hit if back on ground
|
||||
if ( !FBitSet( pev->flags, FL_ONGROUND ) )
|
||||
{
|
||||
EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pBiteSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||
EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pBiteSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||
|
||||
if (UTIL_IsPlayer(pOther))
|
||||
UTIL_TakeDamage( pOther, pev, pev, GetDamageAmount(), DMG_SLASH );
|
||||
@@ -359,7 +359,7 @@ void CMHeadCrab :: StartTask ( Task_t *pTask )
|
||||
{
|
||||
case TASK_RANGE_ATTACK1:
|
||||
{
|
||||
EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pAttackSounds[0], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||
EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pAttackSounds[0], GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||
m_IdealActivity = ACT_RANGE_ATTACK1;
|
||||
SetTouch ( &CMHeadCrab::LeapTouch );
|
||||
break;
|
||||
@@ -415,7 +415,7 @@ int CMHeadCrab :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, f
|
||||
#define CRAB_ATTN_IDLE (float)1.5
|
||||
void CMHeadCrab :: IdleSound ( void )
|
||||
{
|
||||
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
@@ -423,7 +423,7 @@ void CMHeadCrab :: IdleSound ( void )
|
||||
//=========================================================
|
||||
void CMHeadCrab :: AlertSound ( void )
|
||||
{
|
||||
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAlertSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAlertSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
@@ -431,7 +431,7 @@ void CMHeadCrab :: AlertSound ( void )
|
||||
//=========================================================
|
||||
void CMHeadCrab :: PainSound ( void )
|
||||
{
|
||||
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
@@ -439,7 +439,7 @@ void CMHeadCrab :: PainSound ( void )
|
||||
//=========================================================
|
||||
void CMHeadCrab :: DeathSound ( void )
|
||||
{
|
||||
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||
}
|
||||
|
||||
Schedule_t* CMHeadCrab :: GetScheduleOfType ( int Type )
|
||||
|
||||
233
src/dlls/shock.cpp
Normal file
233
src/dlls/shock.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
// HUGE thanks to DrBeef for his hlsdk-xash3d-opfor repository!
|
||||
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2001, 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.
|
||||
*
|
||||
* This source code contains proprietary and confidential information of
|
||||
* Valve LLC and its suppliers. Access to this code is restricted to
|
||||
* persons who have executed a written SDK license with Valve. Any access,
|
||||
* use or distribution of this code by or to any unlicensed person is illegal.
|
||||
*
|
||||
****/
|
||||
//=========================================================
|
||||
// shock - projectile shot from shockrifles.
|
||||
//=========================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "monsters.h"
|
||||
#include "schedule.h"
|
||||
#include "effects.h"
|
||||
#include "decals.h"
|
||||
#include "weapons.h"
|
||||
#include "customentity.h"
|
||||
#include "shock.h"
|
||||
|
||||
|
||||
void CMShock::Spawn()
|
||||
{
|
||||
Precache();
|
||||
|
||||
pev->movetype = MOVETYPE_FLY;
|
||||
pev->solid = SOLID_BBOX;
|
||||
pev->classname = MAKE_STRING("shock_beam");
|
||||
SET_MODEL(ENT(pev), "models/shock_effect.mdl");
|
||||
UTIL_SetOrigin(pev, pev->origin);
|
||||
pev->dmg = gSkillData.monDmgShockroach;
|
||||
UTIL_SetSize(pev, Vector(-4, -4, -4), Vector(4, 4, 4));
|
||||
|
||||
CreateEffects();
|
||||
SetThink( &CMShock::FlyThink );
|
||||
pev->nextthink = gpGlobals->time;
|
||||
}
|
||||
|
||||
void CMShock::Precache()
|
||||
{
|
||||
PRECACHE_MODEL("sprites/flare3.spr");
|
||||
PRECACHE_MODEL("sprites/lgtning.spr");
|
||||
PRECACHE_MODEL("models/shock_effect.mdl");
|
||||
PRECACHE_SOUND("weapons/shock_impact.wav");
|
||||
}
|
||||
|
||||
void CMShock::FlyThink()
|
||||
{
|
||||
if (pev->waterlevel == 3)
|
||||
{
|
||||
entvars_t *pevOwner = VARS(pev->owner);
|
||||
EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/shock_impact.wav", VOL_NORM, ATTN_NORM);
|
||||
RadiusDamage(pev->origin, pev, pevOwner ? pevOwner : pev, pev->dmg * 3, 144, CLASS_NONE, DMG_SHOCK | DMG_ALWAYSGIB );
|
||||
ClearEffects();
|
||||
SetThink( &CMBaseEntity::SUB_Remove );
|
||||
pev->nextthink = gpGlobals->time;
|
||||
}
|
||||
else
|
||||
{
|
||||
pev->nextthink = gpGlobals->time + 0.05;
|
||||
}
|
||||
}
|
||||
|
||||
edict_t *CMShock::Shoot(entvars_t *pevOwner, const Vector angles, const Vector vecStart, const Vector vecVelocity)
|
||||
{
|
||||
CMShock *pShock = CreateClassPtr((CMShock *)NULL);
|
||||
|
||||
if (pShock == NULL)
|
||||
return NULL;
|
||||
|
||||
UTIL_SetOrigin(pShock->pev, vecStart);
|
||||
pShock->Spawn();
|
||||
|
||||
pShock->pev->velocity = vecVelocity;
|
||||
pShock->pev->owner = ENT(pevOwner);
|
||||
pShock->pev->angles = angles;
|
||||
|
||||
pShock->pev->nextthink = gpGlobals->time;
|
||||
|
||||
return pShock->edict();
|
||||
}
|
||||
|
||||
void CMShock::Touch(edict_t *pOther)
|
||||
{
|
||||
// Do not collide with the owner.
|
||||
if (pOther == pev->owner)
|
||||
return;
|
||||
|
||||
TraceResult tr = UTIL_GetGlobalTrace( );
|
||||
|
||||
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
|
||||
WRITE_BYTE(TE_DLIGHT);
|
||||
WRITE_COORD(pev->origin.x); // X
|
||||
WRITE_COORD(pev->origin.y); // Y
|
||||
WRITE_COORD(pev->origin.z); // Z
|
||||
WRITE_BYTE( 8 ); // radius * 0.1
|
||||
WRITE_BYTE( 0 ); // r
|
||||
WRITE_BYTE( 255 ); // g
|
||||
WRITE_BYTE( 255 ); // b
|
||||
WRITE_BYTE( 10 ); // time * 10
|
||||
WRITE_BYTE( 10 ); // decay * 0.1
|
||||
MESSAGE_END( );
|
||||
|
||||
ClearEffects();
|
||||
if (!pOther->v.takedamage)
|
||||
{
|
||||
// make a splat on the wall
|
||||
const int baseDecal = DECAL_SCORCH1;
|
||||
UTIL_DecalTrace(&tr, baseDecal + RANDOM_LONG(0, 1));
|
||||
|
||||
int iContents = UTIL_PointContents(pev->origin);
|
||||
|
||||
// Create sparks
|
||||
if (iContents != CONTENTS_WATER)
|
||||
{
|
||||
UTIL_Sparks(tr.vecEndPos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int damageType = DMG_SHOCK;
|
||||
ClearMultiDamage();
|
||||
entvars_t *pevOwner = VARS(pev->owner);
|
||||
entvars_t *pevAttacker = pevOwner ? pevOwner : pev;
|
||||
|
||||
if ( UTIL_IsPlayer( pOther ) )
|
||||
UTIL_TraceAttack( pOther, pevAttacker, pev->dmg, pev->velocity.Normalize(), &tr, damageType );
|
||||
else if ( pOther->v.euser4 != NULL )
|
||||
{
|
||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||
pMonster->TraceAttack( pevAttacker, pev->dmg, pev->velocity.Normalize(), &tr, damageType );
|
||||
}
|
||||
|
||||
ApplyMultiDamage(pev, pevAttacker);
|
||||
}
|
||||
|
||||
// splat sound
|
||||
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/shock_impact.wav", VOL_NORM, ATTN_NORM);
|
||||
|
||||
pev->modelindex = 0;
|
||||
pev->solid = SOLID_NOT;
|
||||
SetThink( &CMBaseEntity::SUB_Remove );
|
||||
pev->nextthink = gpGlobals->time + 0.01; // let the sound play
|
||||
}
|
||||
|
||||
void CMShock::CreateEffects()
|
||||
{
|
||||
m_pSprite = CMSprite::SpriteCreate( "sprites/flare3.spr", pev->origin, FALSE );
|
||||
m_pSprite->SetAttachment( edict(), 0 );
|
||||
m_pSprite->pev->scale = 0.35;
|
||||
m_pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 170, kRenderFxNoDissipation );
|
||||
//m_pSprite->pev->spawnflags |= SF_SPRITE_TEMPORARY;
|
||||
//m_pSprite->pev->flags |= FL_SKIPLOCALHOST;
|
||||
|
||||
m_pBeam = CMBeam::BeamCreate( "sprites/lgtning.spr", 30 );
|
||||
|
||||
if (m_pBeam)
|
||||
{
|
||||
m_pBeam->EntsInit( entindex(), entindex() );
|
||||
m_pBeam->SetStartAttachment( 1 );
|
||||
m_pBeam->SetEndAttachment( 2 );
|
||||
m_pBeam->SetBrightness( 180 );
|
||||
m_pBeam->SetScrollRate( 10 );
|
||||
m_pBeam->SetNoise( 0 );
|
||||
m_pBeam->SetFlags( BEAM_FSHADEOUT );
|
||||
m_pBeam->SetColor( 0, 255, 255 );
|
||||
//m_pBeam->pev->spawnflags = SF_BEAM_TEMPORARY;
|
||||
m_pBeam->RelinkBeam();
|
||||
}
|
||||
else
|
||||
{
|
||||
ALERT(at_console, "Could not create shockbeam beam!\n");
|
||||
}
|
||||
|
||||
m_pNoise = CMBeam::BeamCreate( "sprites/lgtning.spr", 30 );
|
||||
|
||||
if (m_pNoise)
|
||||
{
|
||||
m_pNoise->EntsInit( entindex(), entindex() );
|
||||
m_pNoise->SetStartAttachment( 1 );
|
||||
m_pNoise->SetEndAttachment( 2 );
|
||||
m_pNoise->SetBrightness( 180 );
|
||||
m_pNoise->SetScrollRate( 30 );
|
||||
m_pNoise->SetNoise( 30 );
|
||||
m_pNoise->SetFlags( BEAM_FSHADEOUT );
|
||||
m_pNoise->SetColor( 255, 255, 173 );
|
||||
//m_pNoise->pev->spawnflags = SF_BEAM_TEMPORARY;
|
||||
m_pNoise->RelinkBeam();
|
||||
}
|
||||
else
|
||||
{
|
||||
ALERT(at_console, "Could not create shockbeam noise!\n");
|
||||
}
|
||||
}
|
||||
|
||||
void CMShock::ClearEffects()
|
||||
{
|
||||
if (m_pBeam)
|
||||
{
|
||||
UTIL_Remove( m_pBeam->edict() );
|
||||
m_pBeam = NULL;
|
||||
}
|
||||
|
||||
if (m_pNoise)
|
||||
{
|
||||
UTIL_Remove( m_pNoise->edict() );
|
||||
m_pNoise = NULL;
|
||||
}
|
||||
|
||||
if (m_pSprite)
|
||||
{
|
||||
UTIL_Remove( m_pSprite->edict() );
|
||||
m_pSprite = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CMShock::UpdateOnRemove()
|
||||
{
|
||||
CMBaseAnimating::UpdateOnRemove();
|
||||
ClearEffects();
|
||||
}
|
||||
25
src/dlls/shock.h
Normal file
25
src/dlls/shock.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef SHOCKBEAM_H
|
||||
#define SHOCKBEAM_H
|
||||
|
||||
//=========================================================
|
||||
// Shockrifle projectile
|
||||
//=========================================================
|
||||
class CMShock : public CMBaseAnimating
|
||||
{
|
||||
public:
|
||||
void Spawn(void);
|
||||
void Precache(void);
|
||||
|
||||
static edict_t *Shoot(entvars_t *pevOwner, const Vector angles, const Vector vecStart, const Vector vecVelocity);
|
||||
void Touch(edict_t *pOther);
|
||||
void EXPORT FlyThink();
|
||||
|
||||
void CreateEffects();
|
||||
void ClearEffects();
|
||||
void UpdateOnRemove();
|
||||
|
||||
CMBeam *m_pBeam;
|
||||
CMBeam *m_pNoise;
|
||||
CMSprite *m_pSprite;
|
||||
};
|
||||
#endif
|
||||
223
src/dlls/shockroach.cpp
Normal file
223
src/dlls/shockroach.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
// HUGE thanks to DrBeef for his hlsdk-xash3d-opfor repository!
|
||||
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2001, 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.
|
||||
*
|
||||
* This source code contains proprietary and confidential information of
|
||||
* Valve LLC and its suppliers. Access to this code is restricted to
|
||||
* persons who have executed a written SDK license with Valve. Any access,
|
||||
* use or distribution of this code by or to any unlicensed person is illegal.
|
||||
*
|
||||
****/
|
||||
//=========================================================
|
||||
// shockroach.cpp
|
||||
//=========================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "monsters.h"
|
||||
#include "schedule.h"
|
||||
#include "weapons.h"
|
||||
|
||||
const char *CMShockRoach::pIdleSounds[] =
|
||||
{
|
||||
"shockroach/shock_idle1.wav",
|
||||
"shockroach/shock_idle2.wav",
|
||||
"shockroach/shock_idle3.wav",
|
||||
};
|
||||
const char *CMShockRoach::pAlertSounds[] =
|
||||
{
|
||||
"shockroach/shock_angry.wav",
|
||||
};
|
||||
const char *CMShockRoach::pPainSounds[] =
|
||||
{
|
||||
"shockroach/shock_flinch.wav",
|
||||
};
|
||||
const char *CMShockRoach::pAttackSounds[] =
|
||||
{
|
||||
"shockroach/shock_jump1.wav",
|
||||
"shockroach/shock_jump2.wav",
|
||||
};
|
||||
|
||||
const char *CMShockRoach::pDeathSounds[] =
|
||||
{
|
||||
"shockroach/shock_die.wav",
|
||||
};
|
||||
|
||||
const char *CMShockRoach::pBiteSounds[] =
|
||||
{
|
||||
"shockroach/shock_bite.wav",
|
||||
};
|
||||
|
||||
|
||||
//=========================================================
|
||||
// Spawn
|
||||
//=========================================================
|
||||
void CMShockRoach::Spawn()
|
||||
{
|
||||
Precache();
|
||||
|
||||
SET_MODEL(ENT(pev), "models/w_shock_rifle.mdl");
|
||||
UTIL_SetOrigin(pev, pev->origin);
|
||||
|
||||
pev->solid = SOLID_SLIDEBOX;
|
||||
pev->movetype = MOVETYPE_FLY;
|
||||
m_bloodColor = BLOOD_COLOR_GREEN;
|
||||
|
||||
pev->effects = 0;
|
||||
pev->health = gSkillData.roachHealth;
|
||||
pev->view_ofs = Vector(0, 0, 20);// position of the eyes relative to monster's origin.
|
||||
pev->yaw_speed = 5;//!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim?
|
||||
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||
m_MonsterState = MONSTERSTATE_NONE;
|
||||
|
||||
m_fRoachSolid = 0;
|
||||
m_flBirthTime = gpGlobals->time;
|
||||
|
||||
MonsterInit();
|
||||
|
||||
pev->classname = MAKE_STRING( "monster_shockroach" );
|
||||
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||
{
|
||||
// default name
|
||||
m_szMonsterName = MAKE_STRING( "Shock Roach" );
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// Precache - precaches all resources this monster needs
|
||||
//=========================================================
|
||||
void CMShockRoach::Precache()
|
||||
{
|
||||
PRECACHE_SOUND_ARRAY(pIdleSounds);
|
||||
PRECACHE_SOUND_ARRAY(pAlertSounds);
|
||||
PRECACHE_SOUND_ARRAY(pPainSounds);
|
||||
PRECACHE_SOUND_ARRAY(pAttackSounds);
|
||||
PRECACHE_SOUND_ARRAY(pDeathSounds);
|
||||
PRECACHE_SOUND_ARRAY(pBiteSounds);
|
||||
|
||||
PRECACHE_SOUND("shockroach/shock_walk.wav");
|
||||
|
||||
PRECACHE_MODEL("models/w_shock_rifle.mdl");
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// LeapTouch - this is the headcrab's touch function when it
|
||||
// is in the air
|
||||
//=========================================================
|
||||
void CMShockRoach::LeapTouch(edict_t *pOther)
|
||||
{
|
||||
if (!pOther->v.takedamage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't hit if back on ground
|
||||
if (!FBitSet(pev->flags, FL_ONGROUND))
|
||||
{
|
||||
EMIT_SOUND_DYN(edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pBiteSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch());
|
||||
|
||||
if (UTIL_IsPlayer(pOther))
|
||||
UTIL_TakeDamage( pOther, pev, pev, GetDamageAmount(), DMG_SLASH );
|
||||
else if (pOther->v.euser4 != NULL)
|
||||
{
|
||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||
pMonster->TakeDamage( pev, pev, GetDamageAmount(), DMG_SLASH );
|
||||
}
|
||||
}
|
||||
|
||||
SetTouch(NULL);
|
||||
}
|
||||
//=========================================================
|
||||
// PrescheduleThink
|
||||
//=========================================================
|
||||
void CMShockRoach::MonsterThink(void)
|
||||
{
|
||||
float lifeTime = (gpGlobals->time - m_flBirthTime);
|
||||
if (lifeTime >= 0.2)
|
||||
{
|
||||
pev->movetype = MOVETYPE_STEP;
|
||||
}
|
||||
if (!m_fRoachSolid && lifeTime >= 2.0 ) {
|
||||
m_fRoachSolid = TRUE;
|
||||
UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 4));
|
||||
}
|
||||
if (lifeTime >= gSkillData.roachLifespan)
|
||||
{
|
||||
pev->health = -1;
|
||||
Killed(pev, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
CMHeadCrab::MonsterThink();
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// IdleSound
|
||||
//=========================================================
|
||||
void CMShockRoach::IdleSound(void)
|
||||
{
|
||||
EMIT_SOUND_DYN(edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch());
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// AlertSound
|
||||
//=========================================================
|
||||
void CMShockRoach::AlertSound(void)
|
||||
{
|
||||
EMIT_SOUND_DYN(edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAlertSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch());
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// AlertSound
|
||||
//=========================================================
|
||||
void CMShockRoach::PainSound(void)
|
||||
{
|
||||
EMIT_SOUND_DYN(edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch());
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// DeathSound
|
||||
//=========================================================
|
||||
void CMShockRoach::DeathSound(void)
|
||||
{
|
||||
EMIT_SOUND_DYN(edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch());
|
||||
}
|
||||
|
||||
|
||||
void CMShockRoach::StartTask(Task_t *pTask)
|
||||
{
|
||||
m_iTaskStatus = TASKSTATUS_RUNNING;
|
||||
|
||||
switch (pTask->iTask)
|
||||
{
|
||||
case TASK_RANGE_ATTACK1:
|
||||
{
|
||||
m_IdealActivity = ACT_RANGE_ATTACK1;
|
||||
SetTouch(&CMShockRoach::LeapTouch);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
CMHeadCrab::StartTask(pTask);
|
||||
}
|
||||
}
|
||||
|
||||
int CMShockRoach::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
||||
{
|
||||
if ( gpGlobals->time - m_flBirthTime < 2.0 )
|
||||
flDamage = 0.0;
|
||||
// Skip headcrab's TakeDamage to avoid unwanted immunity to acid.
|
||||
return CMBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
|
||||
}
|
||||
|
||||
void CMShockRoach::AttackSound()
|
||||
{
|
||||
EMIT_SOUND_DYN(edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch());
|
||||
}
|
||||
@@ -83,6 +83,12 @@ skill_cfg_t skill_cfg[] = {
|
||||
{"sk_pitdrone_dmg_spit", &gSkillData.pitdroneDmgSpit},
|
||||
{"sk_pitdrone_dmg_whip", &gSkillData.pitdroneDmgWhip},
|
||||
{"sk_pitdrone_dmg_bite", &gSkillData.pitdroneDmgBite},
|
||||
{"sk_shockroach_health", &gSkillData.roachHealth},
|
||||
{"sk_shockroach_lifespan", &gSkillData.roachLifespan},
|
||||
{"sk_shocktrooper_health", &gSkillData.strooperHealth},
|
||||
{"sk_shocktrooper_kick", &gSkillData.strooperDmgKick},
|
||||
{"sk_shocktrooper_maxcharge", &gSkillData.strooperMaxCharge},
|
||||
{"sk_shocktrooper_rchgspeed", &gSkillData.strooperRchgSpeed},
|
||||
{"sk_12mm_bullet", &gSkillData.monDmg9MM},
|
||||
{"sk_9mmAR_bullet", &gSkillData.monDmgMP5},
|
||||
{"sk_9mm_bullet", &gSkillData.monDmg12MM},
|
||||
@@ -90,6 +96,8 @@ skill_cfg_t skill_cfg[] = {
|
||||
{"sk_762_bullet", &gSkillData.monDmg762},
|
||||
{"sk_357_bullet", &gSkillData.monDmg357},
|
||||
{"sk_hornet_dmg", &gSkillData.monDmgHornet},
|
||||
{"sk_shock_dmg", &gSkillData.monDmgShockroach},
|
||||
{"sk_spore_dmg", &gSkillData.monDmgSpore},
|
||||
{"", NULL}
|
||||
};
|
||||
|
||||
@@ -244,6 +252,16 @@ void monster_skill_init(void)
|
||||
gSkillData.pitdroneDmgWhip = 35.0f;
|
||||
gSkillData.pitdroneDmgBite = 25.0f;
|
||||
|
||||
// Shock Roach
|
||||
gSkillData.roachHealth = 10.0f;
|
||||
gSkillData.roachLifespan = 10.0f;
|
||||
|
||||
// Shock Trooper
|
||||
gSkillData.strooperHealth = 50.0f;
|
||||
gSkillData.strooperDmgKick = 10.0f;
|
||||
gSkillData.strooperMaxCharge = 8.0f;
|
||||
gSkillData.strooperRchgSpeed = 1.0f;
|
||||
|
||||
// MONSTER WEAPONS
|
||||
gSkillData.monDmg9MM = 5.0f;
|
||||
gSkillData.monDmgMP5 = 4.0f;
|
||||
@@ -254,8 +272,13 @@ void monster_skill_init(void)
|
||||
|
||||
// HORNET
|
||||
gSkillData.monDmgHornet = 5.0f;
|
||||
|
||||
|
||||
|
||||
// SHOCK ROACH
|
||||
gSkillData.monDmgShockroach = 15.0f;
|
||||
|
||||
// SPORE GRENADE
|
||||
gSkillData.monDmgSpore = 50.0f;
|
||||
|
||||
// find the directory name of the currently running MOD...
|
||||
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
||||
|
||||
|
||||
@@ -102,6 +102,14 @@ struct skilldata_t
|
||||
float pitdroneDmgWhip;
|
||||
float pitdroneDmgBite;
|
||||
|
||||
float roachHealth;
|
||||
float roachLifespan;
|
||||
|
||||
float strooperHealth;
|
||||
float strooperDmgKick;
|
||||
float strooperMaxCharge;
|
||||
float strooperRchgSpeed;
|
||||
|
||||
// weapons shared by monsters
|
||||
float monDmg9MM;
|
||||
float monDmgMP5;
|
||||
@@ -111,6 +119,8 @@ struct skilldata_t
|
||||
float monDmg357;
|
||||
|
||||
float monDmgHornet;
|
||||
float monDmgShockroach;
|
||||
float monDmgSpore;
|
||||
};
|
||||
|
||||
extern DLL_GLOBAL skilldata_t gSkillData;
|
||||
|
||||
345
src/dlls/sporegrenade.cpp
Normal file
345
src/dlls/sporegrenade.cpp
Normal file
@@ -0,0 +1,345 @@
|
||||
// HUGE thanks to DrBeef for his hlsdk-xash3d-opfor repository!
|
||||
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2001, 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 "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "monsters.h"
|
||||
#include "weapons.h"
|
||||
#include "decals.h"
|
||||
#include "explode.h"
|
||||
|
||||
int gSporeExplode, gSporeExplodeC;
|
||||
|
||||
void CMSporeGrenade::Precache()
|
||||
{
|
||||
PRECACHE_MODEL("models/spore.mdl");
|
||||
PRECACHE_MODEL("sprites/glow02.spr");
|
||||
g_sModelIndexTinySpit = PRECACHE_MODEL("sprites/tinyspit.spr");
|
||||
gSporeExplode = PRECACHE_MODEL("sprites/spore_exp_01.spr");
|
||||
gSporeExplodeC = PRECACHE_MODEL("sprites/spore_exp_c_01.spr");
|
||||
PRECACHE_SOUND("weapons/splauncher_bounce.wav");
|
||||
PRECACHE_SOUND("weapons/splauncher_impact.wav");
|
||||
}
|
||||
|
||||
void CMSporeGrenade::Explode(TraceResult *pTrace)
|
||||
{
|
||||
pev->solid = SOLID_NOT;// intangible
|
||||
pev->takedamage = DAMAGE_NO;
|
||||
|
||||
// Pull out of the wall a bit
|
||||
if (pTrace->flFraction != 1.0)
|
||||
{
|
||||
pev->origin = pTrace->vecEndPos + (pTrace->vecPlaneNormal * (pev->dmg - 24) * 0.6);
|
||||
}
|
||||
|
||||
Vector vecSpraySpot = pTrace->vecEndPos;
|
||||
float flSpraySpeed = RANDOM_LONG(10, 15);
|
||||
|
||||
// If the trace is pointing up, then place
|
||||
// spawn position a few units higher.
|
||||
if (pTrace->vecPlaneNormal.z > 0)
|
||||
{
|
||||
vecSpraySpot = vecSpraySpot + (pTrace->vecPlaneNormal * 8);
|
||||
flSpraySpeed *= 2; // Double the speed to make them fly higher
|
||||
// in the air.
|
||||
}
|
||||
|
||||
// Spawn small particles at the explosion origin.
|
||||
SpawnExplosionParticles(
|
||||
vecSpraySpot, // position
|
||||
pTrace->vecPlaneNormal, // direction
|
||||
g_sModelIndexTinySpit, // modelindex
|
||||
RANDOM_LONG(40, 50), // count
|
||||
flSpraySpeed, // speed
|
||||
RANDOM_FLOAT(600, 640)); // noise
|
||||
|
||||
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
|
||||
WRITE_BYTE( TE_SPRITE );
|
||||
WRITE_COORD( pev->origin.x );
|
||||
WRITE_COORD( pev->origin.y );
|
||||
WRITE_COORD( pev->origin.z );
|
||||
WRITE_SHORT( RANDOM_LONG( 0, 1 ) ? gSporeExplode : gSporeExplodeC );
|
||||
WRITE_BYTE( 25 ); // scale * 10
|
||||
WRITE_BYTE( 155 ); // framerate
|
||||
MESSAGE_END();
|
||||
|
||||
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
|
||||
WRITE_BYTE(TE_DLIGHT);
|
||||
WRITE_COORD( pev->origin.x ); // X
|
||||
WRITE_COORD( pev->origin.y ); // Y
|
||||
WRITE_COORD( pev->origin.z ); // Z
|
||||
WRITE_BYTE( 12 ); // radius * 0.1
|
||||
WRITE_BYTE( 0 ); // r
|
||||
WRITE_BYTE( 180 ); // g
|
||||
WRITE_BYTE( 0 ); // b
|
||||
WRITE_BYTE( 20 ); // time * 10
|
||||
WRITE_BYTE( 20 ); // decay * 0.1
|
||||
MESSAGE_END( );
|
||||
|
||||
// Play explode sound.
|
||||
EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/splauncher_impact.wav", 1, ATTN_NORM);
|
||||
|
||||
entvars_t *pevOwner;
|
||||
if (pev->owner)
|
||||
pevOwner = VARS(pev->owner);
|
||||
else
|
||||
pevOwner = NULL;
|
||||
|
||||
pev->owner = NULL; // can't traceline attack owner if this is set
|
||||
|
||||
RadiusDamage(pev, pevOwner, pev->dmg, CLASS_NONE, DMG_BLAST);
|
||||
|
||||
// Place a decal on the surface that was hit.
|
||||
UTIL_DecalTrace(pTrace, DECAL_SPIT1 + RANDOM_LONG(0, 1));
|
||||
|
||||
UpdateOnRemove();
|
||||
UTIL_Remove( this->edict() );
|
||||
}
|
||||
|
||||
void CMSporeGrenade::Detonate()
|
||||
{
|
||||
TraceResult tr;
|
||||
Vector vecSpot = pev->origin + Vector(0, 0, 8);
|
||||
UTIL_TraceLine(vecSpot, vecSpot + Vector(0, 0, -40), ignore_monsters, ENT(pev), &tr);
|
||||
|
||||
Explode(&tr);
|
||||
}
|
||||
|
||||
|
||||
void CMSporeGrenade::BounceSound()
|
||||
{
|
||||
EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/splauncher_bounce.wav", 0.25, ATTN_NORM);
|
||||
}
|
||||
|
||||
void CMSporeGrenade::TumbleThink()
|
||||
{
|
||||
if (!IsInWorld())
|
||||
{
|
||||
UpdateOnRemove();
|
||||
UTIL_Remove( this->edict() );
|
||||
return;
|
||||
}
|
||||
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
|
||||
if (pev->dmgtime <= gpGlobals->time)
|
||||
{
|
||||
SetThink(&CMSporeGrenade::Detonate);
|
||||
}
|
||||
|
||||
// Spawn particles.
|
||||
SpawnTrailParticles(
|
||||
pev->origin, // position
|
||||
-pev->velocity.Normalize(), // dir
|
||||
g_sModelIndexTinySpit, // modelindex
|
||||
RANDOM_LONG( 2, 4 ), // count
|
||||
RANDOM_FLOAT(10, 15), // speed
|
||||
RANDOM_FLOAT(2, 3) * 100); // noise ( client will divide by 100 )
|
||||
}
|
||||
|
||||
//
|
||||
// Contact grenade, explode when it touches something
|
||||
//
|
||||
void CMSporeGrenade::ExplodeTouch(edict_t *pOther)
|
||||
{
|
||||
TraceResult tr;
|
||||
Vector vecSpot;// trace starts here!
|
||||
|
||||
pev->enemy = pOther;
|
||||
|
||||
vecSpot = pev->origin - pev->velocity.Normalize() * 32;
|
||||
UTIL_TraceLine(vecSpot, vecSpot + pev->velocity.Normalize() * 64, ignore_monsters, ENT(pev), &tr);
|
||||
|
||||
Explode(&tr);
|
||||
}
|
||||
|
||||
void CMSporeGrenade::DangerSoundThink()
|
||||
{
|
||||
if (!IsInWorld())
|
||||
{
|
||||
UpdateOnRemove();
|
||||
UTIL_Remove( this->edict() );
|
||||
return;
|
||||
}
|
||||
|
||||
pev->nextthink = gpGlobals->time + 0.2;
|
||||
|
||||
// Spawn particles.
|
||||
SpawnTrailParticles(
|
||||
pev->origin, // position
|
||||
-pev->velocity.Normalize(), // dir
|
||||
g_sModelIndexTinySpit, // modelindex
|
||||
RANDOM_LONG( 5, 10), // count
|
||||
RANDOM_FLOAT(10, 15), // speed
|
||||
RANDOM_FLOAT(2, 3) * 100); // noise ( client will divide by 100 )
|
||||
}
|
||||
|
||||
void CMSporeGrenade::BounceTouch(edict_t *pOther)
|
||||
{
|
||||
if ( !pOther->v.takedamage )
|
||||
{
|
||||
if (!(pev->flags & FL_ONGROUND)) {
|
||||
if (pev->dmg_save < gpGlobals->time) {
|
||||
BounceSound();
|
||||
pev->dmg_save = gpGlobals->time + 0.1;
|
||||
}
|
||||
} else {
|
||||
pev->velocity = pev->velocity * 0.9;
|
||||
}
|
||||
if (pev->flags & FL_SWIM)
|
||||
{
|
||||
pev->velocity = pev->velocity * 0.5;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceResult tr = UTIL_GetGlobalTrace();
|
||||
Explode(&tr);
|
||||
}
|
||||
}
|
||||
|
||||
void CMSporeGrenade::Spawn()
|
||||
{
|
||||
Precache();
|
||||
pev->classname = MAKE_STRING("spore");
|
||||
pev->movetype = MOVETYPE_BOUNCE;
|
||||
|
||||
pev->solid = SOLID_BBOX;
|
||||
|
||||
SET_MODEL(ENT(pev), "models/spore.mdl");
|
||||
UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0));
|
||||
|
||||
//pev->gravity = 0.5;
|
||||
|
||||
pev->dmg = gSkillData.monDmgSpore;
|
||||
|
||||
m_pSporeGlow = CMSprite::SpriteCreate("sprites/glow02.spr", pev->origin, FALSE);
|
||||
|
||||
if (m_pSporeGlow)
|
||||
{
|
||||
m_pSporeGlow->SetTransparency(kRenderGlow, 150, 158, 19, 155, kRenderFxNoDissipation);
|
||||
m_pSporeGlow->SetAttachment(edict(), 0);
|
||||
m_pSporeGlow->SetScale(.75f);
|
||||
}
|
||||
}
|
||||
|
||||
CMSporeGrenade* CMSporeGrenade::ShootTimed(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, bool ai)
|
||||
{
|
||||
CMSporeGrenade *pGrenade = CreateClassPtr((CMSporeGrenade *)NULL);
|
||||
|
||||
if (pGrenade == NULL)
|
||||
return NULL;
|
||||
|
||||
UTIL_SetOrigin(pGrenade->pev, vecStart);
|
||||
pGrenade->Spawn();
|
||||
pGrenade->pev->velocity = vecVelocity;
|
||||
pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity);
|
||||
pGrenade->pev->owner = ENT(pevOwner);
|
||||
|
||||
pGrenade->SetTouch(&CMSporeGrenade::BounceTouch); // Bounce if touched
|
||||
|
||||
float lifetime = 2.0;
|
||||
if (ai) {
|
||||
lifetime = 4.0;
|
||||
pGrenade->pev->gravity = 0.5;
|
||||
pGrenade->pev->friction = 0.9;
|
||||
}
|
||||
pGrenade->pev->dmgtime = gpGlobals->time + lifetime;
|
||||
pGrenade->SetThink(&CMSporeGrenade::TumbleThink);
|
||||
pGrenade->pev->nextthink = gpGlobals->time + 0.1;
|
||||
if (lifetime < 0.1)
|
||||
{
|
||||
pGrenade->pev->nextthink = gpGlobals->time;
|
||||
pGrenade->pev->velocity = Vector(0, 0, 0);
|
||||
}
|
||||
|
||||
return pGrenade;
|
||||
}
|
||||
|
||||
CMSporeGrenade *CMSporeGrenade::ShootContact(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity)
|
||||
{
|
||||
CMSporeGrenade *pGrenade = CreateClassPtr((CMSporeGrenade *)NULL);
|
||||
|
||||
if (pGrenade == NULL)
|
||||
return NULL;
|
||||
|
||||
UTIL_SetOrigin(pGrenade->pev, vecStart);
|
||||
pGrenade->Spawn();
|
||||
pGrenade->pev->movetype = MOVETYPE_FLY;
|
||||
pGrenade->pev->velocity = vecVelocity;
|
||||
pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity);
|
||||
pGrenade->pev->owner = ENT(pevOwner);
|
||||
|
||||
// make monsters afraid of it while in the air
|
||||
pGrenade->SetThink(&CMSporeGrenade::DangerSoundThink);
|
||||
pGrenade->pev->nextthink = gpGlobals->time;
|
||||
|
||||
// Explode on contact
|
||||
pGrenade->SetTouch(&CMSporeGrenade::ExplodeTouch);
|
||||
|
||||
pGrenade->pev->gravity = 0.5;
|
||||
pGrenade->pev->friction = 0.7;
|
||||
|
||||
return pGrenade;
|
||||
}
|
||||
|
||||
void CMSporeGrenade::SpawnTrailParticles(const Vector& origin, const Vector& direction, int modelindex, int count, float speed, float noise)
|
||||
{
|
||||
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, origin);
|
||||
WRITE_BYTE(TE_SPRITE_SPRAY);
|
||||
WRITE_COORD(origin.x); // pos
|
||||
WRITE_COORD(origin.y);
|
||||
WRITE_COORD(origin.z);
|
||||
WRITE_COORD(direction.x); // dir
|
||||
WRITE_COORD(direction.y);
|
||||
WRITE_COORD(direction.z);
|
||||
WRITE_SHORT(modelindex); // model
|
||||
WRITE_BYTE(count); // count
|
||||
WRITE_BYTE(speed); // speed
|
||||
WRITE_BYTE(noise); // noise ( client will divide by 100 )
|
||||
MESSAGE_END();
|
||||
}
|
||||
|
||||
void CMSporeGrenade::SpawnExplosionParticles(const Vector& origin, const Vector& direction, int modelindex, int count, float speed, float noise)
|
||||
{
|
||||
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, origin);
|
||||
WRITE_BYTE(TE_SPRITE_SPRAY);
|
||||
WRITE_COORD(origin.x); // pos
|
||||
WRITE_COORD(origin.y);
|
||||
WRITE_COORD(origin.z);
|
||||
WRITE_COORD(direction.x); // dir
|
||||
WRITE_COORD(direction.y);
|
||||
WRITE_COORD(direction.z);
|
||||
WRITE_SHORT(modelindex); // model
|
||||
WRITE_BYTE(count); // count
|
||||
WRITE_BYTE(speed); // speed
|
||||
WRITE_BYTE(noise); // noise ( client will divide by 100 )
|
||||
MESSAGE_END();
|
||||
}
|
||||
|
||||
void CMSporeGrenade::UpdateOnRemove()
|
||||
{
|
||||
CMBaseMonster::UpdateOnRemove();
|
||||
if (m_pSporeGlow)
|
||||
{
|
||||
UTIL_Remove(m_pSporeGlow->edict());
|
||||
m_pSporeGlow = NULL;
|
||||
}
|
||||
}
|
||||
899
src/dlls/strooper.cpp
Normal file
899
src/dlls/strooper.cpp
Normal file
@@ -0,0 +1,899 @@
|
||||
// HUGE thanks to DrBeef for his hlsdk-xash3d-opfor repository!
|
||||
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2001, 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.
|
||||
*
|
||||
* This source code contains proprietary and confidential information of
|
||||
* Valve LLC and its suppliers. Access to this code is restricted to
|
||||
* persons who have executed a written SDK license with Valve. Any access,
|
||||
* use or distribution of this code by or to any unlicensed person is illegal.
|
||||
*
|
||||
****/
|
||||
//=========================================================
|
||||
// shocktrooper
|
||||
//=========================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "plane.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "monsters.h"
|
||||
#include "schedule.h"
|
||||
#include "animation.h"
|
||||
#include "weapons.h"
|
||||
#include "cmtalkmonster.h"
|
||||
#include "effects.h"
|
||||
#include "customentity.h"
|
||||
#include "shock.h"
|
||||
|
||||
int g_fStrooperQuestion; // true if an idle grunt asked a question. Cleared when someone answers.
|
||||
|
||||
extern Schedule_t slGruntTakeCover[];
|
||||
extern Schedule_t slGruntGrenadeCover[];
|
||||
|
||||
//=========================================================
|
||||
// monster-specific DEFINE's
|
||||
//=========================================================
|
||||
#define STROOPER_CLIP_SIZE 10 // how many bullets in a clip? - NOTE: 3 round burst sound, so keep as 3 * x!
|
||||
#define STROOPER_VOL 0.35 // volume of grunt sounds
|
||||
#define STROOPER_ATTN ATTN_NORM // attenutation of grunt sentences
|
||||
#define STROOPER_LIMP_HEALTH 20
|
||||
#define STROOPER_DMG_HEADSHOT ( DMG_BULLET | DMG_CLUB ) // damage types that can kill a grunt with a single headshot.
|
||||
#define STROOPER_NUM_HEADS 2 // how many grunt heads are there?
|
||||
#define STROOPER_MINIMUM_HEADSHOT_DAMAGE 15 // must do at least this much damage in one shot to head to score a headshot kill
|
||||
#define STROOPER_SENTENCE_VOLUME (float)0.35 // volume of grunt sentences
|
||||
#define STROOPER_MUZZLEFLASH "sprites/muzzle_shock.spr"
|
||||
|
||||
#define STROOPER_SHOCKRIFLE (1 << 0)
|
||||
#define STROOPER_HANDGRENADE (1 << 1)
|
||||
|
||||
#define GUN_GROUP 1
|
||||
#define GUN_SHOCKRIFLE 0
|
||||
#define GUN_NONE 1
|
||||
|
||||
//=========================================================
|
||||
// Monster's Anim Events Go Here
|
||||
//=========================================================
|
||||
#define STROOPER_AE_RELOAD ( 2 )
|
||||
#define STROOPER_AE_KICK ( 3 )
|
||||
#define STROOPER_AE_BURST1 ( 4 )
|
||||
#define STROOPER_AE_BURST2 ( 5 )
|
||||
#define STROOPER_AE_BURST3 ( 6 )
|
||||
#define STROOPER_AE_GREN_TOSS ( 7 )
|
||||
#define STROOPER_AE_GREN_LAUNCH ( 8 )
|
||||
#define STROOPER_AE_GREN_DROP ( 9 )
|
||||
#define STROOPER_AE_CAUGHT_ENEMY ( 10 ) // shocktrooper established sight with an enemy (player only) that had previously eluded the squad.
|
||||
#define STROOPER_AE_DROP_GUN ( 11 ) // shocktrooper (probably dead) is dropping his shockrifle.
|
||||
|
||||
|
||||
//=========================================================
|
||||
// monster-specific schedule types
|
||||
//=========================================================
|
||||
enum
|
||||
{
|
||||
SCHED_STROOPER_SUPPRESS = LAST_COMMON_SCHEDULE + 1,
|
||||
SCHED_STROOPER_ESTABLISH_LINE_OF_FIRE,// move to a location to set up an attack against the enemy. (usually when a friendly is in the way).
|
||||
SCHED_STROOPER_COVER_AND_RELOAD,
|
||||
SCHED_STROOPER_SWEEP,
|
||||
SCHED_STROOPER_FOUND_ENEMY,
|
||||
SCHED_STROOPER_REPEL,
|
||||
SCHED_STROOPER_REPEL_ATTACK,
|
||||
SCHED_STROOPER_REPEL_LAND,
|
||||
SCHED_STROOPER_WAIT_FACE_ENEMY,
|
||||
SCHED_STROOPER_TAKECOVER_FAILED,// special schedule type that forces analysis of conditions and picks the best possible schedule to recover from this type of failure.
|
||||
SCHED_STROOPER_ELOF_FAIL,
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// monster-specific tasks
|
||||
//=========================================================
|
||||
enum
|
||||
{
|
||||
TASK_STROOPER_FACE_TOSS_DIR = LAST_COMMON_TASK + 1,
|
||||
TASK_STROOPER_SPEAK_SENTENCE,
|
||||
TASK_STROOPER_CHECK_FIRE,
|
||||
};
|
||||
|
||||
int iStrooperMuzzleFlash;
|
||||
|
||||
const char *CMStrooper::pGruntSentences[] =
|
||||
{
|
||||
"ST_GREN", // grenade scared grunt
|
||||
"ST_ALERT", // sees player
|
||||
"ST_MONST", // sees monster
|
||||
"ST_COVER", // running to cover
|
||||
"ST_THROW", // about to throw grenade
|
||||
"ST_CHARGE", // running out to get the enemy
|
||||
"ST_TAUNT", // say rude things
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STROOPER_SENT_NONE = -1,
|
||||
STROOPER_SENT_GREN = 0,
|
||||
STROOPER_SENT_ALERT,
|
||||
STROOPER_SENT_MONSTER,
|
||||
STROOPER_SENT_COVER,
|
||||
STROOPER_SENT_THROW,
|
||||
STROOPER_SENT_CHARGE,
|
||||
STROOPER_SENT_TAUNT,
|
||||
} STROOPER_SENTENCE_TYPES;
|
||||
|
||||
void CMStrooper::SpeakSentence()
|
||||
{
|
||||
if( m_iSentence == STROOPER_SENT_NONE )
|
||||
{
|
||||
// no sentence cued up.
|
||||
return;
|
||||
}
|
||||
|
||||
if( FOkToSpeak() )
|
||||
{
|
||||
SENTENCEG_PlayRndSz( ENT( pev ), pGruntSentences[m_iSentence], STROOPER_SENTENCE_VOLUME, STROOPER_ATTN, 0, m_voicePitch );
|
||||
JustSpoke();
|
||||
}
|
||||
}
|
||||
|
||||
#define STROOPER_GIB_COUNT 8
|
||||
//=========================================================
|
||||
// GibMonster - make gun fly through the air.
|
||||
//=========================================================
|
||||
void CMStrooper::GibMonster()
|
||||
{
|
||||
if (GetBodygroup(GUN_GROUP) != GUN_NONE)
|
||||
{
|
||||
DropShockRoach(true);
|
||||
}
|
||||
|
||||
EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "common/bodysplat.wav", 1, ATTN_NORM );
|
||||
|
||||
if( CVAR_GET_FLOAT( "violence_agibs" ) != 0 ) // Should never get here, but someone might call it directly
|
||||
{
|
||||
CMGib::SpawnRandomGibs( pev, STROOPER_GIB_COUNT, "models/strooper_gibs.mdl", 0 ); // Throw alien gibs
|
||||
}
|
||||
SetThink( &CMBaseEntity::SUB_Remove );
|
||||
pev->nextthink = gpGlobals->time;
|
||||
}
|
||||
|
||||
void CMStrooper::IdleSound()
|
||||
{
|
||||
if (FOkToSpeak() && (g_fStrooperQuestion || RANDOM_LONG(0, 1)))
|
||||
{
|
||||
if (!g_fStrooperQuestion)
|
||||
{
|
||||
// ask question or make statement
|
||||
switch (RANDOM_LONG(0, 2))
|
||||
{
|
||||
case 0: // check in
|
||||
SENTENCEG_PlayRndSz(ENT(pev), "ST_CHECK", STROOPER_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
||||
g_fStrooperQuestion = 1;
|
||||
break;
|
||||
case 1: // question
|
||||
SENTENCEG_PlayRndSz(ENT(pev), "ST_QUEST", STROOPER_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
||||
g_fStrooperQuestion = 2;
|
||||
break;
|
||||
case 2: // statement
|
||||
SENTENCEG_PlayRndSz(ENT(pev), "ST_IDLE", STROOPER_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (g_fStrooperQuestion)
|
||||
{
|
||||
case 1: // check in
|
||||
SENTENCEG_PlayRndSz(ENT(pev), "ST_CLEAR", STROOPER_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
||||
break;
|
||||
case 2: // question
|
||||
SENTENCEG_PlayRndSz(ENT(pev), "ST_ANSWER", STROOPER_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
||||
break;
|
||||
}
|
||||
g_fStrooperQuestion = 0;
|
||||
}
|
||||
JustSpoke();
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// Classify - indicates this monster's place in the
|
||||
// relationship table.
|
||||
//=========================================================
|
||||
int CMStrooper::Classify()
|
||||
{
|
||||
if ( m_iClassifyOverride == -1 ) // helper
|
||||
return CLASS_NONE;
|
||||
else if ( m_iClassifyOverride > 0 )
|
||||
return m_iClassifyOverride; // override
|
||||
|
||||
return CLASS_RACEX_SHOCK;
|
||||
}
|
||||
|
||||
BOOL CMStrooper::CheckRangeAttack1(float flDot, float flDist)
|
||||
{
|
||||
return m_cAmmoLoaded >= 1;// && CMHGrunt::CheckRangeAttack1(flDot, flDist);
|
||||
}
|
||||
|
||||
BOOL CMStrooper::CheckRangeAttack2( float flDot, float flDist )
|
||||
{
|
||||
if( !FBitSet( pev->weapons, STROOPER_HANDGRENADE ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
return CMHGrunt::CheckRangeAttack2(flDot, flDist);
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// HandleAnimEvent - catches the monster-specific messages
|
||||
// that occur when tagged animation frames are played.
|
||||
//=========================================================
|
||||
void CMStrooper::HandleAnimEvent(MonsterEvent_t *pEvent)
|
||||
{
|
||||
switch (pEvent->event)
|
||||
{
|
||||
case STROOPER_AE_DROP_GUN:
|
||||
{
|
||||
if (GetBodygroup(GUN_GROUP) != GUN_NONE)
|
||||
{
|
||||
DropShockRoach(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STROOPER_AE_RELOAD:
|
||||
m_cAmmoLoaded = m_cClipSize;
|
||||
ClearConditions(bits_COND_NO_AMMO_LOADED);
|
||||
break;
|
||||
|
||||
case STROOPER_AE_GREN_TOSS:
|
||||
{
|
||||
UTIL_MakeVectors(pev->angles);
|
||||
// CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 34 + Vector (0, 0, 32), m_vecTossVelocity, 3.5 );
|
||||
CMSporeGrenade::ShootTimed(pev, pev->origin + Vector(0,0,98), m_vecTossVelocity, 3.5);
|
||||
|
||||
m_fThrowGrenade = FALSE;
|
||||
m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown.
|
||||
// !!!LATER - when in a group, only try to throw grenade if ordered.
|
||||
}
|
||||
break;
|
||||
|
||||
case STROOPER_AE_GREN_LAUNCH:
|
||||
case STROOPER_AE_GREN_DROP:
|
||||
break;
|
||||
|
||||
case STROOPER_AE_BURST1:
|
||||
{
|
||||
if (m_hEnemy)
|
||||
{
|
||||
Vector vecGunPos;
|
||||
Vector vecGunAngles;
|
||||
|
||||
GetAttachment(0, vecGunPos, vecGunAngles);
|
||||
|
||||
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecGunPos );
|
||||
WRITE_BYTE( TE_SPRITE );
|
||||
WRITE_COORD( vecGunPos.x ); // pos
|
||||
WRITE_COORD( vecGunPos.y );
|
||||
WRITE_COORD( vecGunPos.z );
|
||||
WRITE_SHORT( iStrooperMuzzleFlash ); // model
|
||||
WRITE_BYTE( 4 ); // size * 10
|
||||
WRITE_BYTE( 128 ); // brightness
|
||||
MESSAGE_END();
|
||||
|
||||
UTIL_MakeVectors(pev->angles);
|
||||
Vector vecShootOrigin = vecGunPos + gpGlobals->v_forward * 32;
|
||||
Vector vecShootDir = ShootAtEnemy( vecShootOrigin );
|
||||
vecGunAngles = UTIL_VecToAngles(vecShootDir);
|
||||
|
||||
//CBaseEntity *pShock = CBaseEntity::Create("shock_beam", vecShootOrigin, vecGunAngles, edict());
|
||||
CMShock *pShock = CreateClassPtr((CMShock *)NULL);
|
||||
|
||||
if (pShock != NULL)
|
||||
{
|
||||
pShock->pev->origin = vecShootOrigin;
|
||||
|
||||
vecGunAngles.z += RANDOM_FLOAT( -0.05, 0 );
|
||||
pShock->pev->angles = UTIL_VecToAngles( vecGunAngles );
|
||||
pShock->pev->owner = edict();
|
||||
|
||||
// Initialize these for entities who don't link to the world
|
||||
pShock->pev->absmin = pShock->pev->origin - Vector(1,1,1);
|
||||
pShock->pev->absmax = pShock->pev->origin + Vector(1,1,1);
|
||||
|
||||
pShock->Spawn();
|
||||
|
||||
pShock->pev->velocity = vecShootDir * 2000;
|
||||
pShock->pev->nextthink = gpGlobals->time;
|
||||
}
|
||||
|
||||
m_cAmmoLoaded--;
|
||||
SetBlending( 0, vecGunAngles.x );
|
||||
|
||||
// Play fire sound.
|
||||
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/shock_fire.wav", 1, ATTN_NORM);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STROOPER_AE_KICK:
|
||||
{
|
||||
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "zombie/claw_miss2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM + RANDOM_LONG( -5, 5 ) );
|
||||
edict_t *pHurt = Kick();
|
||||
|
||||
if (pHurt)
|
||||
{
|
||||
// SOUND HERE!
|
||||
UTIL_MakeVectors(pev->angles);
|
||||
pHurt->v.punchangle.x = 15;
|
||||
pHurt->v.punchangle.z = (m_fRightClaw) ? -10 : 10;
|
||||
pHurt->v.velocity = pHurt->v.velocity + gpGlobals->v_forward * 100 + gpGlobals->v_up * 50;
|
||||
|
||||
if ( UTIL_IsPlayer( pHurt ) )
|
||||
UTIL_TakeDamage( pHurt, pev, pev, gSkillData.strooperDmgKick, DMG_CLUB );
|
||||
else if ( pHurt->v.euser4 != NULL )
|
||||
{
|
||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pHurt));
|
||||
pMonster->TakeDamage( pev, pev, gSkillData.strooperDmgKick, DMG_CLUB );
|
||||
}
|
||||
}
|
||||
|
||||
m_fRightClaw = !m_fRightClaw;
|
||||
}
|
||||
break;
|
||||
|
||||
case STROOPER_AE_CAUGHT_ENEMY:
|
||||
{
|
||||
if (FOkToSpeak())
|
||||
{
|
||||
SENTENCEG_PlayRndSz(ENT(pev), "ST_ALERT", STROOPER_SENTENCE_VOLUME, STROOPER_ATTN, 0, m_voicePitch);
|
||||
JustSpoke();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
default:
|
||||
CMHGrunt::HandleAnimEvent(pEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=========================================================
|
||||
// Spawn
|
||||
//=========================================================
|
||||
void CMStrooper::Spawn()
|
||||
{
|
||||
Precache();
|
||||
|
||||
SET_MODEL(ENT(pev), "models/strooper.mdl");
|
||||
UTIL_SetSize( pev, Vector(-24, -24, 0), Vector(24, 24, 72) );
|
||||
|
||||
pev->solid = SOLID_SLIDEBOX;
|
||||
pev->movetype = MOVETYPE_STEP;
|
||||
m_bloodColor = BLOOD_COLOR_GREEN;
|
||||
pev->effects = 0;
|
||||
pev->health = gSkillData.strooperHealth;
|
||||
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||
m_MonsterState = MONSTERSTATE_NONE;
|
||||
m_flNextGrenadeCheck = gpGlobals->time + 1;
|
||||
m_flNextPainTime = gpGlobals->time;
|
||||
m_iSentence = STROOPER_SENT_NONE;
|
||||
|
||||
m_afCapability = bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
|
||||
|
||||
//m_fEnemyEluded = FALSE;
|
||||
m_fFirstEncounter = TRUE;// this is true when the grunt spawns, because he hasn't encountered an enemy yet.
|
||||
|
||||
m_HackedGunPos = Vector(0, 0, 55);
|
||||
|
||||
if (pev->weapons == 0)
|
||||
{
|
||||
// initialize to original values
|
||||
pev->weapons = STROOPER_SHOCKRIFLE | STROOPER_HANDGRENADE;
|
||||
}
|
||||
|
||||
m_cClipSize = gSkillData.strooperMaxCharge;
|
||||
|
||||
m_cAmmoLoaded = m_cClipSize;
|
||||
|
||||
m_fRightClaw = FALSE;
|
||||
|
||||
CMTalkMonster::g_talkWaitTime = 0;
|
||||
m_rechargeTime = gpGlobals->time + gSkillData.strooperRchgSpeed;
|
||||
m_blinkTime = gpGlobals->time + RANDOM_FLOAT(3.0f, 7.0f);
|
||||
|
||||
MonsterInit();
|
||||
|
||||
pev->classname = MAKE_STRING( "monster_shocktrooper" );
|
||||
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||
{
|
||||
// default name
|
||||
m_szMonsterName = MAKE_STRING( "Shock Trooper" );
|
||||
}
|
||||
}
|
||||
|
||||
void CMStrooper::MonsterThink()
|
||||
{
|
||||
if (m_cAmmoLoaded < m_cClipSize)
|
||||
{
|
||||
if (m_rechargeTime < gpGlobals->time)
|
||||
{
|
||||
m_cAmmoLoaded++;
|
||||
m_rechargeTime = gpGlobals->time + gSkillData.strooperRchgSpeed;
|
||||
}
|
||||
}
|
||||
if (m_blinkTime <= gpGlobals->time && pev->skin == 0) {
|
||||
pev->skin = 1;
|
||||
m_blinkTime = gpGlobals->time + RANDOM_FLOAT(3.0f, 7.0f);
|
||||
m_eyeChangeTime = gpGlobals->time + 0.1;
|
||||
}
|
||||
if (pev->skin != 0) {
|
||||
if (m_eyeChangeTime <= gpGlobals->time) {
|
||||
m_eyeChangeTime = gpGlobals->time + 0.1;
|
||||
pev->skin++;
|
||||
if (pev->skin > 3) {
|
||||
pev->skin = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
CMHGrunt::MonsterThink();
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// Precache - precaches all resources this monster needs
|
||||
//=========================================================
|
||||
void CMStrooper::Precache()
|
||||
{
|
||||
PRECACHE_MODEL("models/strooper.mdl");
|
||||
PRECACHE_MODEL("models/strooper_gibs.mdl");
|
||||
iStrooperMuzzleFlash = PRECACHE_MODEL(STROOPER_MUZZLEFLASH);
|
||||
PRECACHE_SOUND("shocktrooper/shock_trooper_attack.wav");
|
||||
|
||||
PRECACHE_SOUND("shocktrooper/shock_trooper_die1.wav");
|
||||
PRECACHE_SOUND("shocktrooper/shock_trooper_die2.wav");
|
||||
PRECACHE_SOUND("shocktrooper/shock_trooper_die3.wav");
|
||||
PRECACHE_SOUND("shocktrooper/shock_trooper_die4.wav");
|
||||
|
||||
PRECACHE_SOUND("shocktrooper/shock_trooper_pain1.wav");
|
||||
PRECACHE_SOUND("shocktrooper/shock_trooper_pain2.wav");
|
||||
PRECACHE_SOUND("shocktrooper/shock_trooper_pain3.wav");
|
||||
PRECACHE_SOUND("shocktrooper/shock_trooper_pain4.wav");
|
||||
PRECACHE_SOUND("shocktrooper/shock_trooper_pain5.wav");
|
||||
|
||||
PRECACHE_SOUND("weapons/shock_fire.wav");
|
||||
PRECACHE_SOUND("weapons/shock_impact.wav");
|
||||
|
||||
PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event
|
||||
|
||||
// shock_beam
|
||||
CMShock shock;
|
||||
shock.Precache();
|
||||
|
||||
// spore
|
||||
CMSporeGrenade spore;
|
||||
spore.Precache();
|
||||
|
||||
// shockroach
|
||||
CMShockRoach shockroach;
|
||||
shockroach.Precache();
|
||||
|
||||
// get voice pitch
|
||||
if (RANDOM_LONG(0, 1))
|
||||
m_voicePitch = 109 + RANDOM_LONG(0, 7);
|
||||
else
|
||||
m_voicePitch = 100;
|
||||
|
||||
m_iBrassShell = PRECACHE_MODEL("models/shell.mdl");// brass shell
|
||||
}
|
||||
|
||||
|
||||
//=========================================================
|
||||
// PainSound
|
||||
//=========================================================
|
||||
void CMStrooper::PainSound()
|
||||
{
|
||||
if (gpGlobals->time > m_flNextPainTime)
|
||||
{
|
||||
#if 0
|
||||
if (RANDOM_LONG(0, 99) < 5)
|
||||
{
|
||||
// pain sentences are rare
|
||||
if (FOkToSpeak())
|
||||
{
|
||||
SENTENCEG_PlayRndSz(ENT(pev), "HG_PAIN", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, PITCH_NORM);
|
||||
JustSpoke();
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
switch (RANDOM_LONG(0, 4))
|
||||
{
|
||||
case 0:
|
||||
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_pain1.wav", 1, ATTN_NORM);
|
||||
break;
|
||||
case 1:
|
||||
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_pain2.wav", 1, ATTN_NORM);
|
||||
break;
|
||||
case 2:
|
||||
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_pain3.wav", 1, ATTN_NORM);
|
||||
break;
|
||||
case 3:
|
||||
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_pain4.wav", 1, ATTN_NORM);
|
||||
break;
|
||||
case 4:
|
||||
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_pain5.wav", 1, ATTN_NORM);
|
||||
break;
|
||||
}
|
||||
|
||||
m_flNextPainTime = gpGlobals->time + 1;
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// DeathSound
|
||||
//=========================================================
|
||||
void CMStrooper::DeathSound()
|
||||
{
|
||||
switch (RANDOM_LONG(0, 3))
|
||||
{
|
||||
case 0:
|
||||
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_die1.wav", 1, ATTN_IDLE);
|
||||
break;
|
||||
case 1:
|
||||
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_die2.wav", 1, ATTN_IDLE);
|
||||
break;
|
||||
case 2:
|
||||
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_die3.wav", 1, ATTN_IDLE);
|
||||
break;
|
||||
case 3:
|
||||
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_die4.wav", 1, ATTN_IDLE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// TraceAttack - reimplemented in shock trooper because they never have helmets
|
||||
//=========================================================
|
||||
void CMStrooper::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
|
||||
{
|
||||
CMBaseMonster::TraceAttack(pevAttacker, flDamage, vecDir, ptr, bitsDamageType);
|
||||
}
|
||||
|
||||
void CMStrooper::DropShockRoach(bool gibbed)
|
||||
{
|
||||
Vector vecGunPos;
|
||||
Vector vecGunAngles;
|
||||
|
||||
GetAttachment(0, vecGunPos, vecGunAngles);
|
||||
SetBodygroup(GUN_GROUP, GUN_NONE);
|
||||
|
||||
Vector vecDropAngles;
|
||||
|
||||
// Remove any pitch.
|
||||
vecDropAngles.x = 0;
|
||||
vecDropAngles.y = vecGunAngles.y;
|
||||
vecDropAngles.z = 0;
|
||||
|
||||
Vector vecPos = pev->origin;
|
||||
if (gibbed)
|
||||
vecPos.z += 32;
|
||||
else
|
||||
vecPos.z += 48;
|
||||
|
||||
// now spawn a shockroach.
|
||||
//CBaseEntity* roach = CBaseEntity::Create( "monster_shockroach", vecPos, vecDropAngles );
|
||||
CMShockRoach *roach = CreateClassPtr((CMShockRoach *)NULL);
|
||||
if (roach != NULL)
|
||||
{
|
||||
roach->pev->origin = vecPos;
|
||||
roach->pev->angles = UTIL_VecToAngles( vecDropAngles );
|
||||
|
||||
// Initialize these for entities who don't link to the world
|
||||
roach->pev->absmin = roach->pev->origin - Vector(1,1,1);
|
||||
roach->pev->absmax = roach->pev->origin + Vector(1,1,1);
|
||||
|
||||
roach->Spawn();
|
||||
|
||||
if (ShouldFadeOnDeath())
|
||||
roach->pev->spawnflags |= SF_MONSTER_FADECORPSE;
|
||||
if (gibbed)
|
||||
{
|
||||
roach->pev->velocity = Vector(RANDOM_FLOAT(-100.0f, 100.0f), RANDOM_FLOAT(-100.0f, 100.0f), RANDOM_FLOAT(200.0f, 300.0f));
|
||||
roach->pev->avelocity = Vector(0, RANDOM_FLOAT(200.0f, 300.0f), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
roach->pev->velocity = Vector(RANDOM_FLOAT(-20.0f, 20.0f) , RANDOM_FLOAT(-20.0f, 20.0f), RANDOM_FLOAT(20.0f, 30.0f));
|
||||
roach->pev->avelocity = Vector(0, RANDOM_FLOAT(20.0f, 40.0f), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=========================================================
|
||||
// SetActivity
|
||||
//=========================================================
|
||||
void CMStrooper::SetActivity(Activity NewActivity)
|
||||
{
|
||||
int iSequence = ACTIVITY_NOT_AVAILABLE;
|
||||
void *pmodel = GET_MODEL_PTR(ENT(pev));
|
||||
|
||||
switch (NewActivity)
|
||||
{
|
||||
case ACT_RANGE_ATTACK1:
|
||||
// shocktrooper is either shooting standing or shooting crouched
|
||||
if (m_fStanding)
|
||||
{
|
||||
// get aimable sequence
|
||||
iSequence = LookupSequence("standing_mp5");
|
||||
}
|
||||
else
|
||||
{
|
||||
// get crouching shoot
|
||||
iSequence = LookupSequence("crouching_mp5");
|
||||
}
|
||||
break;
|
||||
case ACT_RANGE_ATTACK2:
|
||||
// shocktrooper is going to throw a grenade.
|
||||
|
||||
// get toss anim
|
||||
iSequence = LookupSequence("throwgrenade");
|
||||
break;
|
||||
|
||||
case ACT_RUN:
|
||||
if (pev->health <= STROOPER_LIMP_HEALTH)
|
||||
{
|
||||
// limp!
|
||||
iSequence = LookupActivity(ACT_RUN_HURT);
|
||||
}
|
||||
else
|
||||
{
|
||||
iSequence = LookupActivity(NewActivity);
|
||||
}
|
||||
break;
|
||||
case ACT_WALK:
|
||||
if (pev->health <= STROOPER_LIMP_HEALTH)
|
||||
{
|
||||
// limp!
|
||||
iSequence = LookupActivity(ACT_WALK_HURT);
|
||||
}
|
||||
else
|
||||
{
|
||||
iSequence = LookupActivity(NewActivity);
|
||||
}
|
||||
break;
|
||||
case ACT_IDLE:
|
||||
if (m_MonsterState == MONSTERSTATE_COMBAT)
|
||||
{
|
||||
NewActivity = ACT_IDLE_ANGRY;
|
||||
}
|
||||
iSequence = LookupActivity(NewActivity);
|
||||
break;
|
||||
default:
|
||||
iSequence = LookupActivity(NewActivity);
|
||||
break;
|
||||
}
|
||||
|
||||
m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present
|
||||
|
||||
// Set to the desired anim, or default anim if the desired is not present
|
||||
if (iSequence > ACTIVITY_NOT_AVAILABLE)
|
||||
{
|
||||
if (pev->sequence != iSequence || !m_fSequenceLoops)
|
||||
{
|
||||
pev->frame = 0;
|
||||
}
|
||||
|
||||
pev->sequence = iSequence; // Set to the reset anim (if it's there)
|
||||
ResetSequenceInfo();
|
||||
SetYawSpeed();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not available try to get default anim
|
||||
ALERT(at_console, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity);
|
||||
pev->sequence = 0; // Set to the reset anim (if it's there)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=========================================================
|
||||
// Get Schedule!
|
||||
//=========================================================
|
||||
Schedule_t *CMStrooper::GetSchedule(void)
|
||||
{
|
||||
|
||||
// clear old sentence
|
||||
m_iSentence = STROOPER_SENT_NONE;
|
||||
|
||||
// flying? If PRONE, barnacle has me. IF not, it's assumed I am rapelling.
|
||||
if (pev->movetype == MOVETYPE_FLY && m_MonsterState != MONSTERSTATE_PRONE)
|
||||
{
|
||||
if (pev->flags & FL_ONGROUND)
|
||||
{
|
||||
// just landed
|
||||
pev->movetype = MOVETYPE_STEP;
|
||||
return GetScheduleOfType(SCHED_STROOPER_REPEL_LAND);
|
||||
}
|
||||
else
|
||||
{
|
||||
// repel down a rope,
|
||||
if (m_MonsterState == MONSTERSTATE_COMBAT)
|
||||
return GetScheduleOfType(SCHED_STROOPER_REPEL_ATTACK);
|
||||
else
|
||||
return GetScheduleOfType(SCHED_STROOPER_REPEL);
|
||||
}
|
||||
}
|
||||
|
||||
switch (m_MonsterState)
|
||||
{
|
||||
case MONSTERSTATE_COMBAT:
|
||||
{
|
||||
// dead enemy
|
||||
if (HasConditions(bits_COND_ENEMY_DEAD))
|
||||
{
|
||||
// call base class, all code to handle dead enemies is centralized there.
|
||||
return CMBaseMonster::GetSchedule();
|
||||
}
|
||||
|
||||
// new enemy
|
||||
if (HasConditions(bits_COND_NEW_ENEMY))
|
||||
{
|
||||
//!!!KELLY - the leader of a squad of grunts has just seen the player or a
|
||||
// monster and has made it the squad's enemy. You
|
||||
// can check pev->flags for FL_CLIENT to determine whether this is the player
|
||||
// or a monster. He's going to immediately start
|
||||
// firing, though. If you'd like, we can make an alternate "first sight"
|
||||
// schedule where the leader plays a handsign anim
|
||||
// that gives us enough time to hear a short sentence or spoken command
|
||||
// before he starts pluggin away.
|
||||
if (FOkToSpeak())// && RANDOM_LONG(0,1))
|
||||
{
|
||||
if ((m_hEnemy != 0) && UTIL_IsPlayer( m_hEnemy ))
|
||||
// player
|
||||
SENTENCEG_PlayRndSz(ENT(pev), "ST_ALERT", STROOPER_SENTENCE_VOLUME, STROOPER_ATTN, 0, m_voicePitch);
|
||||
/*
|
||||
else if ((m_hEnemy != 0) &&
|
||||
(m_hEnemy->Classify() != CLASS_PLAYER_ALLY) &&
|
||||
(m_hEnemy->Classify() != CLASS_HUMAN_PASSIVE) &&
|
||||
(m_hEnemy->Classify() != CLASS_MACHINE))
|
||||
// monster
|
||||
SENTENCEG_PlayRndSz(ENT(pev), "ST_MONST", STROOPER_SENTENCE_VOLUME, STROOPER_ATTN, 0, m_voicePitch);
|
||||
*/
|
||||
JustSpoke();
|
||||
}
|
||||
|
||||
if (HasConditions(bits_COND_CAN_RANGE_ATTACK1))
|
||||
{
|
||||
return GetScheduleOfType(SCHED_STROOPER_SUPPRESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetScheduleOfType(SCHED_STROOPER_ESTABLISH_LINE_OF_FIRE);
|
||||
}
|
||||
}
|
||||
// no ammo
|
||||
else if (HasConditions(bits_COND_NO_AMMO_LOADED))
|
||||
{
|
||||
//!!!KELLY - this individual just realized he's out of bullet ammo.
|
||||
// He's going to try to find cover to run to and reload, but rarely, if
|
||||
// none is available, he'll drop and reload in the open here.
|
||||
return GetScheduleOfType(SCHED_STROOPER_COVER_AND_RELOAD);
|
||||
}
|
||||
|
||||
// damaged just a little
|
||||
else if (HasConditions(bits_COND_LIGHT_DAMAGE))
|
||||
{
|
||||
// if hurt:
|
||||
// 90% chance of taking cover
|
||||
// 10% chance of flinch.
|
||||
int iPercent = RANDOM_LONG(0, 99);
|
||||
|
||||
if (iPercent <= 90 && m_hEnemy != 0)
|
||||
{
|
||||
// only try to take cover if we actually have an enemy!
|
||||
|
||||
//!!!KELLY - this grunt was hit and is going to run to cover.
|
||||
if (FOkToSpeak()) // && RANDOM_LONG(0,1))
|
||||
{
|
||||
//SENTENCEG_PlayRndSz( ENT(pev), "HG_COVER", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
|
||||
m_iSentence = STROOPER_SENT_COVER;
|
||||
//JustSpoke();
|
||||
}
|
||||
return GetScheduleOfType(SCHED_TAKE_COVER_FROM_ENEMY);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetScheduleOfType(SCHED_SMALL_FLINCH);
|
||||
}
|
||||
}
|
||||
// can kick
|
||||
else if (HasConditions(bits_COND_CAN_MELEE_ATTACK1))
|
||||
{
|
||||
return GetScheduleOfType(SCHED_MELEE_ATTACK1);
|
||||
}
|
||||
|
||||
// can shoot
|
||||
if (HasConditions(bits_COND_CAN_RANGE_ATTACK1))
|
||||
{
|
||||
if (HasConditions(bits_COND_CAN_RANGE_ATTACK2))
|
||||
{
|
||||
// throw a grenade if can and no engage slots are available
|
||||
return GetScheduleOfType(SCHED_RANGE_ATTACK2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// hide!
|
||||
return GetScheduleOfType(SCHED_TAKE_COVER_FROM_ENEMY);
|
||||
}
|
||||
}
|
||||
// can't see enemy
|
||||
else if (HasConditions(bits_COND_ENEMY_OCCLUDED))
|
||||
{
|
||||
if (HasConditions(bits_COND_CAN_RANGE_ATTACK2))
|
||||
{
|
||||
//!!!KELLY - this grunt is about to throw or fire a grenade at the player. Great place for "fire in the hole" "frag out" etc
|
||||
if (FOkToSpeak())
|
||||
{
|
||||
SENTENCEG_PlayRndSz(ENT(pev), "ST_THROW", STROOPER_SENTENCE_VOLUME, STROOPER_ATTN, 0, m_voicePitch);
|
||||
JustSpoke();
|
||||
}
|
||||
return GetScheduleOfType(SCHED_RANGE_ATTACK2);
|
||||
}
|
||||
else
|
||||
{
|
||||
//!!!KELLY - grunt is going to stay put for a couple seconds to see if
|
||||
// the enemy wanders back out into the open, or approaches the
|
||||
// grunt's covered position. Good place for a taunt, I guess?
|
||||
if (FOkToSpeak() && RANDOM_LONG(0, 1))
|
||||
{
|
||||
SENTENCEG_PlayRndSz(ENT(pev), "ST_TAUNT", STROOPER_SENTENCE_VOLUME, STROOPER_ATTN, 0, m_voicePitch);
|
||||
JustSpoke();
|
||||
}
|
||||
return GetScheduleOfType(SCHED_STANDOFF);
|
||||
}
|
||||
}
|
||||
|
||||
if (HasConditions(bits_COND_SEE_ENEMY) && !HasConditions(bits_COND_CAN_RANGE_ATTACK1))
|
||||
{
|
||||
return GetScheduleOfType(SCHED_STROOPER_ESTABLISH_LINE_OF_FIRE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no special cases here, call the base class
|
||||
return CMBaseMonster::GetSchedule();
|
||||
}
|
||||
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
Schedule_t* CMStrooper::GetScheduleOfType(int Type)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case SCHED_TAKE_COVER_FROM_ENEMY:
|
||||
{
|
||||
if (RANDOM_LONG(0, 1))
|
||||
{
|
||||
return &slGruntTakeCover[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return &slGruntGrenadeCover[0];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
return CMHGrunt::GetScheduleOfType(Type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,33 @@ public:
|
||||
BOOL m_fRegisteredSound;// whether or not this grenade has issued its DANGER sound to the world sound list yet.
|
||||
};
|
||||
|
||||
// Contact/Timed spore grenade
|
||||
class CMSporeGrenade : public CMBaseMonster
|
||||
{
|
||||
public:
|
||||
void Precache(void);
|
||||
void Spawn(void);
|
||||
|
||||
static CMSporeGrenade *ShootTimed(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, bool ai);
|
||||
static CMSporeGrenade *ShootContact(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity);
|
||||
|
||||
void Explode(TraceResult *pTrace);
|
||||
|
||||
void EXPORT BounceTouch(edict_t *pOther);
|
||||
void EXPORT ExplodeTouch(edict_t *pOther);
|
||||
void EXPORT DangerSoundThink(void);
|
||||
void EXPORT Detonate(void);
|
||||
void EXPORT TumbleThink(void);
|
||||
|
||||
void BounceSound(void);
|
||||
void DangerSound();
|
||||
static void SpawnTrailParticles(const Vector& origin, const Vector& direction, int modelindex, int count, float speed, float noise);
|
||||
static void SpawnExplosionParticles(const Vector& origin, const Vector& direction, int modelindex, int count, float speed, float noise);
|
||||
|
||||
void UpdateOnRemove();
|
||||
|
||||
CMSprite* m_pSporeGlow;
|
||||
};
|
||||
|
||||
// constant items
|
||||
#define ITEM_HEALTHKIT 1
|
||||
|
||||
Reference in New Issue
Block a user