From 875d6610ae56e83058917558ba8783c3ce2df0e5 Mon Sep 17 00:00:00 2001 From: Giegue Date: Sun, 5 Feb 2023 17:13:39 -0300 Subject: [PATCH] Add monster_robogrunt. --- src/dlls/cmbasemonster.h | 35 ++++ src/dlls/dllapi.cpp | 4 + src/dlls/explode.cpp | 72 +++++-- src/dlls/explode.h | 1 + src/dlls/gargantua.cpp | 58 +----- src/dlls/monster_mm.dsp | 8 + src/dlls/rgrunt.cpp | 423 +++++++++++++++++++++++++++++++++++++++ src/dlls/skill.cpp | 6 + src/dlls/skill.h | 3 + 9 files changed, 546 insertions(+), 64 deletions(-) create mode 100644 src/dlls/rgrunt.cpp diff --git a/src/dlls/cmbasemonster.h b/src/dlls/cmbasemonster.h index d003aee..5f762c4 100644 --- a/src/dlls/cmbasemonster.h +++ b/src/dlls/cmbasemonster.h @@ -1660,4 +1660,39 @@ public: 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 diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index 63fec8a..e8d9161 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -162,6 +162,7 @@ monster_type_t monster_types[]= "monster_baby_voltigore", FALSE, "monster_babygarg", FALSE, // Sven Co-op Monsters "monster_hwgrunt", FALSE, + "monster_robogrunt", FALSE, "info_node", FALSE, // Nodes "info_node_air", 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 26: monsters[monster_index].pMonster = CreateClassPtr((CMBabyGargantua *)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) @@ -1319,6 +1321,7 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) CMBabyVoltigore babyvoltigore; CMBabyGargantua babygargantua; CMHWGrunt hwgrunt; + CMRGrunt rgrunt; 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 26: babygargantua.Precache(); break; case 27: hwgrunt.Precache(); break; + case 28: rgrunt.Precache(); break; } } } diff --git a/src/dlls/explode.cpp b/src/dlls/explode.cpp index 4c3e358..1b10789 100644 --- a/src/dlls/explode.cpp +++ b/src/dlls/explode.cpp @@ -81,13 +81,52 @@ void CMShower::Touch( CMBaseEntity *pOther ) 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 { public: void Spawn( ); void EXPORT Smoke ( void ); void KeyValue( KeyValueData *pkvd ); - void DelayUse( void ); + void EXPORT DelayUse( void ); void Use( CMBaseEntity *pActivator, CMBaseEntity *pCaller, USE_TYPE useType, float value ); int m_iMagnitude;// how large is the fireball? how much damage? @@ -106,7 +145,7 @@ void CMEnvExplosion::KeyValue( KeyValueData *pkvd ) } void CMEnvExplosion::Spawn( void ) -{ +{ pev->solid = SOLID_NOT; pev->effects = EF_NODRAW; @@ -142,7 +181,7 @@ void CMEnvExplosion::DelayUse( void ) } void CMEnvExplosion::Use( CMBaseEntity *pActivator, CMBaseEntity *pCaller, USE_TYPE useType, float value ) -{ +{ TraceResult tr; pev->model = iStringNull;//invisible @@ -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 ) { KeyValueData kvd; @@ -287,15 +327,19 @@ void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwne pExplosion->pev->spawnflags &= ~SF_ENVEXPLOSION_REPEATABLE; pExplosion->Spawn(); - if ( delay > 0.0f ) - { - //pExplosion->SetThink( &CMBaseEntity::SUB_CallUseToggle ); // i don't trust you - pExplosion->SetThink( &CMEnvExplosion::DelayUse ); - pExplosion->pev->nextthink = gpGlobals->time + delay; - } - else - { - pExplosion->Use( NULL, NULL, USE_TOGGLE, 0 ); - } + pExplosion->SetThink( &CMEnvExplosion::DelayUse ); + pExplosion->pev->nextthink = gpGlobals->time + delay; } } + +// Emit smoke +void SmokeCreate( const Vector &origin, int amount, int size, int radius, float delay ) +{ + 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 +} \ No newline at end of file diff --git a/src/dlls/explode.h b/src/dlls/explode.h index 6b34159..74278dc 100644 --- a/src/dlls/explode.h +++ b/src/dlls/explode.h @@ -28,5 +28,6 @@ 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 ); +extern void SmokeCreate( const Vector &origin, int amount, int size, int radius, float delay ); #endif //EXPLODE_H diff --git a/src/dlls/gargantua.cpp b/src/dlls/gargantua.cpp index 73452cc..476cac6 100644 --- a/src/dlls/gargantua.cpp +++ b/src/dlls/gargantua.cpp @@ -62,13 +62,6 @@ const float GARG_ATTACKDIST = 80.0; int gStompSprite = 0, gGargGibModel = 0; 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 class CSpiral : public CMBaseEntity { @@ -781,7 +774,7 @@ void CMGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector ve // 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 ); } - flDamage *= (1.01f - gSkillData.gargantuaArmor); // Again, for mods (see below) +// flDamage *= (1.00f - gSkillData.gargantuaArmor); // in here...? } 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 ) { if ( IsAlive() ) { 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 SetConditions( bits_COND_LIGHT_DAMAGE ); @@ -821,14 +813,12 @@ void CMGargantua::DeathEffect( void ) SpawnExplosion( position, 70, (i * 0.3), 60 + (i*20), pev->owner ); position.z += 15; } - - CMBaseEntity *pSmoker = CreateClassPtr((CSmoker *)NULL); // CMBaseEntity::Create( "env_smoker", pev->origin, g_vecZero, NULL ); - UTIL_SetOrigin( pSmoker->pev, pev->origin ); - pSmoker->Spawn(); - pSmoker->pev->health = 1; // 1 smoke balls - pSmoker->pev->scale = 46; // 4.6X normal size - pSmoker->pev->dmg = 0; // 0 radial distribution - pSmoker->pev->nextthink = gpGlobals->time + 2.5; // Start in 2.5 seconds + + // 1 smoke balls + // 4.6X normal size + // 0 radial distribution + // start in 2.5 seconds + SmokeCreate( pev->origin, 1, 46, 0, 2.5 ); } @@ -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 ) { pev->movetype = MOVETYPE_NONE; diff --git a/src/dlls/monster_mm.dsp b/src/dlls/monster_mm.dsp index 817ad96..129e886 100644 --- a/src/dlls/monster_mm.dsp +++ b/src/dlls/monster_mm.dsp @@ -198,6 +198,10 @@ SOURCE=.\houndeye.cpp # End Source File # Begin Source File +SOURCE=.\hwgrunt.cpp +# End Source File +# Begin Source File + SOURCE=.\islave.cpp # End Source File # Begin Source File @@ -234,6 +238,10 @@ SOURCE=.\pitdrone.cpp # End Source File # Begin Source File +SOURCE=.\rgrunt.cpp +# End Source File +# Begin Source File + SOURCE=.\scientist.cpp # End Source File # Begin Source File diff --git a/src/dlls/rgrunt.cpp b/src/dlls/rgrunt.cpp new file mode 100644 index 0000000..7d307bf --- /dev/null +++ b/src/dlls/rgrunt.cpp @@ -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 +} diff --git a/src/dlls/skill.cpp b/src/dlls/skill.cpp index 14421f6..f0ae765 100644 --- a/src/dlls/skill.cpp +++ b/src/dlls/skill.cpp @@ -99,6 +99,8 @@ skill_cfg_t skill_cfg[] = { {"sk_babygarg_dmg_fire", &gSkillData.babygargDmgFire}, {"sk_babygarg_dmg_stomp", &gSkillData.babygargDmgStomp}, {"sk_hwgrunt_health", &gSkillData.hwgruntHealth}, + {"sk_rgrunt_health", &gSkillData.rgruntHealth}, + {"sk_rgrunt_armor", &gSkillData.rgruntArmor}, {"sk_12mm_bullet", &gSkillData.monDmg9MM}, {"sk_9mmAR_bullet", &gSkillData.monDmgMP5}, {"sk_9mm_bullet", &gSkillData.monDmg12MM}, @@ -289,6 +291,10 @@ void monster_skill_init(void) // Heavy Weapons Grunt gSkillData.hwgruntHealth = 60.0f; + + // Robo Grunt + gSkillData.rgruntHealth = 50.0f; + gSkillData.rgruntArmor = 0.75f; // MONSTER WEAPONS gSkillData.monDmg9MM = 5.0f; diff --git a/src/dlls/skill.h b/src/dlls/skill.h index ad91122..6eae1e3 100644 --- a/src/dlls/skill.h +++ b/src/dlls/skill.h @@ -127,6 +127,9 @@ struct skilldata_t float hwgruntHealth; + float rgruntHealth; + float rgruntArmor; + // weapons shared by monsters float monDmg9MM;