6 Commits

Author SHA1 Message Date
Giegue
f035b865e5 Fix Alien Slave beams not clearing upon gib/removal.
Fix env_smoker showing as func_wall.
Fix pev->message field not working on many entities.
Fix monstermaker "soundlist" keyvalue not working.
Add prisoner spawnflag (16) for monstermaker.
Add poison damage to spore grenades.
Increase max entities from 512 to 768.
Increase max spawnpoints from 256 to 384.
2024-01-21 14:46:32 -03:00
Giegue
9f77e10934 - Fix a few possible crashes.
- Fix xenmaker sprites never being removed if their framerate is 0.
- Fix xenmaker sprites never showing if their scale is 0.
- Add trigger_setcvar.
- New "health" keyvalue for monsters/monstermaker for custom health.
2024-01-10 16:05:40 -03:00
Giegue
75596ad87e Fix xenmaker monsters not fading, again. 2023-11-02 16:13:45 -03:00
Giegue
f57c7760f7 Fix xenmaker sprite effects.
Fix xenmaker monsters not fading after death.
2023-10-21 14:01:48 -03:00
Giegue
8ed6c4eb2b Fix xenmaker crashing when many of them are activated simultaneously. 2023-10-06 19:44:17 -03:00
Giegue
c1660a0e48 Add env_xenmaker entity. 2023-10-06 01:43:56 -03:00
46 changed files with 691 additions and 74 deletions

View File

@@ -63,7 +63,9 @@ I'm aware that the plugin is far from perfect, and there are a few things that n
- Rarely, Stukabats will become unable to fly towards their target, standing in air doing seemingly nothing. - Rarely, Stukabats will become unable to fly towards their target, standing in air doing seemingly nothing.
- Monsters are very prone to gibbing when hurt during death animations. - Monsters are very prone to gibbing.
- Houndeyes and Hornets (Alien Grunts) do not get along. The server will crash if a houndeye damages a hornet.
There are probably more issues that aren't listed here, I'll attempt to fix them as I find them. Of course, any bug report is welcome. If reporting a bug, try to explain step by step how the bug ocurred. The easier it is to replicate a bug, the easier it is to locate it and fix it. There are probably more issues that aren't listed here, I'll attempt to fix them as I find them. Of course, any bug report is welcome. If reporting a bug, try to explain step by step how the bug ocurred. The easier it is to replicate a bug, the easier it is to locate it and fix it.

View File

@@ -16,7 +16,7 @@ sk_apache_health 250
// Barney // Barney
sk_barney_health 35 sk_barney_health 35
// Big Momma // Big Momma (HP = 150 * health_factor)
sk_bigmomma_health_factor 1.5 sk_bigmomma_health_factor 1.5
sk_bigmomma_dmg_slash 60 sk_bigmomma_dmg_slash 60
sk_bigmomma_dmg_blast 120 sk_bigmomma_dmg_blast 120

View File

@@ -46,6 +46,7 @@ OBJ = \
rgrunt.o \ rgrunt.o \
ripent.o \ ripent.o \
scientist.o \ scientist.o \
setcvar.o \
shock.o \ shock.o \
shockroach.o \ shockroach.o \
skill.o \ skill.o \
@@ -60,6 +61,7 @@ OBJ = \
util.o \ util.o \
voltigore.o \ voltigore.o \
weapons.o \ weapons.o \
xenmaker.o \
zombie.o zombie.o
monster_mm_i386.so: ${OBJ} monster_mm_i386.so: ${OBJ}

View File

@@ -543,7 +543,7 @@ void CMAGrunt :: Spawn()
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0; pev->effects = 0;
pev->health = gSkillData.agruntHealth; if (!pev->health) { pev->health = gSkillData.agruntHealth; }
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;
m_afCapability = 0; m_afCapability = 0;

View File

@@ -41,7 +41,7 @@ void CMApache :: Spawn( void )
pev->flags |= FL_MONSTER; pev->flags |= FL_MONSTER;
pev->takedamage = DAMAGE_AIM; pev->takedamage = DAMAGE_AIM;
pev->health = gSkillData.apacheHealth; if (!pev->health) { pev->health = gSkillData.apacheHealth; }
m_flFieldOfView = -0.707; // 270 degrees m_flFieldOfView = -0.707; // 270 degrees

View File

@@ -351,7 +351,7 @@ void CMBarney :: Spawn()
pev->solid = SOLID_SLIDEBOX; pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
pev->health = gSkillData.barneyHealth; if (!pev->health) { pev->health = gSkillData.barneyHealth; }
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin. pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_FULL; m_flFieldOfView = VIEW_FIELD_FULL;
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;

View File

@@ -610,7 +610,7 @@ void CMBigMomma :: Spawn()
pev->solid = SOLID_SLIDEBOX; pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->health = 150 * gSkillData.bigmommaHealthFactor; if (!pev->health) { pev->health = 150 * gSkillData.bigmommaHealthFactor; }
pev->view_ofs = Vector ( 0, 0, 128 );// position of the eyes relative to monster's origin. pev->view_ofs = Vector ( 0, 0, 128 );// position of the eyes relative to monster's origin.
m_flFieldOfView = 0.3;// indicates the width of this monster's forward view cone ( as a dotproduct result ) m_flFieldOfView = 0.3;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;

View File

@@ -65,6 +65,7 @@ public:
void EXPORT Animate( void ); void EXPORT Animate( void );
int m_maxFrame; int m_maxFrame;
EHANDLE m_hOwner;
}; };
void CSquidSpit:: Spawn( void ) void CSquidSpit:: Spawn( void )
@@ -110,6 +111,7 @@ void CSquidSpit::Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity
UTIL_SetOrigin( pSpit->pev, vecStart ); UTIL_SetOrigin( pSpit->pev, vecStart );
pSpit->pev->velocity = vecVelocity; pSpit->pev->velocity = vecVelocity;
pSpit->pev->owner = ENT(pevOwner); pSpit->pev->owner = ENT(pevOwner);
pSpit->m_hOwner = ENT(pevOwner);
pSpit->SetThink ( &CSquidSpit::Animate ); pSpit->SetThink ( &CSquidSpit::Animate );
pSpit->pev->nextthink = gpGlobals->time + 0.1; pSpit->pev->nextthink = gpGlobals->time + 0.1;
@@ -118,6 +120,9 @@ void CSquidSpit::Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity
void CSquidSpit :: SpitTouch ( edict_t *pOther ) void CSquidSpit :: SpitTouch ( edict_t *pOther )
{ {
if (m_hOwner == NULL)
pev->owner = NULL;
TraceResult tr; TraceResult tr;
int iPitch; int iPitch;
@@ -617,7 +622,7 @@ void CMBullsquid :: Spawn()
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0; pev->effects = 0;
pev->health = gSkillData.bullsquidHealth; if (!pev->health) { pev->health = gSkillData.bullsquidHealth; }
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;

View File

@@ -48,4 +48,57 @@ public:
BOOL m_fPlaying; // music is active BOOL m_fPlaying; // music is active
}; };
//=========================================================
// XenMaker - spawns a monster with a teleportation effect.
//=========================================================
class CMXenMaker : public CMBaseMonster
{
public:
void Spawn(void);
void Precache(void);
void KeyValue(KeyValueData* pkvd);
void EXPORT CyclicUse(edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value);
void EXPORT RetryThink(void);
void StartEffect(void);
void EXPORT MiddleEffect(void);
void EXPORT EndEffect(void);
int m_iMonsterIndex;// index of the monster that will be created.
float m_flBeamRadius; // Maximum beam strike radius.
int m_iBeamAlpha;
int m_iBeamCount; // Number of single beam instances.
Vector m_vBeamColor;
float m_flLightRadius;
Vector m_vLightColor;
float m_flStartSpriteFramerate;
float m_flStartSpriteScale;
int m_iStartSpriteAlpha;
Vector m_vStartSpriteColor;
float m_flEndSpriteFramerate;
float m_flEndSpriteScale;
int m_iEndSpriteAlpha;
Vector m_vEndSpriteColor;
private:
void SpawnBeam(void);
int m_iBeamIndex;
};
//=========================================================
// Set CVar - Adjust a map CVar when triggered.
//=========================================================
class CMSetCVar : public CMBaseMonster
{
public:
void Spawn(void);
void KeyValue(KeyValueData* pkvd);
void EXPORT ActUse(edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value);
string_t m_iszCVarToChange;
};
#endif // BASEEXTRA_H #endif // BASEEXTRA_H

