Add monster_robogrunt.
This commit is contained in:
@@ -1660,4 +1660,39 @@ public:
|
|||||||
float m_flMinigunSpinTime;
|
float m_flMinigunSpinTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Robo Grunt
|
||||||
|
//=========================================================
|
||||||
|
class CMRGrunt : public CMHGrunt
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int Classify(void);
|
||||||
|
|
||||||
|
BOOL FOkToSpeak(void);
|
||||||
|
|
||||||
|
void Spawn( void );
|
||||||
|
void Precache( void );
|
||||||
|
|
||||||
|
void DeathSound(void);
|
||||||
|
void PainSound(void);
|
||||||
|
void IdleSound(void);
|
||||||
|
|
||||||
|
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
|
||||||
|
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
|
||||||
|
|
||||||
|
void RunAI(void);
|
||||||
|
|
||||||
|
void Killed(entvars_t *pevAttacker, int iGib);
|
||||||
|
void GibMonster();
|
||||||
|
|
||||||
|
void EXPORT SparkTouch(edict_t *pOther);
|
||||||
|
void EXPORT StartGib(void);
|
||||||
|
|
||||||
|
float m_flNextSpark;
|
||||||
|
float m_flNextDischarge;
|
||||||
|
float m_flActiveDischarge;
|
||||||
|
|
||||||
|
int m_iBodyGibs;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // BASEMONSTER_H
|
#endif // BASEMONSTER_H
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ monster_type_t monster_types[]=
|
|||||||
"monster_baby_voltigore", FALSE,
|
"monster_baby_voltigore", FALSE,
|
||||||
"monster_babygarg", FALSE, // Sven Co-op Monsters
|
"monster_babygarg", FALSE, // Sven Co-op Monsters
|
||||||
"monster_hwgrunt", FALSE,
|
"monster_hwgrunt", FALSE,
|
||||||
|
"monster_robogrunt", FALSE,
|
||||||
"info_node", FALSE, // Nodes
|
"info_node", FALSE, // Nodes
|
||||||
"info_node_air", FALSE,
|
"info_node_air", FALSE,
|
||||||
"", FALSE
|
"", FALSE
|
||||||
@@ -632,6 +633,7 @@ bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_i
|
|||||||
case 25: monsters[monster_index].pMonster = CreateClassPtr((CMBabyVoltigore *)NULL); break;
|
case 25: monsters[monster_index].pMonster = CreateClassPtr((CMBabyVoltigore *)NULL); break;
|
||||||
case 26: monsters[monster_index].pMonster = CreateClassPtr((CMBabyGargantua *)NULL); break;
|
case 26: monsters[monster_index].pMonster = CreateClassPtr((CMBabyGargantua *)NULL); break;
|
||||||
case 27: monsters[monster_index].pMonster = CreateClassPtr((CMHWGrunt *)NULL); break;
|
case 27: monsters[monster_index].pMonster = CreateClassPtr((CMHWGrunt *)NULL); break;
|
||||||
|
case 28: monsters[monster_index].pMonster = CreateClassPtr((CMRGrunt *)NULL); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (monsters[monster_index].pMonster == NULL)
|
if (monsters[monster_index].pMonster == NULL)
|
||||||
@@ -1319,6 +1321,7 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
|||||||
CMBabyVoltigore babyvoltigore;
|
CMBabyVoltigore babyvoltigore;
|
||||||
CMBabyGargantua babygargantua;
|
CMBabyGargantua babygargantua;
|
||||||
CMHWGrunt hwgrunt;
|
CMHWGrunt hwgrunt;
|
||||||
|
CMRGrunt rgrunt;
|
||||||
|
|
||||||
g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" );
|
g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" );
|
||||||
|
|
||||||
@@ -1364,6 +1367,7 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
|||||||
case 25: babyvoltigore.Precache(); break;
|
case 25: babyvoltigore.Precache(); break;
|
||||||
case 26: babygargantua.Precache(); break;
|
case 26: babygargantua.Precache(); break;
|
||||||
case 27: hwgrunt.Precache(); break;
|
case 27: hwgrunt.Precache(); break;
|
||||||
|
case 28: rgrunt.Precache(); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,13 +81,52 @@ void CMShower::Touch( CMBaseEntity *pOther )
|
|||||||
pev->speed = 0;
|
pev->speed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Puff of Smoke
|
||||||
|
class CSmoker : public CMBaseEntity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn( void );
|
||||||
|
void Think( void );
|
||||||
|
};
|
||||||
|
|
||||||
|
void CSmoker::Spawn( void )
|
||||||
|
{
|
||||||
|
pev->movetype = MOVETYPE_NONE;
|
||||||
|
pev->nextthink = gpGlobals->time;
|
||||||
|
pev->solid = SOLID_NOT;
|
||||||
|
UTIL_SetSize(pev, g_vecZero, g_vecZero );
|
||||||
|
pev->effects |= EF_NODRAW;
|
||||||
|
pev->angles = g_vecZero;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSmoker::Think( void )
|
||||||
|
{
|
||||||
|
// lots of smoke
|
||||||
|
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
|
||||||
|
WRITE_BYTE( TE_SMOKE );
|
||||||
|
WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -pev->dmg, pev->dmg ));
|
||||||
|
WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -pev->dmg, pev->dmg ));
|
||||||
|
WRITE_COORD( pev->origin.z);
|
||||||
|
WRITE_SHORT( g_sModelIndexSmoke );
|
||||||
|
WRITE_BYTE( RANDOM_LONG(pev->scale, pev->scale * 1.1) );
|
||||||
|
WRITE_BYTE( RANDOM_LONG(8,14) ); // framerate
|
||||||
|
MESSAGE_END();
|
||||||
|
|
||||||
|
pev->health--;
|
||||||
|
if ( pev->health > 0 )
|
||||||
|
pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.1, 0.2);
|
||||||
|
else
|
||||||
|
UTIL_Remove( this->edict() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explosion
|
||||||
class CMEnvExplosion : public CMBaseMonster
|
class CMEnvExplosion : public CMBaseMonster
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void Spawn( );
|
void Spawn( );
|
||||||
void EXPORT Smoke ( void );
|
void EXPORT Smoke ( void );
|
||||||
void KeyValue( KeyValueData *pkvd );
|
void KeyValue( KeyValueData *pkvd );
|
||||||
void DelayUse( void );
|
void EXPORT DelayUse( void );
|
||||||
void Use( CMBaseEntity *pActivator, CMBaseEntity *pCaller, USE_TYPE useType, float value );
|
void Use( CMBaseEntity *pActivator, CMBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||||
|
|
||||||
int m_iMagnitude;// how large is the fireball? how much damage?
|
int m_iMagnitude;// how large is the fireball? how much damage?
|
||||||
@@ -259,7 +298,8 @@ void CMEnvExplosion::Smoke( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Stock to quickly create a one-time explosion
|
// Stocks:
|
||||||
|
// Create a one-time explosion
|
||||||
void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, int flags, float delay )
|
void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, int flags, float delay )
|
||||||
{
|
{
|
||||||
KeyValueData kvd;
|
KeyValueData kvd;
|
||||||
@@ -287,15 +327,19 @@ void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwne
|
|||||||
pExplosion->pev->spawnflags &= ~SF_ENVEXPLOSION_REPEATABLE;
|
pExplosion->pev->spawnflags &= ~SF_ENVEXPLOSION_REPEATABLE;
|
||||||
|
|
||||||
pExplosion->Spawn();
|
pExplosion->Spawn();
|
||||||
if ( delay > 0.0f )
|
|
||||||
{
|
|
||||||
//pExplosion->SetThink( &CMBaseEntity::SUB_CallUseToggle ); // i don't trust you
|
|
||||||
pExplosion->SetThink( &CMEnvExplosion::DelayUse );
|
pExplosion->SetThink( &CMEnvExplosion::DelayUse );
|
||||||
pExplosion->pev->nextthink = gpGlobals->time + delay;
|
pExplosion->pev->nextthink = gpGlobals->time + delay;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
// Emit smoke
|
||||||
|
void SmokeCreate( const Vector &origin, int amount, int size, int radius, float delay )
|
||||||
{
|
{
|
||||||
pExplosion->Use( NULL, NULL, USE_TOGGLE, 0 );
|
CMBaseEntity *pSmoker = CreateClassPtr((CSmoker *)NULL); // CMBaseEntity::Create( "env_smoker", pev->origin, g_vecZero, NULL );
|
||||||
}
|
UTIL_SetOrigin( pSmoker->pev, origin );
|
||||||
}
|
pSmoker->Spawn();
|
||||||
|
pSmoker->pev->health = amount; // number of smoke balls
|
||||||
|
pSmoker->pev->scale = size; // size in 0.1x - size 10 = x1.0
|
||||||
|
pSmoker->pev->dmg = radius; // radial distribution
|
||||||
|
pSmoker->pev->nextthink = gpGlobals->time + delay; // Start in ... seconds
|
||||||
}
|
}
|
||||||
@@ -28,5 +28,6 @@ extern DLL_GLOBAL short g_sModelIndexSmoke;
|
|||||||
extern DLL_GLOBAL short g_sModelIndexTinySpit;
|
extern DLL_GLOBAL short g_sModelIndexTinySpit;
|
||||||
|
|
||||||
extern void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, int flags, float delay );
|
extern void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, int flags, float delay );
|
||||||
|
extern void SmokeCreate( const Vector &origin, int amount, int size, int radius, float delay );
|
||||||
|
|
||||||
#endif //EXPLODE_H
|
#endif //EXPLODE_H
|
||||||
|
|||||||
@@ -62,13 +62,6 @@ const float GARG_ATTACKDIST = 80.0;
|
|||||||
int gStompSprite = 0, gGargGibModel = 0;
|
int gStompSprite = 0, gGargGibModel = 0;
|
||||||
void SpawnExplosion( Vector center, float randomRange, float time, int magnitude, edict_t *owner );
|
void SpawnExplosion( Vector center, float randomRange, float time, int magnitude, edict_t *owner );
|
||||||
|
|
||||||
class CSmoker : public CMBaseEntity
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void Spawn( void );
|
|
||||||
void Think( void );
|
|
||||||
};
|
|
||||||
|
|
||||||
// Spiral Effect
|
// Spiral Effect
|
||||||
class CSpiral : public CMBaseEntity
|
class CSpiral : public CMBaseEntity
|
||||||
{
|
{
|
||||||
@@ -781,7 +774,7 @@ void CMGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector ve
|
|||||||
// if ( RANDOM_LONG(0,100) < 25 )
|
// if ( RANDOM_LONG(0,100) < 25 )
|
||||||
// EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, pRicSounds[ RANDOM_LONG(0,ARRAYSIZE(pRicSounds)-1) ], 1.0, ATTN_NORM, 0, PITCH_NORM );
|
// EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, pRicSounds[ RANDOM_LONG(0,ARRAYSIZE(pRicSounds)-1) ], 1.0, ATTN_NORM, 0, PITCH_NORM );
|
||||||
}
|
}
|
||||||
flDamage *= (1.01f - gSkillData.gargantuaArmor); // Again, for mods (see below)
|
// flDamage *= (1.00f - gSkillData.gargantuaArmor); // in here...?
|
||||||
}
|
}
|
||||||
|
|
||||||
CMBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
|
CMBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
|
||||||
@@ -789,13 +782,12 @@ void CMGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector ve
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int CMGargantua::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
int CMGargantua::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
||||||
{
|
{
|
||||||
if ( IsAlive() )
|
if ( IsAlive() )
|
||||||
{
|
{
|
||||||
if ( !(bitsDamageType & GARG_DAMAGE) )
|
if ( !(bitsDamageType & GARG_DAMAGE) )
|
||||||
flDamage *= (1.01f - gSkillData.gargantuaArmor); // This is for mods that don't use explosives of any kind or do not work with the gargantua.
|
flDamage *= (1.00f - gSkillData.gargantuaArmor); // This is for mods that don't use explosives of any kind or do not work with the gargantua.
|
||||||
|
|
||||||
// Always set
|
// Always set
|
||||||
SetConditions( bits_COND_LIGHT_DAMAGE );
|
SetConditions( bits_COND_LIGHT_DAMAGE );
|
||||||
@@ -822,13 +814,11 @@ void CMGargantua::DeathEffect( void )
|
|||||||
position.z += 15;
|
position.z += 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
CMBaseEntity *pSmoker = CreateClassPtr((CSmoker *)NULL); // CMBaseEntity::Create( "env_smoker", pev->origin, g_vecZero, NULL );
|
// 1 smoke balls
|
||||||
UTIL_SetOrigin( pSmoker->pev, pev->origin );
|
// 4.6X normal size
|
||||||
pSmoker->Spawn();
|
// 0 radial distribution
|
||||||
pSmoker->pev->health = 1; // 1 smoke balls
|
// start in 2.5 seconds
|
||||||
pSmoker->pev->scale = 46; // 4.6X normal size
|
SmokeCreate( pev->origin, 1, 46, 0, 2.5 );
|
||||||
pSmoker->pev->dmg = 0; // 0 radial distribution
|
|
||||||
pSmoker->pev->nextthink = gpGlobals->time + 2.5; // Start in 2.5 seconds
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1167,38 +1157,6 @@ void CMGargantua::RunTask( Task_t *pTask )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSmoker::Spawn( void )
|
|
||||||
{
|
|
||||||
pev->movetype = MOVETYPE_NONE;
|
|
||||||
pev->nextthink = gpGlobals->time;
|
|
||||||
pev->solid = SOLID_NOT;
|
|
||||||
UTIL_SetSize(pev, g_vecZero, g_vecZero );
|
|
||||||
pev->effects |= EF_NODRAW;
|
|
||||||
pev->angles = g_vecZero;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CSmoker::Think( void )
|
|
||||||
{
|
|
||||||
// lots of smoke
|
|
||||||
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
|
|
||||||
WRITE_BYTE( TE_SMOKE );
|
|
||||||
WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -pev->dmg, pev->dmg ));
|
|
||||||
WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -pev->dmg, pev->dmg ));
|
|
||||||
WRITE_COORD( pev->origin.z);
|
|
||||||
WRITE_SHORT( g_sModelIndexSmoke );
|
|
||||||
WRITE_BYTE( RANDOM_LONG(pev->scale, pev->scale * 1.1) );
|
|
||||||
WRITE_BYTE( RANDOM_LONG(8,14) ); // framerate
|
|
||||||
MESSAGE_END();
|
|
||||||
|
|
||||||
pev->health--;
|
|
||||||
if ( pev->health > 0 )
|
|
||||||
pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.1, 0.2);
|
|
||||||
else
|
|
||||||
UTIL_Remove( this->edict() );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CSpiral::Spawn( void )
|
void CSpiral::Spawn( void )
|
||||||
{
|
{
|
||||||
pev->movetype = MOVETYPE_NONE;
|
pev->movetype = MOVETYPE_NONE;
|
||||||
|
|||||||
@@ -198,6 +198,10 @@ SOURCE=.\houndeye.cpp
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\hwgrunt.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\islave.cpp
|
SOURCE=.\islave.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
@@ -234,6 +238,10 @@ SOURCE=.\pitdrone.cpp
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\rgrunt.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\scientist.cpp
|
SOURCE=.\scientist.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|||||||
423
src/dlls/rgrunt.cpp
Normal file
423
src/dlls/rgrunt.cpp
Normal file
@@ -0,0 +1,423 @@
|
|||||||
|
/***
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
//=========================================================
|
||||||
|
// Robo Grunt
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
#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 "explode.h"
|
||||||
|
#include "customentity.h"
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// monster-specific DEFINE's
|
||||||
|
//=========================================================
|
||||||
|
#define RGRUNT_CLIP_SIZE 36 // how many bullets in a clip? - NOTE: 3 round burst sound, so keep as 3 * x!
|
||||||
|
|
||||||
|
// Weapon flags
|
||||||
|
#define RGRUNT_9MMAR (1 << 0)
|
||||||
|
#define RGRUNT_HANDGRENADE (1 << 1)
|
||||||
|
#define RGRUNT_GRENADELAUNCHER (1 << 2)
|
||||||
|
#define RGRUNT_SHOTGUN (1 << 3)
|
||||||
|
|
||||||
|
// Body groups
|
||||||
|
#define GUN_GROUP 2
|
||||||
|
|
||||||
|
// Gun values
|
||||||
|
#define GUN_MP5 0
|
||||||
|
#define GUN_SHOTGUN 1
|
||||||
|
#define GUN_NONE 2
|
||||||
|
|
||||||
|
// How many sparks to emit when low on health
|
||||||
|
#define RGRUNT_MAX_SPARKS 5
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// These sounds are muted for Robo Grunts
|
||||||
|
//=========================================================
|
||||||
|
BOOL CMRGrunt::FOkToSpeak(void)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMRGrunt::IdleSound(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMRGrunt::PainSound(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// DeathSound
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::DeathSound(void)
|
||||||
|
{
|
||||||
|
switch ( RANDOM_LONG(0,1) )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
EMIT_SOUND( ENT(pev), CHAN_VOICE, "turret/tu_die.wav", 1, ATTN_IDLE );
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
EMIT_SOUND( ENT(pev), CHAN_VOICE, "turret/tu_die2.wav", 1, ATTN_IDLE );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use this spot to activate the explosion
|
||||||
|
int duration = RANDOM_LONG( 3, 9 );
|
||||||
|
|
||||||
|
/* Smoke effect */
|
||||||
|
// variable smoke balls
|
||||||
|
// 1.7X normal size
|
||||||
|
// 0 radial distribution
|
||||||
|
// instant start
|
||||||
|
SmokeCreate( pev->origin, duration * 7, 17, 0, 0 );
|
||||||
|
|
||||||
|
// "Gib"
|
||||||
|
pev->nextthink = gpGlobals->time + duration;
|
||||||
|
SetThink( &CMRGrunt::StartGib );
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Classify - indicates this monster's place in the
|
||||||
|
// relationship table.
|
||||||
|
//=========================================================
|
||||||
|
int CMRGrunt::Classify(void)
|
||||||
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
|
return CLASS_HUMAN_MILITARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Killed - Explode a few seconds after death
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::Killed(entvars_t *pevAttacker, int iGib)
|
||||||
|
{
|
||||||
|
// Turn off electricity
|
||||||
|
if ( m_flActiveDischarge != 0 )
|
||||||
|
{
|
||||||
|
pev->renderfx = kRenderFxNone;
|
||||||
|
m_flActiveDischarge = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disallow this monster to fade away, need to keep it around for the explosion
|
||||||
|
pev->owner = 0;
|
||||||
|
pev->spawnflags &= ~SF_MONSTER_FADECORPSE;
|
||||||
|
pev->solid = SOLID_NOT; // stop interacting with the world
|
||||||
|
|
||||||
|
CMBaseMonster::Killed(pevAttacker, iGib);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMRGrunt::StartGib(void)
|
||||||
|
{
|
||||||
|
// derp
|
||||||
|
GibMonster();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// GibMonster - Boom!
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::GibMonster()
|
||||||
|
{
|
||||||
|
// Don't call this more times than needed
|
||||||
|
if ( pev->iuser1 != 0 )
|
||||||
|
return;
|
||||||
|
pev->iuser1 = 1;
|
||||||
|
|
||||||
|
Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5;
|
||||||
|
|
||||||
|
// Explosion
|
||||||
|
ExplosionCreate( vecSpot, g_vecZero, ENT(pev), 128, 0, 0 );
|
||||||
|
|
||||||
|
// Wreckage
|
||||||
|
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot );
|
||||||
|
WRITE_BYTE( TE_BREAKMODEL );
|
||||||
|
|
||||||
|
// position
|
||||||
|
WRITE_COORD( vecSpot.x );
|
||||||
|
WRITE_COORD( vecSpot.y );
|
||||||
|
WRITE_COORD( vecSpot.z );
|
||||||
|
|
||||||
|
// size
|
||||||
|
WRITE_COORD( 96 );
|
||||||
|
WRITE_COORD( 96 );
|
||||||
|
WRITE_COORD( 16 );
|
||||||
|
|
||||||
|
// velocity
|
||||||
|
WRITE_COORD( 0 );
|
||||||
|
WRITE_COORD( 0 );
|
||||||
|
WRITE_COORD( 30 );
|
||||||
|
|
||||||
|
// randomization
|
||||||
|
WRITE_BYTE( 15 );
|
||||||
|
|
||||||
|
// Model
|
||||||
|
WRITE_SHORT( m_iBodyGibs ); //model id#
|
||||||
|
|
||||||
|
// # of shards
|
||||||
|
WRITE_BYTE( 35 );
|
||||||
|
|
||||||
|
// duration
|
||||||
|
WRITE_BYTE( 100 );// 5.0 seconds
|
||||||
|
|
||||||
|
// flags
|
||||||
|
WRITE_BYTE( BREAK_METAL );
|
||||||
|
MESSAGE_END();
|
||||||
|
|
||||||
|
SetThink( &CMBaseEntity::SUB_Remove );
|
||||||
|
pev->nextthink = gpGlobals->time;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// RunAI - Robo Grunt emits sparks when its low on health.
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::RunAI(void)
|
||||||
|
{
|
||||||
|
CMBaseMonster::RunAI();
|
||||||
|
|
||||||
|
if ( pev->health <= ( pev->max_health / 10 ) ) // below 10% health
|
||||||
|
{
|
||||||
|
// Spark ON
|
||||||
|
if ( gpGlobals->time > m_flNextSpark )
|
||||||
|
{
|
||||||
|
// Code looks familiar? It's CBaseButton::DoSpark
|
||||||
|
for ( int spark_num = 0; spark_num < RGRUNT_MAX_SPARKS; spark_num++ )
|
||||||
|
{
|
||||||
|
Vector tmp = pev->origin + (pev->mins + pev->maxs) * 0.5; // grab center
|
||||||
|
tmp.x += RANDOM_FLOAT( -( pev->size.x / 2 ), pev->size.x / 2); // then randomize
|
||||||
|
tmp.y += RANDOM_FLOAT( -( pev->size.y / 2 ), pev->size.y / 2);
|
||||||
|
tmp.z += RANDOM_FLOAT( -( pev->size.z / 2 ), pev->size.z / 2);
|
||||||
|
UTIL_Sparks( tmp );
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( (int)(RANDOM_FLOAT(0,1) * 6) )
|
||||||
|
{
|
||||||
|
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark1.wav", 0.6, ATTN_NORM); break;
|
||||||
|
case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark2.wav", 0.6, ATTN_NORM); break;
|
||||||
|
case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark3.wav", 0.6, ATTN_NORM); break;
|
||||||
|
case 3: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark4.wav", 0.6, ATTN_NORM); break;
|
||||||
|
case 4: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark5.wav", 0.6, ATTN_NORM); break;
|
||||||
|
case 5: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark6.wav", 0.6, ATTN_NORM); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_flNextSpark = gpGlobals->time + 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Glow/Hurt ON
|
||||||
|
if ( gpGlobals->time > m_flNextDischarge )
|
||||||
|
{
|
||||||
|
// Turn on the electric glow
|
||||||
|
pev->renderfx = kRenderFxGlowShell;
|
||||||
|
pev->rendercolor = Vector( 100, 150, 250 ); // r, g, b
|
||||||
|
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_BODY, "debris/beamstart14.wav", 0.8, ATTN_NORM);
|
||||||
|
|
||||||
|
// Sustain the electricity for this long
|
||||||
|
m_flActiveDischarge = gpGlobals->time + RANDOM_FLOAT( 0.3, 0.6 );
|
||||||
|
|
||||||
|
// Discharge again in...
|
||||||
|
m_flNextDischarge = gpGlobals->time + RANDOM_FLOAT( 0.9, 2.7 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Glow/Hurt OFF
|
||||||
|
if ( gpGlobals->time > m_flActiveDischarge )
|
||||||
|
{
|
||||||
|
// Turn off electricity
|
||||||
|
pev->renderfx = kRenderFxNone;
|
||||||
|
m_flActiveDischarge = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// SparkTouch - Hurt players who come too close to it
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::SparkTouch( edict_t *pOther )
|
||||||
|
{
|
||||||
|
// No electricity, no harm
|
||||||
|
if ( m_flActiveDischarge == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Only affect players
|
||||||
|
if ( UTIL_IsPlayer( pOther ) )
|
||||||
|
{
|
||||||
|
// Because of Touch(), players are going to be hurt every server frame.
|
||||||
|
// Don't be bullshit like Sven Co-op, set the damage REALLY LOW.
|
||||||
|
UTIL_TakeDamage( pOther, pev, pev, 1, DMG_SHOCK );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// TraceAttack - Override for robo grunt
|
||||||
|
// Emit ricochet sparks if getting hurt from bullets
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )
|
||||||
|
{
|
||||||
|
// Absorb damage and emit ricochet if bullets or melee attacks are used
|
||||||
|
if ( bitsDamageType & ( DMG_BULLET | DMG_SLASH | DMG_CLUB ) )
|
||||||
|
{
|
||||||
|
if ( RANDOM_LONG( 0, 100 ) < 20 )
|
||||||
|
{
|
||||||
|
UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 0.5, 1.5 ) );
|
||||||
|
// EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, pRicSounds[ RANDOM_LONG(0,ARRAYSIZE(pRicSounds)-1) ], 1.0, ATTN_NORM, 0, PITCH_NORM );
|
||||||
|
}
|
||||||
|
flDamage *= (1.00f - gSkillData.rgruntArmor); // cut damage
|
||||||
|
}
|
||||||
|
// Lower protection against explosions
|
||||||
|
else if ( bitsDamageType & DMG_BLAST )
|
||||||
|
flDamage *= (1.00f - (gSkillData.rgruntArmor / 2.00f)); // 50% less protection
|
||||||
|
// No protection at all against other types of damages
|
||||||
|
|
||||||
|
CMBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// TakeDamage - Robo Grunts should not take cover as soon
|
||||||
|
// as they take damage.
|
||||||
|
//=========================================================
|
||||||
|
int CMRGrunt::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
||||||
|
{
|
||||||
|
return CMBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Spawn
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::Spawn()
|
||||||
|
{
|
||||||
|
Precache();
|
||||||
|
|
||||||
|
SET_MODEL(ENT(pev), "models/rgrunt.mdl");
|
||||||
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
pev->movetype = MOVETYPE_STEP;
|
||||||
|
m_bloodColor = DONT_BLEED;
|
||||||
|
pev->effects = 0;
|
||||||
|
pev->health = gSkillData.rgruntHealth;
|
||||||
|
pev->max_health = pev->health; // to determine when sparks should be emitted
|
||||||
|
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_flNextSpark = gpGlobals->time; // when to emit sparks again
|
||||||
|
m_flNextDischarge = gpGlobals->time; // when electric shell should activate
|
||||||
|
m_flActiveDischarge = 0; // how long to sustain the electricity
|
||||||
|
m_iSentence = -1;
|
||||||
|
|
||||||
|
//m_afCapability = bits_CAP_SQUAD | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// weapons not specified, randomize
|
||||||
|
switch(RANDOM_LONG(0, 2))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
pev->weapons = RGRUNT_9MMAR | RGRUNT_HANDGRENADE;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
pev->weapons = RGRUNT_SHOTGUN;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pev->weapons = RGRUNT_9MMAR | RGRUNT_GRENADELAUNCHER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FBitSet(pev->weapons, RGRUNT_SHOTGUN))
|
||||||
|
{
|
||||||
|
SetBodygroup(GUN_GROUP, GUN_SHOTGUN);
|
||||||
|
m_cClipSize = 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_cClipSize = RGRUNT_CLIP_SIZE;
|
||||||
|
}
|
||||||
|
m_cAmmoLoaded = m_cClipSize;
|
||||||
|
|
||||||
|
CMTalkMonster::g_talkWaitTime = 0;
|
||||||
|
|
||||||
|
MonsterInit();
|
||||||
|
|
||||||
|
SetTouch( &CMRGrunt::SparkTouch );
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_robogrunt" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Robo Grunt" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Precache - precaches all resources this monster needs
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::Precache()
|
||||||
|
{
|
||||||
|
PRECACHE_MODEL("models/rgrunt.mdl");
|
||||||
|
|
||||||
|
m_iBodyGibs = PRECACHE_MODEL( "models/metalplategibs_green.mdl" );
|
||||||
|
|
||||||
|
PRECACHE_SOUND("hgrunt/gr_mgun1.wav");
|
||||||
|
PRECACHE_SOUND("hgrunt/gr_mgun2.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("turret/tu_die.wav");
|
||||||
|
PRECACHE_SOUND("turret/tu_die2.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("buttons/spark1.wav");
|
||||||
|
PRECACHE_SOUND("buttons/spark2.wav");
|
||||||
|
PRECACHE_SOUND("buttons/spark3.wav");
|
||||||
|
PRECACHE_SOUND("buttons/spark4.wav");
|
||||||
|
PRECACHE_SOUND("buttons/spark5.wav");
|
||||||
|
PRECACHE_SOUND("buttons/spark6.wav");
|
||||||
|
PRECACHE_SOUND("debris/beamstart14.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("hgrunt/gr_reload1.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("weapons/glauncher.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
|
||||||
|
}
|
||||||
@@ -99,6 +99,8 @@ skill_cfg_t skill_cfg[] = {
|
|||||||
{"sk_babygarg_dmg_fire", &gSkillData.babygargDmgFire},
|
{"sk_babygarg_dmg_fire", &gSkillData.babygargDmgFire},
|
||||||
{"sk_babygarg_dmg_stomp", &gSkillData.babygargDmgStomp},
|
{"sk_babygarg_dmg_stomp", &gSkillData.babygargDmgStomp},
|
||||||
{"sk_hwgrunt_health", &gSkillData.hwgruntHealth},
|
{"sk_hwgrunt_health", &gSkillData.hwgruntHealth},
|
||||||
|
{"sk_rgrunt_health", &gSkillData.rgruntHealth},
|
||||||
|
{"sk_rgrunt_armor", &gSkillData.rgruntArmor},
|
||||||
{"sk_12mm_bullet", &gSkillData.monDmg9MM},
|
{"sk_12mm_bullet", &gSkillData.monDmg9MM},
|
||||||
{"sk_9mmAR_bullet", &gSkillData.monDmgMP5},
|
{"sk_9mmAR_bullet", &gSkillData.monDmgMP5},
|
||||||
{"sk_9mm_bullet", &gSkillData.monDmg12MM},
|
{"sk_9mm_bullet", &gSkillData.monDmg12MM},
|
||||||
@@ -290,6 +292,10 @@ void monster_skill_init(void)
|
|||||||
// Heavy Weapons Grunt
|
// Heavy Weapons Grunt
|
||||||
gSkillData.hwgruntHealth = 60.0f;
|
gSkillData.hwgruntHealth = 60.0f;
|
||||||
|
|
||||||
|
// Robo Grunt
|
||||||
|
gSkillData.rgruntHealth = 50.0f;
|
||||||
|
gSkillData.rgruntArmor = 0.75f;
|
||||||
|
|
||||||
// MONSTER WEAPONS
|
// MONSTER WEAPONS
|
||||||
gSkillData.monDmg9MM = 5.0f;
|
gSkillData.monDmg9MM = 5.0f;
|
||||||
gSkillData.monDmgMP5 = 4.0f;
|
gSkillData.monDmgMP5 = 4.0f;
|
||||||
|
|||||||
@@ -127,6 +127,9 @@ struct skilldata_t
|
|||||||
|
|
||||||
float hwgruntHealth;
|
float hwgruntHealth;
|
||||||
|
|
||||||
|
float rgruntHealth;
|
||||||
|
float rgruntArmor;
|
||||||
|
|
||||||
|
|
||||||
// weapons shared by monsters
|
// weapons shared by monsters
|
||||||
float monDmg9MM;
|
float monDmg9MM;
|
||||||
|
|||||||
Reference in New Issue
Block a user