You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
663 lines
16 KiB
663 lines
16 KiB
/*** |
|
* |
|
* 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. |
|
* |
|
****/ |
|
|
|
//========================================================= |
|
// Hit groups! |
|
//========================================================= |
|
/* |
|
|
|
1 - Head |
|
2 - Stomach |
|
3 - Gun |
|
|
|
*/ |
|
|
|
#include "extdll.h" |
|
#include "plane.h" |
|
#include "util.h" |
|
#include "cbase.h" |
|
#include "monsters.h" |
|
#include "schedule.h" |
|
#include "animation.h" |
|
#include "squadmonster.h" |
|
#include "weapons.h" |
|
#include "talkmonster.h" |
|
#include "soundent.h" |
|
#include "effects.h" |
|
#include "customentity.h" |
|
#include "hgrunt.h" |
|
|
|
//========================================================= |
|
// monster-specific DEFINE's |
|
//========================================================= |
|
#define TERRORIST_CLIP_SIZE 36 // how many bullets in a clip? - NOTE: 3 round burst sound, so keep as 3 * x! |
|
#define TERRORIST_VOL 0.35 // volume of grunt sounds |
|
#define TERRORIST_ATTN ATTN_NORM // attenutation of grunt sentences |
|
#define TERRORIST_LIMP_HEALTH 20 |
|
#define TERRORIST_DMG_HEADSHOT ( DMG_BULLET | DMG_CLUB ) // damage types that can kill a grunt with a single headshot. |
|
#define TERRORIST_NUM_HEADS 2 // how many grunt heads are there? |
|
#define TERRORIST_MINIMUM_HEADSHOT_DAMAGE 15 // must do at least this much damage in one shot to head to score a headshot kill |
|
#define TERRORIST_SENTENCE_VOLUME (float)0.35 // volume of grunt sentences |
|
|
|
#define TERROR_AK47 ( 1 << 0) |
|
#define TERROR_HANDGRENADE ( 1 << 1) |
|
#define TERROR_GRENADELAUNCHER ( 1 << 2) |
|
#define TERROR_SHOTGUN ( 1 << 3) |
|
|
|
#define HEAD_GROUP 0 |
|
#define HEAD_GRUNT 0 |
|
#define HEAD_COMMANDER 1 |
|
#define HEAD_SHOTGUN 2 |
|
#define HEAD_M203 3 |
|
#define GUN_GROUP 1 |
|
#define GUN_MP5 0 |
|
#define GUN_SHOTGUN 1 |
|
#define GUN_NONE 2 |
|
|
|
enum |
|
{ |
|
TERROR_SENT_NONE = -1, |
|
TERROR_SENT_GREN = 0, |
|
TERROR_SENT_ALERT, |
|
TERROR_SENT_MONSTER, |
|
TERROR_SENT_COVER, |
|
TERROR_SENT_THROW, |
|
TERROR_SENT_CHARGE, |
|
TERROR_SENT_TAUNT, |
|
}; |
|
|
|
//========================================================= |
|
// Monster's Anim Events Go Here |
|
//========================================================= |
|
#define TERROR_AE_RELOAD ( 2 ) |
|
#define TERROR_AE_KICK ( 3 ) |
|
#define TERROR_AE_BURST1 ( 4 ) |
|
#define TERROR_AE_BURST2 ( 5 ) |
|
#define TERROR_AE_BURST3 ( 6 ) |
|
#define TERROR_AE_GREN_TOSS ( 7 ) |
|
#define TERROR_AE_GREN_LAUNCH ( 8 ) |
|
#define TERROR_AE_GREN_DROP ( 9 ) |
|
#define TERROR_AE_CAUGHT_ENEMY ( 10 ) // grunt established sight with an enemy (player only) that had previously eluded the squad. |
|
#define TERROR_AE_DROP_GUN ( 11 ) // grunt (probably dead) is dropping his mp5. |
|
|
|
// |
|
// Terrorist special flags. |
|
// |
|
#define TF_HUMAN_SENTRY 1 |
|
|
|
extern Schedule_t slGruntCombatFail[]; |
|
extern Schedule_t slGruntEstablishLineOfFire[]; |
|
extern Schedule_t slGruntTakeCover[]; |
|
extern Schedule_t slGruntGrenadeCover[]; |
|
extern Schedule_t slGruntTossGrenadeCover[]; |
|
extern Schedule_t slGruntTakeCoverFromBestSound[]; |
|
extern Schedule_t slGruntHideReload[]; |
|
extern Schedule_t slGruntRangeAttack1A[]; |
|
extern Schedule_t slGruntRangeAttack1B[]; |
|
|
|
|
|
//========================================================= |
|
// Terrorist |
|
//========================================================= |
|
class CTerrorist : public CHGrunt |
|
{ |
|
public: |
|
void Spawn(void); |
|
void Precache(void); |
|
void HandleAnimEvent(MonsterEvent_t* pEvent); |
|
void Killed(entvars_t *pevAttacker, int iGib); |
|
|
|
void Shoot(Vector vecSpread, int iBulletType); |
|
void ShootAK47(Vector vecSpread); |
|
|
|
void DeathSound(void); |
|
void PainSound(void); |
|
void GibMonster(void); |
|
|
|
BOOL IsHumanSentry() const; |
|
|
|
BOOL HasWeapon(); |
|
void DropWeapon(Vector vecVelocity = g_vecZero, Vector angVelocity = g_vecZero); |
|
|
|
void TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); |
|
|
|
Schedule_t *GetScheduleOfType(int Type); |
|
|
|
int Save(CSave &save); |
|
int Restore(CRestore &restore); |
|
static TYPEDESCRIPTION m_SaveData[]; |
|
|
|
static const char *pPainSounds[]; |
|
static const char *pDeathSounds[]; |
|
static const char *pBurstSounds[]; |
|
|
|
int m_iTerrorFlags; |
|
BOOL m_bHasWeapon; |
|
}; |
|
|
|
LINK_ENTITY_TO_CLASS(monster_terrorist, CTerrorist); |
|
LINK_ENTITY_TO_CLASS(monster_human_sentry, CTerrorist); |
|
|
|
TYPEDESCRIPTION CTerrorist::m_SaveData[] = |
|
{ |
|
DEFINE_FIELD(CTerrorist, m_iTerrorFlags, FIELD_INTEGER), |
|
DEFINE_FIELD(CTerrorist, m_bHasWeapon, FIELD_BOOLEAN), |
|
}; |
|
|
|
IMPLEMENT_SAVERESTORE(CTerrorist, CHGrunt); |
|
|
|
const char *CTerrorist::pPainSounds[] = |
|
{ |
|
"hgrunt/gr_pain1.wav", |
|
"hgrunt/gr_pain2.wav", |
|
"hgrunt/gr_pain3.wav", |
|
"hgrunt/gr_pain4.wav", |
|
"hgrunt/gr_pain5.wav", |
|
}; |
|
|
|
const char *CTerrorist::pDeathSounds[] = |
|
{ |
|
"hgrunt/gr_die1.wav", |
|
"hgrunt/gr_die2.wav", |
|
"hgrunt/gr_die3.wav", |
|
}; |
|
|
|
const char *CTerrorist::pBurstSounds[] = |
|
{ |
|
"weapons/hks1.wav", |
|
"weapons/hks2.wav", |
|
"weapons/hks3.wav", |
|
}; |
|
|
|
|
|
//========================================================= |
|
// Shoot |
|
//========================================================= |
|
void CTerrorist::Shoot(Vector vecSpread, int iBulletType) |
|
{ |
|
if (m_hEnemy == NULL) |
|
{ |
|
return; |
|
} |
|
|
|
Vector vecShootOrigin = GetGunPosition(); |
|
Vector vecShootDir = ShootAtEnemy(vecShootOrigin); |
|
|
|
UTIL_MakeVectors(pev->angles); |
|
|
|
Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40, 90) + gpGlobals->v_up * RANDOM_FLOAT(75, 200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40); |
|
EjectBrass(vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iBrassShell, TE_BOUNCE_SHELL); |
|
FireBullets(1, vecShootOrigin, vecShootDir, vecSpread, 2048, iBulletType); // shoot +-5 degrees |
|
|
|
pev->effects |= EF_MUZZLEFLASH; |
|
|
|
m_cAmmoLoaded--;// take away a bullet! |
|
|
|
Vector angDir = UTIL_VecToAngles(vecShootDir); |
|
SetBlending(0, angDir.x); |
|
} |
|
|
|
//========================================================= |
|
// ShootAK47 |
|
//========================================================= |
|
void CTerrorist::ShootAK47(Vector vecSpread) |
|
{ |
|
Shoot(VECTOR_CONE_10DEGREES, BULLET_MONSTER_MP5); |
|
|
|
EMIT_SOUND(ENT(pev), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pBurstSounds), 1, ATTN_NORM); |
|
} |
|
|
|
//========================================================= |
|
// HandleAnimEvent - catches the monster-specific messages |
|
// that occur when tagged animation frames are played. |
|
//========================================================= |
|
void CTerrorist::HandleAnimEvent(MonsterEvent_t *pEvent) |
|
{ |
|
Vector vecShootDir; |
|
Vector vecShootOrigin; |
|
|
|
switch (pEvent->event) |
|
{ |
|
case TERROR_AE_DROP_GUN: |
|
{ |
|
if (HasWeapon()) |
|
{ |
|
DropWeapon(); |
|
} |
|
break; |
|
} |
|
|
|
case TERROR_AE_BURST1: |
|
{ |
|
if (FBitSet(pev->weapons, TERROR_AK47)) |
|
{ |
|
ShootAK47( VECTOR_CONE_10DEGREES ); |
|
} |
|
else |
|
{ |
|
Shotgun(); |
|
|
|
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/sbarrel1.wav", 1, ATTN_NORM); |
|
} |
|
|
|
CSoundEnt::InsertSound(bits_SOUND_COMBAT, pev->origin, 384, 0.3); |
|
} |
|
break; |
|
|
|
case TERROR_AE_BURST2: |
|
case TERROR_AE_BURST3: |
|
ShootAK47( VECTOR_CONE_10DEGREES ); |
|
break; |
|
|
|
default: |
|
CHGrunt::HandleAnimEvent(pEvent); |
|
break; |
|
} |
|
} |
|
|
|
void CTerrorist::Killed(entvars_t *pevAttacker, int iGib) |
|
{ |
|
SetBodygroup(GUN_GROUP, GUN_NONE); |
|
|
|
CHGrunt::Killed(pevAttacker, iGib); |
|
} |
|
|
|
//========================================================= |
|
// Spawn |
|
//========================================================= |
|
void CTerrorist::Spawn() |
|
{ |
|
Precache(); |
|
|
|
SET_MODEL(ENT(pev), "models/terrorist.mdl"); |
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); |
|
|
|
pev->solid = SOLID_SLIDEBOX; |
|
pev->movetype = MOVETYPE_STEP; |
|
m_bloodColor = BLOOD_COLOR_RED; |
|
pev->effects = 0; |
|
pev->health = gSkillData.hgruntHealth; |
|
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 = TERROR_SENT_NONE; |
|
|
|
m_afCapability = bits_CAP_SQUAD | 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); |
|
|
|
m_bHasWeapon = TRUE; |
|
|
|
if (pev->weapons == 0) |
|
{ |
|
// initialize to original values |
|
pev->weapons = TERROR_AK47 | TERROR_HANDGRENADE; |
|
} |
|
|
|
// Prevent terrorist from using grenade launchers. |
|
pev->weapons &= ~TERROR_GRENADELAUNCHER; |
|
|
|
if (FBitSet(pev->weapons, TERROR_SHOTGUN)) |
|
{ |
|
SetBodygroup(GUN_GROUP, GUN_SHOTGUN); |
|
m_cClipSize = SHOTGUN_MAX_CLIP; |
|
} |
|
else |
|
{ |
|
m_cClipSize = TERRORIST_CLIP_SIZE; |
|
} |
|
m_cAmmoLoaded = m_cClipSize; |
|
|
|
m_iTerrorFlags = 0; |
|
|
|
if (FClassnameIs(pev, "monster_human_sentry")) |
|
{ |
|
m_iTerrorFlags |= TF_HUMAN_SENTRY; |
|
} |
|
|
|
CTalkMonster::g_talkWaitTime = 0; |
|
|
|
MonsterInit(); |
|
} |
|
|
|
//========================================================= |
|
// Precache - precaches all resources this monster needs |
|
//========================================================= |
|
void CTerrorist::Precache() |
|
{ |
|
PRECACHE_MODEL("models/terrorist.mdl"); |
|
|
|
PRECACHE_SOUND_ARRAY( pPainSounds ); |
|
PRECACHE_SOUND_ARRAY( pDeathSounds ); |
|
PRECACHE_SOUND_ARRAY( pBurstSounds ); |
|
|
|
PRECACHE_SOUND("hgrunt/gr_reload1.wav"); |
|
|
|
PRECACHE_SOUND("weapons/sbarrel1.wav"); |
|
|
|
PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event |
|
|
|
// 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 |
|
m_iShotgunShell = PRECACHE_MODEL("models/shotgunshell.mdl"); |
|
} |
|
|
|
//========================================================= |
|
// GibMonster - make gun fly through the air. |
|
//========================================================= |
|
void CTerrorist::GibMonster(void) |
|
{ |
|
if (HasWeapon() ) |
|
{ |
|
Vector velocity = Vector(RANDOM_FLOAT(-100, 100), RANDOM_FLOAT(-100, 100), RANDOM_FLOAT(200, 300)); |
|
Vector angVelocity = Vector(0, RANDOM_FLOAT(200, 400), 0); |
|
|
|
DropWeapon(velocity, angVelocity); |
|
} |
|
|
|
CBaseMonster::GibMonster(); |
|
} |
|
|
|
//========================================================= |
|
// PainSound |
|
//========================================================= |
|
void CTerrorist::PainSound(void) |
|
{ |
|
if (gpGlobals->time > m_flNextPainTime) |
|
{ |
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), 1, ATTN_NORM); |
|
|
|
m_flNextPainTime = gpGlobals->time + 1; |
|
} |
|
} |
|
|
|
//========================================================= |
|
// DeathSound |
|
//========================================================= |
|
void CTerrorist::DeathSound(void) |
|
{ |
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), 1, ATTN_IDLE); |
|
} |
|
|
|
//========================================================= |
|
// TraceAttack - make sure we're not taking it in the helmet |
|
//========================================================= |
|
void CTerrorist::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) |
|
{ |
|
if (pev->takedamage) |
|
{ |
|
// Human sentries are not allowed to drop weapons. |
|
if (!IsHumanSentry()) |
|
{ |
|
if (ptr->iHitgroup == HITGROUP_RIGHTARM) |
|
{ |
|
// ========================================== |
|
// Code changes for- Night at the Office: |
|
// ========================================== |
|
// |
|
// -Droppable guns. If terrorist is shot in the arm, he will drop |
|
// his gun and seek cover. Very useful in situation where player |
|
// is low on health/ammo or in a stealthy situation. Difficult to |
|
// get an arm shot while in combat, due to stance of the terrorist. |
|
|
|
if (HasWeapon()) |
|
{ |
|
Vector velocity = Vector(RANDOM_FLOAT(-10, 10), RANDOM_FLOAT(-10, 10), RANDOM_FLOAT(30, 40)); |
|
Vector angVelocity = Vector(0, RANDOM_FLOAT(10, 20), 0); |
|
|
|
DropWeapon(velocity, angVelocity); |
|
|
|
// Remove ability to shoot at enemy, now that we dropped our weapon. |
|
m_afCapability &= ~bits_CAP_RANGE_ATTACK1; |
|
} |
|
} |
|
} |
|
// check for helmet shot |
|
else if (ptr->iHitgroup == 11) |
|
{ |
|
// it's head shot anyways |
|
ptr->iHitgroup = HITGROUP_HEAD; |
|
} |
|
|
|
} |
|
|
|
CSquadMonster::TraceAttack(pevAttacker, flDamage, vecDir, ptr, bitsDamageType); |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
Schedule_t* CTerrorist :: GetScheduleOfType ( int Type ) |
|
{ |
|
switch ( Type ) |
|
{ |
|
case SCHED_TAKE_COVER_FROM_ENEMY: |
|
{ |
|
// Human sentries are not allowed to take cover. |
|
if (IsHumanSentry()) |
|
{ |
|
return CSquadMonster::GetScheduleOfType( SCHED_COMBAT_FACE ); |
|
} |
|
else |
|
{ |
|
if (InSquad()) |
|
{ |
|
if (g_iSkillLevel == SKILL_HARD && HasConditions(bits_COND_CAN_RANGE_ATTACK2) && OccupySlot(bits_SLOTS_HGRUNT_GRENADE)) |
|
{ |
|
if (FOkToSpeak()) |
|
{ |
|
SENTENCEG_PlayRndSz(ENT(pev), "HG_THROW", TERRORIST_SENTENCE_VOLUME, TERRORIST_ATTN, 0, m_voicePitch); |
|
JustSpoke(); |
|
} |
|
return slGruntTossGrenadeCover; |
|
} |
|
else |
|
{ |
|
return &slGruntTakeCover[0]; |
|
} |
|
} |
|
else |
|
{ |
|
if (HasWeapon()) |
|
{ |
|
if (RANDOM_LONG(0, 1)) |
|
{ |
|
return &slGruntTakeCover[0]; |
|
} |
|
else |
|
{ |
|
return &slGruntGrenadeCover[0]; |
|
} |
|
} |
|
else |
|
{ |
|
return &slGruntTakeCover[0]; |
|
} |
|
} |
|
} |
|
} |
|
case SCHED_TAKE_COVER_FROM_BEST_SOUND: |
|
{ |
|
// Human sentries are not allowed to run away from sounds. |
|
if (IsHumanSentry()) |
|
{ |
|
return GetScheduleOfType( SCHED_COWER ); |
|
} |
|
else |
|
{ |
|
return &slGruntTakeCoverFromBestSound[ 0 ]; |
|
} |
|
} |
|
case SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE: |
|
{ |
|
// Human sentries are not allowed to strafe to get a better shot. |
|
if (IsHumanSentry()) |
|
{ |
|
return &slGruntCombatFail[ 0 ]; |
|
} |
|
else |
|
{ |
|
return &slGruntEstablishLineOfFire[0]; |
|
} |
|
} |
|
break; |
|
case SCHED_RANGE_ATTACK1: |
|
{ |
|
if ( HasWeapon() ) |
|
{ |
|
// randomly stand or crouch |
|
if (RANDOM_LONG(0, 9) == 0) |
|
m_fStanding = RANDOM_LONG(0, 1); |
|
|
|
if (m_fStanding) |
|
return &slGruntRangeAttack1B[0]; |
|
else |
|
return &slGruntRangeAttack1A[0]; |
|
} |
|
else |
|
{ |
|
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); |
|
} |
|
} |
|
|
|
case SCHED_GRUNT_COVER_AND_RELOAD: |
|
{ |
|
// Human sentries can only reload in situ. |
|
if (IsHumanSentry()) |
|
{ |
|
return CSquadMonster::GetScheduleOfType( SCHED_RELOAD ); |
|
} |
|
else |
|
{ |
|
return &slGruntHideReload[ 0 ]; |
|
} |
|
} |
|
default: |
|
{ |
|
return CHGrunt :: GetScheduleOfType ( Type ); |
|
} |
|
} |
|
} |
|
|
|
BOOL CTerrorist::IsHumanSentry() const |
|
{ |
|
return (m_iTerrorFlags & TF_HUMAN_SENTRY); |
|
} |
|
|
|
BOOL CTerrorist::HasWeapon() |
|
{ |
|
return m_bHasWeapon; /* (GetBodygroup(GUN_GROUP) != GUN_NONE)*/; |
|
} |
|
|
|
void CTerrorist::DropWeapon(Vector vecVelocity, Vector angVelocity) |
|
{ |
|
Vector vecGunPos; |
|
Vector vecGunAngles; |
|
|
|
CBaseEntity *pGun; |
|
GetAttachment(0, vecGunPos, vecGunAngles); |
|
|
|
// switch to body group with no gun. |
|
SetBodygroup(GUN_GROUP, GUN_NONE); |
|
|
|
// now spawn a gun. |
|
if (FBitSet(pev->weapons, TERROR_SHOTGUN)) |
|
{ |
|
pGun = DropItem("weapon_shotgun", vecGunPos, vecGunAngles); |
|
} |
|
else |
|
{ |
|
pGun = DropItem("weapon_9mmAR", vecGunPos, vecGunAngles); |
|
} |
|
|
|
if (pGun) |
|
{ |
|
pGun->pev->velocity = vecVelocity; |
|
pGun->pev->avelocity = angVelocity; |
|
} |
|
|
|
m_bHasWeapon = FALSE; |
|
} |
|
|
|
|
|
//========================================================= |
|
// DEAD TERRORIST PROP |
|
//========================================================= |
|
class CDeadTerrorist : public CDeadHGrunt |
|
{ |
|
public: |
|
void Spawn(void); |
|
}; |
|
|
|
LINK_ENTITY_TO_CLASS(monster_terrorist_dead, CDeadTerrorist); |
|
|
|
//========================================================= |
|
// ********** DeadTerrorist SPAWN ********** |
|
//========================================================= |
|
void CDeadTerrorist::Spawn(void) |
|
{ |
|
PRECACHE_MODEL("models/terrorist.mdl"); |
|
SET_MODEL(ENT(pev), "models/terrorist.mdl"); |
|
|
|
pev->effects = 0; |
|
pev->yaw_speed = 8; |
|
pev->sequence = 0; |
|
m_bloodColor = BLOOD_COLOR_RED; |
|
|
|
pev->sequence = LookupSequence(m_szPoses[m_iPose]); |
|
|
|
if (pev->sequence == -1) |
|
{ |
|
ALERT(at_console, "Dead terrorist with bad pose\n"); |
|
} |
|
|
|
// Corpses have less health |
|
pev->health = 8; |
|
|
|
// map old bodies onto new bodies |
|
switch (pev->body) |
|
{ |
|
case 0: // Grunt with Gun |
|
pev->body = 0; |
|
pev->skin = 0; |
|
SetBodygroup(GUN_GROUP, GUN_MP5); |
|
break; |
|
case 1: // Commander with Gun |
|
pev->body = 0; |
|
pev->skin = 0; |
|
SetBodygroup(GUN_GROUP, GUN_MP5); |
|
break; |
|
case 2: // Grunt no Gun |
|
pev->body = 0; |
|
pev->skin = 0; |
|
SetBodygroup(GUN_GROUP, GUN_NONE); |
|
break; |
|
case 3: // Commander no Gun |
|
pev->body = 0; |
|
pev->skin = 0; |
|
SetBodygroup(GUN_GROUP, GUN_NONE); |
|
break; |
|
} |
|
|
|
MonsterInitDead(); |
|
}
|
|
|