View File

@@ -632,6 +632,7 @@ public:
void IdleSound( void ); void IdleSound( void );
void Killed( entvars_t *pevAttacker, int iGib ); void Killed( entvars_t *pevAttacker, int iGib );
void UpdateOnRemove();
void StartTask ( Task_t *pTask ); void StartTask ( Task_t *pTask );
Schedule_t *GetSchedule( void ); Schedule_t *GetSchedule( void );

View File

@@ -974,12 +974,17 @@ int CMBaseMonster :: DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAtta
vecDir = Vector( 0, 0, 0 ); vecDir = Vector( 0, 0, 0 );
if (!FNullEnt( pevInflictor )) if (!FNullEnt( pevInflictor ))
{ {
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pevInflictor)); if (pevInflictor->euser4 != NULL)
if (pMonster)
{ {
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pevInflictor));
vecDir = (pMonster->Center() - Vector(0, 0, 10) - Center()).Normalize(); vecDir = (pMonster->Center() - Vector(0, 0, 10) - Center()).Normalize();
vecDir = g_vecAttackDir = vecDir.Normalize(); vecDir = g_vecAttackDir = vecDir.Normalize();
} }
else
{
vecDir = (UTIL_Center(ENT(pevInflictor)) - Vector(0, 0, 10) - Center()).Normalize();
vecDir = g_vecAttackDir = vecDir.Normalize();
}
} }
#if 0// turn this back on when the bounding box issues are resolved. #if 0// turn this back on when the bounding box issues are resolved.

View File

@@ -309,7 +309,7 @@ void CMController :: Spawn()
pev->movetype = MOVETYPE_FLY; pev->movetype = MOVETYPE_FLY;
pev->flags |= FL_FLY; pev->flags |= FL_FLY;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->health = gSkillData.controllerHealth; if (!pev->health) { pev->health = gSkillData.controllerHealth; }
pev->view_ofs = Vector( 0, 0, -2 );// position of the eyes relative to monster's origin. pev->view_ofs = Vector( 0, 0, -2 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_FULL;// indicates the width of this monster's forward view cone ( as a dotproduct result ) m_flFieldOfView = VIEW_FIELD_FULL;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;

View File

@@ -166,6 +166,8 @@ monster_type_t monster_types[]=
"info_node_air", FALSE, "info_node_air", FALSE,
"monstermaker", FALSE, // Extra entities "monstermaker", FALSE, // Extra entities
"ambient_music", FALSE, "ambient_music", FALSE,
"env_xenmaker", FALSE,
"trigger_setcvar", FALSE,
"squadmaker", FALSE, // Aliases "squadmaker", FALSE, // Aliases
"", FALSE "", FALSE
}; };
@@ -711,6 +713,9 @@ edict_t* spawn_monster(int monster_type, Vector origin, Vector angles, int spawn
// Extra entities // Extra entities
case 32: monsters[monster_index].pMonster = CreateClassPtr((CMMonsterMaker *)NULL); break; case 32: monsters[monster_index].pMonster = CreateClassPtr((CMMonsterMaker *)NULL); break;
case 33: monsters[monster_index].pMonster = CreateClassPtr((CMAmbientMusic *)NULL); break; case 33: monsters[monster_index].pMonster = CreateClassPtr((CMAmbientMusic *)NULL); break;
case 34: monsters[monster_index].pMonster = CreateClassPtr((CMXenMaker *)NULL); break;
case 35: monsters[monster_index].pMonster = CreateClassPtr((CMSetCVar *)NULL); break;
default: LOG_MESSAGE(PLID, "ERROR: Invalid monster type! (%i)", monster_type); return NULL;
} }
if (monsters[monster_index].pMonster == NULL) if (monsters[monster_index].pMonster == NULL)
@@ -1239,6 +1244,28 @@ void SpawnViewerCommand(void)
LOG_MESSAGE(PLID, "spawns a node viewer at the player's location"); LOG_MESSAGE(PLID, "spawns a node viewer at the player's location");
} }
void DebugGetEntities(void)
{
LOG_MESSAGE(PLID, "count: %i ents of max %i\n", monster_ents_used, MAX_MONSTER_ENTS);
for (int index = 0; index < MAX_MONSTER_ENTS; index++)
{
if (monsters[index].monster_index)
{
LOG_MESSAGE(PLID, "SLOT #%i:", index);
edict_t *pent = (*g_engfuncs.pfnPEntityOfEntIndex)(monsters[index].monster_index);
if (pent)
{
LOG_MESSAGE(PLID, "Class is \"%s\"\n", STRING(pent->v.classname));
}
else
{
LOG_MESSAGE(PLID, "NULL entity\n");
}
}
}
}
void mmGameDLLInit( void ) void mmGameDLLInit( void )
{ {
// one time initialization stuff here... // one time initialization stuff here...
@@ -1435,11 +1462,14 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
// Extra entities // Extra entities
CMMonsterMaker monstermaker; // 32 CMMonsterMaker monstermaker; // 32
CMAmbientMusic ambientmusic; CMAmbientMusic ambientmusic;
CMXenMaker xenmaker;
CMSetCVar setcvar;
g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" ); g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" );
(g_engfuncs.pfnAddServerCommand)("monster", MonsterCommand); (g_engfuncs.pfnAddServerCommand)("monster", MonsterCommand);
(g_engfuncs.pfnAddServerCommand)("node_viewer", SpawnViewerCommand); (g_engfuncs.pfnAddServerCommand)("node_viewer", SpawnViewerCommand);
(g_engfuncs.pfnAddServerCommand)("get_edicts", DebugGetEntities);
(g_engfuncs.pfnAddServerCommand)("_use", mmDispatchUse); (g_engfuncs.pfnAddServerCommand)("_use", mmDispatchUse);
for (index = 0; monster_types[index].name[0]; index++) for (index = 0; monster_types[index].name[0]; index++)
@@ -1485,6 +1515,8 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
case 29: stukabat.Precache(); break; case 29: stukabat.Precache(); break;
case 32: monstermaker.Precache(); break; case 32: monstermaker.Precache(); break;
//case 33: ambientmusic.Precache(); break; //case 33: ambientmusic.Precache(); break;
case 34: xenmaker.Precache(); break;
//case 35: setcvar.Precache(); break;
} }
} }
} }

View File

@@ -332,6 +332,8 @@ void CMSprite::SpriteInit( const char *pSpriteName, const Vector &origin )
CMSprite *CMSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ) CMSprite *CMSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate )
{ {
CMSprite *pSprite = CreateClassPtr( (CMSprite *)NULL ); CMSprite *pSprite = CreateClassPtr( (CMSprite *)NULL );
if (pSprite)
{
pSprite->SpriteInit(pSpriteName, origin); pSprite->SpriteInit(pSpriteName, origin);
pSprite->pev->classname = MAKE_STRING("env_sprite"); pSprite->pev->classname = MAKE_STRING("env_sprite");
pSprite->pev->solid = SOLID_NOT; pSprite->pev->solid = SOLID_NOT;
@@ -341,6 +343,8 @@ CMSprite *CMSprite::SpriteCreate( const char *pSpriteName, const Vector &origin,
return pSprite; return pSprite;
} }
return NULL;
}
void CMSprite::AnimateThink( void ) void CMSprite::AnimateThink( void )

View File

@@ -79,10 +79,13 @@ public:
inline void AnimateAndDie( float framerate ) inline void AnimateAndDie( float framerate )
{ {
pev->effects = 0;
SetThink(&CMSprite::AnimateUntilDead); SetThink(&CMSprite::AnimateUntilDead);
pev->framerate = framerate; pev->framerate = framerate;
pev->dmgtime = gpGlobals->time + (m_maxFrame / framerate); pev->dmgtime = gpGlobals->time + (m_maxFrame / framerate);
pev->nextthink = gpGlobals->time; pev->nextthink = gpGlobals->time;
m_lastTime = gpGlobals->time;
pev->frame = 0;
} }
void EXPORT AnimateUntilDead( void ); void EXPORT AnimateUntilDead( void );

View File

@@ -97,6 +97,7 @@ void CSmoker::Spawn( void )
UTIL_SetSize(pev, g_vecZero, g_vecZero ); UTIL_SetSize(pev, g_vecZero, g_vecZero );
pev->effects |= EF_NODRAW; pev->effects |= EF_NODRAW;
pev->angles = g_vecZero; pev->angles = g_vecZero;
pev->classname = MAKE_STRING("env_smoker");
} }
void CSmoker::Think( void ) void CSmoker::Think( void )

View File

@@ -684,7 +684,7 @@ void CMGargantua :: Spawn()
pev->solid = SOLID_SLIDEBOX; pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->health = gSkillData.gargantuaHealth; if (!pev->health) { pev->health = gSkillData.gargantuaHealth; }
//pev->view_ofs = Vector ( 0, 0, 96 );// taken from mdl file //pev->view_ofs = Vector ( 0, 0, 96 );// taken from mdl file
m_flFieldOfView = -0.2;// width of forward view cone ( as a dotproduct result ) m_flFieldOfView = -0.2;// width of forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;
@@ -1329,7 +1329,7 @@ void CMBabyGargantua::Spawn()
pev->solid = SOLID_SLIDEBOX; pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->health = gSkillData.babygargHealth; if (!pev->health) { pev->health = gSkillData.babygargHealth; }
//pev->view_ofs = Vector ( 0, 0, 96 );// taken from mdl file //pev->view_ofs = Vector ( 0, 0, 96 );// taken from mdl file
m_flFieldOfView = -0.2;// width of forward view cone ( as a dotproduct result ) m_flFieldOfView = -0.2;// width of forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;

View File

@@ -56,6 +56,12 @@ bool AddGlobalSound(const char *from, const char *to)
{ {
if (numSounds < MAX_REPLACEMENTS) if (numSounds < MAX_REPLACEMENTS)
{ {
if (from[0] == '!')
{
// sentence sounds cannot be replaced, skip.
return false;
}
// allocate for the first time // allocate for the first time
if (!numSounds) if (!numSounds)
GSR = (REPLACER*)calloc(MAX_REPLACEMENTS, sizeof(*GSR)); GSR = (REPLACER*)calloc(MAX_REPLACEMENTS, sizeof(*GSR));

View File

@@ -615,7 +615,7 @@ void CMGonome::Spawn()
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0; pev->effects = 0;
pev->health = gSkillData.gonomeHealth; if (!pev->health) { pev->health = gSkillData.gonomeHealth; }
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;

View File

@@ -222,7 +222,7 @@ void CMHAssassin :: Spawn()
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
pev->effects = 0; pev->effects = 0;
pev->health = gSkillData.hassassinHealth; if (!pev->health) { pev->health = gSkillData.hassassinHealth; }
m_flFieldOfView = VIEW_FIELD_WIDE; // indicates the width of this monster's forward view cone ( as a dotproduct result ) m_flFieldOfView = VIEW_FIELD_WIDE; // indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;
m_afCapability = bits_CAP_MELEE_ATTACK1 | bits_CAP_DOORS_GROUP; m_afCapability = bits_CAP_MELEE_ATTACK1 | bits_CAP_DOORS_GROUP;

View File

@@ -254,7 +254,7 @@ void CMHeadCrab :: Spawn()
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0; pev->effects = 0;
pev->health = gSkillData.headcrabHealth; if (!pev->health) { pev->health = gSkillData.headcrabHealth; }
pev->view_ofs = Vector ( 0, 0, 20 );// position of the eyes relative to monster's origin. 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? 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_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
@@ -466,7 +466,7 @@ void CMBabyCrab :: Spawn( void )
pev->renderamt = 192; pev->renderamt = 192;
UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24)); UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24));
pev->health = gSkillData.headcrabHealth * 0.25; // less health than full grown if (!pev->health) { pev->health = gSkillData.headcrabHealth * 0.25; } // less health than full grown
} }
void CMBabyCrab :: Precache( void ) void CMBabyCrab :: Precache( void )

View File

@@ -837,7 +837,7 @@ void CMHGrunt :: Spawn()
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
pev->effects = 0; pev->effects = 0;
pev->health = gSkillData.hgruntHealth; if (!pev->health) { pev->health = gSkillData.hgruntHealth; }
m_flFieldOfView = VIEW_FIELD_FULL; // indicates the width of this monster's forward view cone ( as a dotproduct result ) m_flFieldOfView = VIEW_FIELD_FULL; // indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;
m_flNextGrenadeCheck = gpGlobals->time + 1; m_flNextGrenadeCheck = gpGlobals->time + 1;

View File

@@ -131,7 +131,10 @@ int CMHornet::Classify ( void )
if (UTIL_IsValidEntity(pev->owner)) if (UTIL_IsValidEntity(pev->owner))
{ {
CMBaseMonster *pOwner = GetClassPtr((CMBaseMonster *)VARS(pev->owner)); CMBaseMonster *pOwner = GetClassPtr((CMBaseMonster *)VARS(pev->owner));
if (pOwner)
return pOwner->Classify(); return pOwner->Classify();
else
return pev->owner->v.iuser4;
} }
return CLASS_ALIEN_BIOWEAPON; return CLASS_ALIEN_BIOWEAPON;
} }

View File

@@ -274,7 +274,7 @@ void CMHoundeye :: Spawn()
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0; pev->effects = 0;
pev->health = gSkillData.houndeyeHealth; if (!pev->health) { pev->health = gSkillData.houndeyeHealth; }
pev->yaw_speed = 5;//!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim? 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_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;

View File

@@ -201,7 +201,7 @@ void CMHWGrunt::Spawn()
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
pev->effects = 0; pev->effects = 0;
pev->health = gSkillData.hwgruntHealth; if (!pev->health) { pev->health = gSkillData.hwgruntHealth; }
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;
//m_flNextGrenadeCheck = gpGlobals->time + 1; //m_flNextGrenadeCheck = gpGlobals->time + 1;

View File

@@ -168,6 +168,12 @@ void CMISlave::Killed( entvars_t *pevAttacker, int iGib )
CMBaseMonster::Killed( pevAttacker, iGib ); CMBaseMonster::Killed( pevAttacker, iGib );
} }
void CMISlave::UpdateOnRemove()
{
CMBaseMonster::UpdateOnRemove();
ClearBeams();
}
//========================================================= //=========================================================
// SetYawSpeed - allows each sequence to have a different // SetYawSpeed - allows each sequence to have a different
// turn rate associated with it. // turn rate associated with it.
@@ -423,7 +429,7 @@ void CMISlave :: Spawn()
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0; pev->effects = 0;
pev->health = gSkillData.slaveHealth; if (!pev->health) { pev->health = gSkillData.slaveHealth; }
pev->view_ofs = Vector ( 0, 0, 64 );// position of the eyes relative to monster's origin. pev->view_ofs = Vector ( 0, 0, 64 );// position of the eyes relative to monster's origin.
m_flFieldOfView = 0.5; m_flFieldOfView = 0.5;
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;

View File

@@ -231,7 +231,7 @@ void CMMassn::Spawn()
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
pev->effects = 0; pev->effects = 0;
pev->health = gSkillData.massnHealth; if (!pev->health) { pev->health = gSkillData.massnHealth; }
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;
m_flNextGrenadeCheck = gpGlobals->time + 1; m_flNextGrenadeCheck = gpGlobals->time + 1;

View File

@@ -133,7 +133,6 @@ void process_monster_sound(edict_t *pMonster, char *fileName)
// SC soundlist path starts from sound/MAPNAME // SC soundlist path starts from sound/MAPNAME
sprintf(srPath, "%s/sound/%s/%s", game_dir, STRING(gpGlobals->mapname), fileName); sprintf(srPath, "%s/sound/%s/%s", game_dir, STRING(gpGlobals->mapname), fileName);
if (access(srPath, 0) == 0) if (access(srPath, 0) == 0)
{ {
if ((fp = fopen(srPath, "r")) != NULL) if ((fp = fopen(srPath, "r")) != NULL)
@@ -225,6 +224,36 @@ void scan_monster_cfg(FILE *fp)
monster = TRUE; monster = TRUE;
} }
} }
else if (strcmp(monster_types[mIndex].name, "trigger_setcvar") == 0)
{
if (monster_spawn_count == MAX_MONSTERS)
{
LOG_MESSAGE(PLID, "ERROR: can't add ambient_music, reached MAX_MONSTERS!");
badent = TRUE;
}
else
{
monster_spawnpoint[monster_spawn_count].monster = mIndex;
monster_types[mIndex].need_to_precache = TRUE;
monster = TRUE;
}
}
else if (strcmp(monster_types[mIndex].name, "env_xenmaker") == 0)
{
// A monster spawner, add it to the list
if (monster_spawn_count == MAX_MONSTERS)
{
// error.exe
LOG_MESSAGE(PLID, "ERROR: can't add monstermaker, reached MAX_MONSTERS!");
badent = TRUE;
}
else
{
monster_spawnpoint[monster_spawn_count].monster = mIndex;
monster_types[mIndex].need_to_precache = TRUE;
monster = TRUE;
}
}
else if (strcmp(monster_types[mIndex].name, "info_node") == 0) else if (strcmp(monster_types[mIndex].name, "info_node") == 0)
{ {
// Normal node // Normal node
@@ -391,8 +420,8 @@ void scan_monster_cfg(FILE *fp)
{ {
if (monster) if (monster)
{ {
// this keyvalue is only valid for monstermaker entity // this keyvalue is only valid for monstermaker entities
if (strcmp(data[kvd_index-1].value, "monstermaker") == 0 || strcmp(data[kvd_index-1].value, "squadmaker") == 0) if (strcmp(data[kvd_index - 1].value, "monstermaker") == 0 || strcmp(data[kvd_index - 1].value, "squadmaker") == 0 || strcmp(data[kvd_index - 1].value, "env_xenmaker") == 0)
{ {
// process the entity precache here // process the entity precache here
int mIndex; int mIndex;
@@ -420,13 +449,13 @@ void scan_monster_cfg(FILE *fp)
{ {
// precache the sound here // precache the sound here
PRECACHE_GENERIC(data[i].value); PRECACHE_GENERIC(data[i].value);
}
// the entity will need the keyvalue // common pev-field, an entity might need it
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key); strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value); strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
} }
} }
}
else else
{ {
// We do not know this keyvalue, but an specific entity might use it. // We do not know this keyvalue, but an specific entity might use it.
@@ -771,7 +800,7 @@ void scan_monster_bsp(void)
if (monster) if (monster)
{ {
// this keyvalue is only valid for monstermaker entity // this keyvalue is only valid for monstermaker entity
if (strcmp(data[classname_kvdI].value, "monstermaker") == 0 || strcmp(data[classname_kvdI].value, "squadmaker") == 0) if (strcmp(data[classname_kvdI].value, "monstermaker") == 0 || strcmp(data[classname_kvdI].value, "squadmaker") == 0 || strcmp(data[classname_kvdI].value, "env_xenmaker") == 0)
{ {
// process the entity precache here // process the entity precache here
for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++) for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++)
@@ -798,13 +827,13 @@ void scan_monster_bsp(void)
{ {
// precache the sound here // precache the sound here
PRECACHE_GENERIC(data[i].value); PRECACHE_GENERIC(data[i].value);
}
// the entity will need the keyvalue // common pev-field, an entity might need it
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key); strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value); strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
} }
} }
}
else else
{ {
// We do not know this keyvalue, but an specific entity might use it. // We do not know this keyvalue, but an specific entity might use it.

View File

@@ -127,6 +127,7 @@
<DataExecutionPrevention> <DataExecutionPrevention>
</DataExecutionPrevention> </DataExecutionPrevention>
<ImportLibrary>.\Release/monster_mm.lib</ImportLibrary> <ImportLibrary>.\Release/monster_mm.lib</ImportLibrary>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
@@ -172,6 +173,7 @@
<ClCompile Include="rgrunt.cpp" /> <ClCompile Include="rgrunt.cpp" />
<ClCompile Include="ripent.cpp" /> <ClCompile Include="ripent.cpp" />
<ClCompile Include="scientist.cpp" /> <ClCompile Include="scientist.cpp" />
<ClCompile Include="setcvar.cpp" />
<ClCompile Include="shock.cpp" /> <ClCompile Include="shock.cpp" />
<ClCompile Include="shockroach.cpp" /> <ClCompile Include="shockroach.cpp" />
<ClCompile Include="skill.cpp" /> <ClCompile Include="skill.cpp" />
@@ -186,6 +188,7 @@
<ClCompile Include="util.cpp" /> <ClCompile Include="util.cpp" />
<ClCompile Include="voltigore.cpp" /> <ClCompile Include="voltigore.cpp" />
<ClCompile Include="weapons.cpp" /> <ClCompile Include="weapons.cpp" />
<ClCompile Include="xenmaker.cpp" />
<ClCompile Include="zombie.cpp" /> <ClCompile Include="zombie.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -186,6 +186,12 @@
<ClCompile Include="globalreplace.cpp"> <ClCompile Include="globalreplace.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="xenmaker.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="setcvar.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="activity.h"> <ClInclude Include="activity.h">

View File

@@ -30,7 +30,7 @@ typedef struct
CMBaseMonster *pMonster; CMBaseMonster *pMonster;
} monster_t; } monster_t;
#define MAX_MONSTER_ENTS 400 #define MAX_MONSTER_ENTS 768
extern monster_t monsters[MAX_MONSTER_ENTS]; extern monster_t monsters[MAX_MONSTER_ENTS];
@@ -43,7 +43,7 @@ typedef struct {
bool need_to_respawn; bool need_to_respawn;
} monster_spawnpoint_t; } monster_spawnpoint_t;
#define MAX_MONSTERS 200 #define MAX_MONSTERS 384
extern monster_spawnpoint_t monster_spawnpoint[MAX_MONSTERS]; extern monster_spawnpoint_t monster_spawnpoint[MAX_MONSTERS];
// this is here to store if a node we want to spawn is an ordinary one, or a flying one // this is here to store if a node we want to spawn is an ordinary one, or a flying one

View File

@@ -28,6 +28,7 @@
#define SF_MONSTERMAKER_START_ON 1 // start active ( if has targetname ) #define SF_MONSTERMAKER_START_ON 1 // start active ( if has targetname )
#define SF_MONSTERMAKER_CYCLIC 4 // drop one monster every time fired. #define SF_MONSTERMAKER_CYCLIC 4 // drop one monster every time fired.
#define SF_MONSTERMAKER_MONSTERCLIP 8 // Children are blocked by monsterclip #define SF_MONSTERMAKER_MONSTERCLIP 8 // Children are blocked by monsterclip
#define SF_MONSTERMAKER_PRISONER 16 // children won't attack or be attacked
extern monster_type_t monster_types[]; extern monster_type_t monster_types[];
extern edict_t* spawn_monster(int monster_type, Vector origin, Vector angles, int spawnflags, pKVD *keyvalue); extern edict_t* spawn_monster(int monster_type, Vector origin, Vector angles, int spawnflags, pKVD *keyvalue);
@@ -171,7 +172,7 @@ void CMMonsterMaker::MakeMonster( void )
} }
edict_t *pent; edict_t *pent;
pKVD keyvalue[MAX_KEYVALUES]; // sometimes, i don't know what am i doing. -Giegue pKVD keyvalue[MAX_KEYVALUES];
int createSF = SF_MONSTER_FALL_TO_GROUND; int createSF = SF_MONSTER_FALL_TO_GROUND;
if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren ) if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren )
@@ -205,6 +206,10 @@ void CMMonsterMaker::MakeMonster( void )
if ( pev->spawnflags & SF_MONSTERMAKER_MONSTERCLIP ) if ( pev->spawnflags & SF_MONSTERMAKER_MONSTERCLIP )
createSF |= SF_MONSTER_HITMONSTERCLIP; createSF |= SF_MONSTER_HITMONSTERCLIP;
// Should children be prisoner entities?
if (pev->spawnflags & SF_MONSTERMAKER_PRISONER)
createSF |= SF_MONSTER_PRISONER;
/* KEYVALUES */ /* KEYVALUES */
// Monster is to have a custom model? // Monster is to have a custom model?
if ( !FStringNull( m_iszCustomModel ) ) if ( !FStringNull( m_iszCustomModel ) )
@@ -247,6 +252,12 @@ void CMMonsterMaker::MakeMonster( void )
strcpy(keyvalue[6].key, "classify"); strcpy(keyvalue[6].key, "classify");
sprintf(keyvalue[6].value, "%i", m_iClassifyOverride); sprintf(keyvalue[6].value, "%i", m_iClassifyOverride);
} }
// Custom health
if (pev->health)
{
strcpy(keyvalue[7].key, "health");
sprintf(keyvalue[7].value, "%f", pev->health);
}
// Attempt to spawn monster // Attempt to spawn monster
pent = spawn_monster(m_iMonsterIndex, pev->origin, pev->angles, createSF, keyvalue); pent = spawn_monster(m_iMonsterIndex, pev->origin, pev->angles, createSF, keyvalue);
@@ -284,7 +295,7 @@ void CMMonsterMaker::MakeMonster( void )
CMBaseMonster *pChild = GetClassPtr((CMBaseMonster *)VARS(pent)); CMBaseMonster *pChild = GetClassPtr((CMBaseMonster *)VARS(pent));
pChild->m_srSoundList = (REPLACER::REPLACER*)calloc(MAX_REPLACEMENTS, sizeof(*pChild->m_srSoundList)); pChild->m_srSoundList = (REPLACER::REPLACER*)calloc(MAX_REPLACEMENTS, sizeof(*pChild->m_srSoundList));
memcpy(pChild->m_srSoundList, m_srSoundList, sizeof(REPLACER::REPLACER)); memcpy(pChild->m_srSoundList, m_srSoundList, m_isrSounds * sizeof(*pChild->m_srSoundList));
pChild->m_isrSounds = m_isrSounds; pChild->m_isrSounds = m_isrSounds;
} }

View File

@@ -143,7 +143,7 @@ void CMOtis::Spawn()
pev->solid = SOLID_SLIDEBOX; pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
pev->health = gSkillData.otisHealth; if (!pev->health) { pev->health = gSkillData.otisHealth; }
pev->view_ofs = Vector(0, 0, 50);// position of the eyes relative to monster's origin. pev->view_ofs = Vector(0, 0, 50);// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;

View File

@@ -578,7 +578,7 @@ void CMPitdrone::Spawn()
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0; pev->effects = 0;
pev->health = gSkillData.pitdroneHealth; if (!pev->health) { pev->health = gSkillData.pitdroneHealth; }
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;

View File

@@ -324,7 +324,7 @@ void CMRGrunt::Spawn()
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = DONT_BLEED; m_bloodColor = DONT_BLEED;
pev->effects = 0; pev->effects = 0;
pev->health = gSkillData.rgruntHealth; if (!pev->health) { pev->health = gSkillData.rgruntHealth; }
pev->max_health = pev->health; // to determine when sparks should be emitted 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_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;

View File

@@ -602,7 +602,7 @@ void CMScientist :: Spawn( void )
pev->solid = SOLID_SLIDEBOX; pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
pev->health = gSkillData.scientistHealth; if (!pev->health) { pev->health = gSkillData.scientistHealth; }
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin. pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so scientists will notice player and say hello m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so scientists will notice player and say hello
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;

68
src/dlls/setcvar.cpp Normal file
View File

@@ -0,0 +1,68 @@
//=========================================================
// Set CVar - trigger_setcvar from Sven Co-op.
// Change a map CVar when triggered.
//=========================================================
#include "extdll.h"
#include "util.h"
#include "cmbase.h"
#include "cmbasemonster.h"
#include "cmbaseextra.h"
#define MAX_CVARS 10
// list of CVars that can be modified by this entity
char *cvar_list[MAX_CVARS]
{
"mp_falldamage",
"mp_flashlight",
"mp_fraglimit",
"mp_timelimit",
"mp_weaponstay",
"sv_accelerate",
"sv_airaccelerate"
"sv_friction",
"sv_gravity",
"sv_maxspeed"
}; // quite lame compared to SC, but many CVars don't exist in vanilla HL
void CMSetCVar::KeyValue(KeyValueData *pkvd)
{
if (FStrEq(pkvd->szKeyName, "m_iszCVarToChange"))
{
for (int index = 0; index < MAX_CVARS; index++)
{
if (strcmp(pkvd->szValue, cvar_list[index]) == 0)
{
m_iszCVarToChange = ALLOC_STRING(pkvd->szValue);
break;
}
}
if (FStringNull(m_iszCVarToChange))
{
ALERT(at_console, "trigger_setcvar - can't change CVar \"%s\". not supported!\n", pkvd->szValue);
}
pkvd->fHandled = TRUE;
}
else
CMBaseMonster::KeyValue(pkvd);
}
void CMSetCVar::Spawn()
{
pev->solid = SOLID_NOT;
SetUse(&CMSetCVar::ActUse);
pev->classname = MAKE_STRING("trigger_setcvar");
}
void CMSetCVar::ActUse(edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value)
{
// nothing to change
if (FStringNull(m_iszCVarToChange))
return;
CVAR_SET_FLOAT(STRING(m_iszCVarToChange), atof(STRING(pev->message)));
if (!FStringNull(pev->netname))
{
FireTargets(STRING(pev->netname), pActivator, this->edict(), USE_TOGGLE, 0.0f);
}
}

View File

@@ -107,7 +107,7 @@ void CMSporeGrenade::Explode(TraceResult *pTrace)
pev->owner = NULL; // can't traceline attack owner if this is set pev->owner = NULL; // can't traceline attack owner if this is set
RadiusDamage(pev, pevOwner, pev->dmg, CLASS_NONE, DMG_BLAST); RadiusDamage(pev, pevOwner, pev->dmg, CLASS_NONE, DMG_BLAST | DMG_POISON);
// Place a decal on the surface that was hit. // Place a decal on the surface that was hit.
UTIL_DecalTrace(pTrace, DECAL_SPIT1 + RANDOM_LONG(0, 1)); UTIL_DecalTrace(pTrace, DECAL_SPIT1 + RANDOM_LONG(0, 1));

View File

@@ -369,7 +369,7 @@ void CMStrooper::Spawn()
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0; pev->effects = 0;
pev->health = gSkillData.strooperHealth; if (!pev->health) { pev->health = gSkillData.strooperHealth; }
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;
m_flNextGrenadeCheck = gpGlobals->time + 1; m_flNextGrenadeCheck = gpGlobals->time + 1;

View File

@@ -106,7 +106,7 @@ void CMStukabat :: Spawn()
pev->movetype = MOVETYPE_FLY; pev->movetype = MOVETYPE_FLY;
pev->flags |= FL_FLY; pev->flags |= FL_FLY;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->health = gSkillData.stukabatHealth; if (!pev->health) { pev->health = gSkillData.stukabatHealth; }
pev->view_ofs = Vector ( 0, 0, 22 );// position of the eyes relative to monster's origin. pev->view_ofs = Vector ( 0, 0, 22 );// position of the eyes relative to monster's origin.
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;

View File

@@ -226,7 +226,7 @@ void CMBaseDelay :: SUB_UseTargets( edict_t *pActivator, USE_TYPE useType, float
pentKillTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_iszKillTarget) ); pentKillTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_iszKillTarget) );
while ( !FNullEnt(pentKillTarget) ) while ( !FNullEnt(pentKillTarget) )
{ {
UTIL_Remove( CMBaseEntity::Instance(pentKillTarget)->edict() ); UTIL_Remove( pentKillTarget );
ALERT( at_aiconsole, "killing %s\n", STRING( pentKillTarget->v.classname ) ); ALERT( at_aiconsole, "killing %s\n", STRING( pentKillTarget->v.classname ) );
pentKillTarget = FIND_ENTITY_BY_TARGETNAME( pentKillTarget, STRING(m_iszKillTarget) ); pentKillTarget = FIND_ENTITY_BY_TARGETNAME( pentKillTarget, STRING(m_iszKillTarget) );

View File

@@ -125,7 +125,7 @@ void CMTurret::Spawn()
{ {
Precache( ); Precache( );
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/turret.mdl")); SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/turret.mdl"));
pev->health = gSkillData.turretHealth; if (!pev->health) { pev->health = gSkillData.turretHealth; }
m_HackedGunPos = Vector( 0, 0, 12.75 ); m_HackedGunPos = Vector( 0, 0, 12.75 );
m_flMaxSpin = TURRET_MAXSPIN; m_flMaxSpin = TURRET_MAXSPIN;
pev->view_ofs.z = 12.75; pev->view_ofs.z = 12.75;
@@ -165,7 +165,7 @@ void CMMiniTurret::Spawn()
{ {
Precache( ); Precache( );
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/miniturret.mdl")); SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/miniturret.mdl"));
pev->health = gSkillData.miniturretHealth; if (!pev->health) { pev->health = gSkillData.miniturretHealth; }
m_HackedGunPos = Vector( 0, 0, 12.75 ); m_HackedGunPos = Vector( 0, 0, 12.75 );
m_flMaxSpin = 0; m_flMaxSpin = 0;
pev->view_ofs.z = 12.75; pev->view_ofs.z = 12.75;
@@ -1019,7 +1019,7 @@ void CMSentry::Spawn()
{ {
Precache( ); Precache( );
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/sentry.mdl")); SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/sentry.mdl"));
pev->health = gSkillData.sentryHealth; if (!pev->health) { pev->health = gSkillData.sentryHealth; }
m_HackedGunPos = Vector( 0, 0, 48 ); m_HackedGunPos = Vector( 0, 0, 48 );
pev->view_ofs.z = 48; pev->view_ofs.z = 48;
m_flMaxWait = 1E6; m_flMaxWait = 1E6;

View File

@@ -1564,9 +1564,9 @@ void UTIL_Remove( edict_t *pEntity )
if ( !pEntity ) if ( !pEntity )
return; return;
//jlb pEntity->UpdateOnRemove(); //pEntity->UpdateOnRemove();
pEntity->v.flags |= FL_KILLME;
pEntity->v.targetname = 0; pEntity->v.targetname = 0;
pEntity->v.flags |= FL_KILLME;
} }

View File

@@ -644,7 +644,7 @@ void CMVoltigore::Spawn()
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0; pev->effects = 0;
pev->health = gSkillData.voltigoreHealth; if (!pev->health) { pev->health = gSkillData.voltigoreHealth; }
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;
@@ -1152,7 +1152,7 @@ void CMBabyVoltigore::Spawn()
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0; pev->effects = 0;
pev->health = gSkillData.babyVoltigoreHealth; if (!pev->health) { pev->health = gSkillData.babyVoltigoreHealth; }
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;

377
src/dlls/xenmaker.cpp Normal file
View File

@@ -0,0 +1,377 @@
//=========================================================
// Xen Maker - Sven Co-op's env_xenmaker.
// Spawns a monster with visual/auditive teleportation effects.
//=========================================================
#include "extdll.h"
#include "util.h"
#include "cmbase.h"
#include "cmbasemonster.h"
#include "cmbaseextra.h"
#include "monsters.h"
// Xenmaker spawnflags
#define SF_XENMAKER_TRY_ONCE 1 // only one attempt to spawn each time it is fired
#define SF_XENMAKER_NO_SPAWN 2 // don't spawn anything, only do effects
#define SF_XENMAKER_NO_LIGHT 4 // don't do light effect
#define SF_XENMAKER_NO_BEAMS 8 // don't do beam effects
#define SF_XENMAKER_NO_SPRITE 16 // don't do sprite effects
#define SF_XENMAKER_NO_SOUND 32 // don't do sound effect
extern monster_type_t monster_types[];
extern edict_t* spawn_monster(int monster_type, Vector origin, Vector angles, int spawnflags, pKVD *keyvalue);
// ========================================================
void CMXenMaker::KeyValue(KeyValueData *pkvd)
{
if (FStrEq(pkvd->szKeyName, "monstertype"))
{
// Process monster_index
int mIndex;
for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++)
{
if (strcmp(pkvd->szValue, monster_types[mIndex].name) == 0)
{
m_iMonsterIndex = mIndex;
break; // grab the first entry we find
}
}
if (monster_types[mIndex].name[0] == 0)
{
ALERT(at_console, "[MONSTER] XenMaker - %s is not a valid monster type!\n", pkvd->szValue);
m_iMonsterIndex = -1;
}
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_flBeamRadius"))
{
m_flBeamRadius = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_iBeamAlpha"))
{
m_iBeamAlpha = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_iBeamCount"))
{
m_iBeamCount = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_vBeamColor"))
{
UTIL_StringToVector(m_vBeamColor, pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_flLightRadius"))
{
m_flLightRadius = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_vLightColor"))
{
UTIL_StringToVector(m_vLightColor, pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_flStartSpriteFramerate"))
{
m_flStartSpriteFramerate = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_flStartSpriteScale"))
{
m_flStartSpriteScale = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_iStartSpriteAlpha"))
{
m_iStartSpriteAlpha = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_vStartSpriteColor"))
{
UTIL_StringToVector(m_vStartSpriteColor, pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_flEndSpriteFramerate"))
{
m_flEndSpriteFramerate = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_flEndSpriteScale"))
{
m_flEndSpriteScale = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_iEndSpriteAlpha"))
{
m_iEndSpriteAlpha = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_vEndSpriteColor"))
{
UTIL_StringToVector(m_vEndSpriteColor, pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CMBaseMonster::KeyValue(pkvd);
}
void CMXenMaker::Spawn()
{
// likely omitted keyvalue, but it could truly be an alien grunt spawn
if (m_iMonsterIndex == 0)
{
if (!monster_types[0].need_to_precache)
{
// monstertype was not defined, it may be intentional if nothing is to spawn here
if (!FBitSet(pev->spawnflags, SF_XENMAKER_NO_SPAWN))
ALERT(at_console, "[MONSTER] Spawned a env_xenmaker entity without a monstertype! targetname: \"%s\"\n", STRING(pev->targetname));
m_iMonsterIndex = -1;
}
}
// fix uninitialized keyvalues (default per Sven Co-op's FGD)
if (!m_flStartSpriteScale) m_flStartSpriteScale = 1.0;
if (!m_flEndSpriteScale) m_flEndSpriteScale = 1.0;
if (!m_flStartSpriteFramerate) m_flStartSpriteFramerate = 12;
if (!m_flEndSpriteFramerate) m_flEndSpriteFramerate = 12;
pev->solid = SOLID_NOT;
Precache();
SetUse(&CMXenMaker::CyclicUse); // drop one monster each time we fire
SetThink(&CMXenMaker::SUB_DoNothing);
pev->classname = MAKE_STRING("env_xenmaker");
}
void CMXenMaker::Precache(void)
{
m_iBeamIndex = PRECACHE_MODELINDEX("sprites/lgtning.spr");
PRECACHE_MODEL("sprites/fexplo1.spr");
PRECACHE_MODEL("sprites/xflare1.spr");
PRECACHE_SOUND("debris/beamstart7.wav");
PRECACHE_SOUND("debris/beamstart2.wav");
CMBaseMonster::Precache();
// choosen monster is auto-precached
}
//=========================================================
// StartEffect - spawns the monster and starts the effects
//=========================================================
void CMXenMaker::StartEffect(void)
{
if (!FBitSet(pev->spawnflags, SF_XENMAKER_NO_SPAWN))
{
// monstermaker incorrectly setup
if (m_iMonsterIndex == -1)
{
ALERT(at_console, "[MONSTER] NULL Ent in XenMaker!\n");
return;
}
edict_t *pent;
Vector mins = pev->origin - Vector(34, 34, 34);
Vector maxs = pev->origin + Vector(34, 34, 34);
edict_t *pList[2];
int count = UTIL_EntitiesInBox(pList, 2, mins, maxs, FL_CLIENT | FL_MONSTER);
if (!count)
{
// Attempt to spawn monster
pent = spawn_monster(m_iMonsterIndex, pev->origin, pev->angles, 0, NULL);
if (pent == NULL)
{
ALERT(at_console, "[MONSTER] XenMaker - failed to spawn monster! targetname: \"%s\"\n", STRING(pev->targetname));
return;
}
else
pent->v.spawnflags |= SF_MONSTER_FADECORPSE;
}
else if (!FBitSet(pev->spawnflags, SF_XENMAKER_TRY_ONCE))
{
// wait until spawnpoint is clear
pev->nextthink = gpGlobals->time + 1;
SetUse(NULL);
SetThink(&CMXenMaker::RetryThink);
return; // don't do effects
}
else
{
// no effects here, either
return;
}
}
// BEAM EFFECT
if (!FBitSet(pev->spawnflags, SF_XENMAKER_NO_BEAMS))
{
for (int beam = 0; beam < m_iBeamCount; beam++)
{
SpawnBeam();
}
}
// LIGHT EFFECT
if (!FBitSet(pev->spawnflags, SF_XENMAKER_NO_LIGHT))
{
MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY);
WRITE_BYTE(TE_DLIGHT);
WRITE_COORD(pev->origin.x);
WRITE_COORD(pev->origin.y);
WRITE_COORD(pev->origin.z);
WRITE_BYTE((int)(m_flLightRadius / 10));
WRITE_BYTE((int)m_vLightColor.x);
WRITE_BYTE((int)m_vLightColor.y);
WRITE_BYTE((int)m_vLightColor.z);
WRITE_BYTE(10); // life
WRITE_BYTE(0); // decay rate
MESSAGE_END();
}
// SPRITE EFFECT
if (!FBitSet(pev->spawnflags, SF_XENMAKER_NO_SPRITE))
{
CMSprite *pSprite = CMSprite::SpriteCreate("sprites/fexplo1.spr", pev->origin, FALSE);
if (pSprite)
{
pSprite->SetScale(m_flStartSpriteScale);
pSprite->SetTransparency(kRenderGlow, (int)m_vStartSpriteColor.x, (int)m_vStartSpriteColor.y, (int)m_vStartSpriteColor.z, m_iStartSpriteAlpha, kRenderFxNoDissipation);
pSprite->AnimateAndDie(m_flStartSpriteFramerate);
}
}
// SOUND EFFECT
if (!FBitSet(pev->spawnflags, SF_XENMAKER_NO_SOUND))
EMIT_SOUND_DYN(ENT(pev), CHAN_AUTO, "debris/beamstart7.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
pev->nextthink = gpGlobals->time + 0.5;
SetUse(NULL);
SetThink(&CMXenMaker::MiddleEffect);
}
//=========================================================
// MiddleEffect - second set of effects
//=========================================================
void CMXenMaker::MiddleEffect(void)
{
// SPRITE EFFECT
if (!FBitSet(pev->spawnflags, SF_XENMAKER_NO_SPRITE))
{
CMSprite *pSprite = CMSprite::SpriteCreate("sprites/xflare1.spr", pev->origin, FALSE);
if (pSprite)
{
pSprite->SetScale(m_flEndSpriteScale);
pSprite->SetTransparency(kRenderGlow, (int)m_vEndSpriteColor.x, (int)m_vEndSpriteColor.y, (int)m_vEndSpriteColor.z, m_iEndSpriteAlpha, kRenderFxNoDissipation);
pSprite->AnimateAndDie(m_flEndSpriteFramerate);
}
}
pev->nextthink = gpGlobals->time + 0.5;
SetThink(&CMXenMaker::EndEffect);
}
//=========================================================
// EndEffect - final set of effects
//=========================================================
void CMXenMaker::EndEffect(void)
{
// SOUND EFFECT
if (!FBitSet(pev->spawnflags, SF_XENMAKER_NO_SOUND))
EMIT_SOUND_DYN(ENT(pev), CHAN_AUTO, "debris/beamstart2.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
SetUse(&CMXenMaker::CyclicUse);
SetThink(&CMXenMaker::SUB_DoNothing);
}
//=========================================================
// CyclicUse - drops one monster from the xen maker
// each time we call this.
//=========================================================
void CMXenMaker::CyclicUse(edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value)
{
StartEffect();
}
//=========================================================
// RetryThink - try spawning again if spawn was obstructed
//=========================================================
void CMXenMaker::RetryThink(void)
{
SetUse(&CMXenMaker::CyclicUse);
SetThink(&CMXenMaker::SUB_DoNothing);
StartEffect();
}
//=========================================================
// SpawnBeam - calculates beam end position and creates it.
// starting position is the origin of the xenmaker itself.
//=========================================================
void CMXenMaker::SpawnBeam(void)
{
// CLightning::RandomArea
for (int iLoops = 0; iLoops < 10; iLoops++)
{
Vector vecSrc = pev->origin;
Vector vecDir1 = Vector(RANDOM_FLOAT(-1.0, 1.0), RANDOM_FLOAT(-1.0, 1.0), RANDOM_FLOAT(-1.0, 1.0));
vecDir1 = vecDir1.Normalize();
TraceResult tr1;
UTIL_TraceLine(vecSrc, vecSrc + vecDir1 * m_flBeamRadius, ignore_monsters, ENT(pev), &tr1);
if (tr1.flFraction == 1.0)
continue;
Vector vecDir2;
do
{
vecDir2 = Vector(RANDOM_FLOAT(-1.0, 1.0), RANDOM_FLOAT(-1.0, 1.0), RANDOM_FLOAT(-1.0, 1.0));
} while (DotProduct(vecDir1, vecDir2) > 0);
vecDir2 = vecDir2.Normalize();
TraceResult tr2;
UTIL_TraceLine(vecSrc, vecSrc + vecDir2 * m_flBeamRadius, ignore_monsters, ENT(pev), &tr2);
if (tr2.flFraction == 1.0)
continue;
if ((tr1.vecEndPos - tr2.vecEndPos).Length() < m_flBeamRadius * 0.1)
continue;
UTIL_TraceLine(tr1.vecEndPos, tr2.vecEndPos, ignore_monsters, ENT(pev), &tr2);
if (tr2.flFraction != 1.0)
continue;
// CLightning::Zap
MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY);
WRITE_BYTE(TE_BEAMPOINTS);
WRITE_COORD(tr1.vecEndPos.x);
WRITE_COORD(tr1.vecEndPos.y);
WRITE_COORD(tr1.vecEndPos.z);
WRITE_COORD(tr2.vecEndPos.x);
WRITE_COORD(tr2.vecEndPos.y);
WRITE_COORD(tr2.vecEndPos.z);
WRITE_SHORT(m_iBeamIndex);
WRITE_BYTE(0); // starting frame
WRITE_BYTE(10); // framerate
WRITE_BYTE(10); // life
WRITE_BYTE(16); // width
WRITE_BYTE(64); // noise
WRITE_BYTE((int)m_vBeamColor.x);
WRITE_BYTE((int)m_vBeamColor.y);
WRITE_BYTE((int)m_vBeamColor.z);
WRITE_BYTE(m_iBeamAlpha);
WRITE_BYTE(15); // speed
MESSAGE_END();
break;
}
}

View File

@@ -242,7 +242,7 @@ void CMZombie :: Spawn()
pev->solid = SOLID_SLIDEBOX; pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP; pev->movetype = MOVETYPE_STEP;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor; m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->health = gSkillData.zombieHealth; if (!pev->health) { pev->health = gSkillData.zombieHealth; }
pev->view_ofs = VEC_VIEW;// position of the eyes relative to monster's origin. pev->view_ofs = VEC_VIEW;// position of the eyes relative to monster's origin.
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE; m_MonsterState = MONSTERSTATE_NONE;