Fixed wrong classname for Voltigore and Baby Voltigore.
Fixed unknown classnames showing as '}'. Remove monster respawn. Add 'monstermaker' entity.
This commit is contained in:
@@ -601,7 +601,6 @@ template <class T> T * CreateClassPtr( T *a )
|
|||||||
// store the class pointer in the array here!!!
|
// store the class pointer in the array here!!!
|
||||||
monsters[monster_index].monster_index = edict_index;
|
monsters[monster_index].monster_index = edict_index;
|
||||||
monsters[monster_index].monster_pent = temp_edict;
|
monsters[monster_index].monster_pent = temp_edict;
|
||||||
monsters[monster_index].respawn_index = -1;
|
|
||||||
monsters[monster_index].pMonster = (CMBaseMonster *)a;
|
monsters[monster_index].pMonster = (CMBaseMonster *)a;
|
||||||
|
|
||||||
// get the private data
|
// get the private data
|
||||||
|
|||||||
35
src/dlls/cmbaseextra.h
Normal file
35
src/dlls/cmbaseextra.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#ifndef BASEEXTRA_H
|
||||||
|
#define BASEEXTRA_H
|
||||||
|
|
||||||
|
// any extra entities created in this project that aren't
|
||||||
|
// monsters will go here
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// MonsterMaker - this ent creates monsters during the game.
|
||||||
|
//=========================================================
|
||||||
|
class CMMonsterMaker : public CMBaseMonster
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn( void );
|
||||||
|
void Precache( void );
|
||||||
|
void KeyValue( KeyValueData* pkvd);
|
||||||
|
void EXPORT ToggleUse ( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value );
|
||||||
|
void EXPORT CyclicUse ( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value );
|
||||||
|
void EXPORT MakerThink ( void );
|
||||||
|
void DeathNotice ( entvars_t *pevChild );// monster maker children use this to tell the monster maker that they have died.
|
||||||
|
void MakeMonster( void );
|
||||||
|
|
||||||
|
int m_iMonsterIndex;// index of the monster(s) that will be created.
|
||||||
|
|
||||||
|
int m_cNumMonsters;// max number of monsters this ent can create
|
||||||
|
int m_iMaxLiveChildren;// max number of monsters that this maker may have out at one time.
|
||||||
|
|
||||||
|
int m_cLiveChildren;// how many monsters made by this monster maker that are currently alive
|
||||||
|
|
||||||
|
float m_flGround; // z coord of the ground under me, used to make sure no monsters are under the maker when it drops a new child
|
||||||
|
|
||||||
|
BOOL m_fActive;
|
||||||
|
BOOL m_fFadeChildren;// should we make the children fadeout?
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BASEEXTRA_H
|
||||||
@@ -580,7 +580,7 @@ void CMBaseMonster::CallGibMonster( void )
|
|||||||
if (pev->health < -99)
|
if (pev->health < -99)
|
||||||
{
|
{
|
||||||
pev->health = 0;
|
pev->health = 0;
|
||||||
pev->fuser4 = pev->health;
|
pev->fuser4 = pev->health;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ShouldFadeOnDeath() && !fade )
|
if ( ShouldFadeOnDeath() && !fade )
|
||||||
@@ -618,14 +618,11 @@ void CMBaseMonster :: Killed( entvars_t *pevAttacker, int iGib )
|
|||||||
SetConditions( bits_COND_LIGHT_DAMAGE );
|
SetConditions( bits_COND_LIGHT_DAMAGE );
|
||||||
|
|
||||||
// tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality.
|
// tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality.
|
||||||
/*jlb monstermaker
|
|
||||||
CMBaseEntity *pOwner = CMBaseEntity::Instance(pev->owner);
|
CMBaseEntity *pOwner = CMBaseEntity::Instance(pev->owner);
|
||||||
if ( pOwner )
|
if ( pOwner )
|
||||||
{
|
{
|
||||||
//jlb it crashes here sometimes!!!
|
|
||||||
pOwner->DeathNotice( pev );
|
pOwner->DeathNotice( pev );
|
||||||
}
|
}
|
||||||
jlb*/
|
|
||||||
|
|
||||||
if ( ShouldGibMonster( iGib ) )
|
if ( ShouldGibMonster( iGib ) )
|
||||||
{
|
{
|
||||||
@@ -642,7 +639,7 @@ jlb*/
|
|||||||
if (pev->health < -99)
|
if (pev->health < -99)
|
||||||
{
|
{
|
||||||
pev->health = 0;
|
pev->health = 0;
|
||||||
pev->fuser4 = pev->health;
|
pev->fuser4 = pev->health;
|
||||||
}
|
}
|
||||||
|
|
||||||
//pev->enemy = ENT( pevAttacker );//why? (sjb)
|
//pev->enemy = ENT( pevAttacker );//why? (sjb)
|
||||||
@@ -894,8 +891,8 @@ int CMBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker
|
|||||||
// do the damage
|
// do the damage
|
||||||
pev->health -= flTake;
|
pev->health -= flTake;
|
||||||
|
|
||||||
if (pev->flags & FL_MONSTER)
|
if (pev->flags & FL_MONSTER)
|
||||||
pev->fuser4 = pev->health;
|
pev->fuser4 = pev->health;
|
||||||
|
|
||||||
// HACKHACK Don't kill monsters in a script. Let them break their scripts first
|
// HACKHACK Don't kill monsters in a script. Let them break their scripts first
|
||||||
if ( m_MonsterState == MONSTERSTATE_SCRIPT )
|
if ( m_MonsterState == MONSTERSTATE_SCRIPT )
|
||||||
@@ -1005,13 +1002,13 @@ int CMBaseMonster :: DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAtta
|
|||||||
if ( pev->health <= flDamage )
|
if ( pev->health <= flDamage )
|
||||||
{
|
{
|
||||||
pev->health = -50;
|
pev->health = -50;
|
||||||
pev->fuser4 = pev->health;
|
pev->fuser4 = pev->health;
|
||||||
Killed( pevAttacker, GIB_ALWAYS );
|
Killed( pevAttacker, GIB_ALWAYS );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Accumulate corpse gibbing damage, so you can gib with multiple hits
|
// Accumulate corpse gibbing damage, so you can gib with multiple hits
|
||||||
pev->health -= flDamage * 0.1;
|
pev->health -= flDamage * 0.1;
|
||||||
pev->fuser4 = pev->health;
|
pev->fuser4 = pev->health;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
#include "cmbase.h"
|
#include "cmbase.h"
|
||||||
#include "cmbasemonster.h"
|
#include "cmbasemonster.h"
|
||||||
|
#include "cmbaseextra.h"
|
||||||
#include "monsters.h"
|
#include "monsters.h"
|
||||||
#include "weapons.h"
|
#include "weapons.h"
|
||||||
#include "hornet.h"
|
#include "hornet.h"
|
||||||
@@ -158,14 +159,15 @@ monster_type_t monster_types[]=
|
|||||||
"monster_pitdrone", FALSE,
|
"monster_pitdrone", FALSE,
|
||||||
"monster_shockroach", FALSE,
|
"monster_shockroach", FALSE,
|
||||||
"monster_shocktrooper", FALSE,
|
"monster_shocktrooper", FALSE,
|
||||||
"monster_voltigore", FALSE,
|
"monster_alien_voltigore", FALSE,
|
||||||
"monster_baby_voltigore", FALSE,
|
"monster_alien_babyvoltigore", FALSE,
|
||||||
"monster_babygarg", FALSE, // Sven Co-op Monsters
|
"monster_babygarg", FALSE, // Sven Co-op Monsters
|
||||||
"monster_hwgrunt", FALSE,
|
"monster_hwgrunt", FALSE,
|
||||||
"monster_robogrunt", FALSE,
|
"monster_robogrunt", FALSE,
|
||||||
"monster_stukabat", FALSE,
|
"monster_stukabat", FALSE,
|
||||||
"info_node", FALSE, // Nodes
|
"info_node", FALSE, // Nodes
|
||||||
"info_node_air", FALSE,
|
"info_node_air", FALSE,
|
||||||
|
"monstermaker", FALSE, // Extra entities
|
||||||
"", FALSE
|
"", FALSE
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -209,15 +211,6 @@ int GetMonsterIndex(void)
|
|||||||
|
|
||||||
void FreeMonsterIndex(int index)
|
void FreeMonsterIndex(int index)
|
||||||
{
|
{
|
||||||
int idx = monsters[index].respawn_index;
|
|
||||||
|
|
||||||
if (idx != -1)
|
|
||||||
{
|
|
||||||
monster_spawnpoint[idx].need_to_respawn = TRUE;
|
|
||||||
monster_spawnpoint[idx].respawn_time = gpGlobals->time +
|
|
||||||
monster_spawnpoint[idx].delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete monsters[index].pMonster;
|
delete monsters[index].pMonster;
|
||||||
|
|
||||||
monsters[index].monster_index = 0;
|
monsters[index].monster_index = 0;
|
||||||
@@ -557,7 +550,7 @@ void check_monster_info( edict_t *pPlayer )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_index, int spawnflags, pKVD *keyvalue)
|
edict_t* spawn_monster(int monster_type, Vector origin, Vector angles, int spawnflags, pKVD *keyvalue)
|
||||||
{
|
{
|
||||||
int monster_index;
|
int monster_index;
|
||||||
edict_t *monster_pent;
|
edict_t *monster_pent;
|
||||||
@@ -567,7 +560,7 @@ bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_i
|
|||||||
{
|
{
|
||||||
//META_CONS("[MONSTER] ERROR: No FREE Monster edicts!");
|
//META_CONS("[MONSTER] ERROR: No FREE Monster edicts!");
|
||||||
LOG_MESSAGE(PLID, "ERROR: No FREE Monster edicts!");
|
LOG_MESSAGE(PLID, "ERROR: No FREE Monster edicts!");
|
||||||
return TRUE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// was this monster NOT precached?
|
// was this monster NOT precached?
|
||||||
@@ -601,11 +594,12 @@ bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_i
|
|||||||
LOG_MESSAGE(PLID, "%s", msg);
|
LOG_MESSAGE(PLID, "%s", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (monster_type)
|
switch (monster_type)
|
||||||
{
|
{
|
||||||
|
// Monsters
|
||||||
case 0: monsters[monster_index].pMonster = CreateClassPtr((CMAGrunt *)NULL); break;
|
case 0: monsters[monster_index].pMonster = CreateClassPtr((CMAGrunt *)NULL); break;
|
||||||
case 1: monsters[monster_index].pMonster = CreateClassPtr((CMApache *)NULL); break;
|
case 1: monsters[monster_index].pMonster = CreateClassPtr((CMApache *)NULL); break;
|
||||||
case 2: monsters[monster_index].pMonster = CreateClassPtr((CMBarney *)NULL); break;
|
case 2: monsters[monster_index].pMonster = CreateClassPtr((CMBarney *)NULL); break;
|
||||||
@@ -636,17 +630,17 @@ bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_i
|
|||||||
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;
|
case 28: monsters[monster_index].pMonster = CreateClassPtr((CMRGrunt *)NULL); break;
|
||||||
case 29: monsters[monster_index].pMonster = CreateClassPtr((CMStukabat *)NULL); break;
|
case 29: monsters[monster_index].pMonster = CreateClassPtr((CMStukabat *)NULL); break;
|
||||||
|
// Extra entities
|
||||||
|
case 32: monsters[monster_index].pMonster = CreateClassPtr((CMMonsterMaker *)NULL); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (monsters[monster_index].pMonster == NULL)
|
if (monsters[monster_index].pMonster == NULL)
|
||||||
{
|
{
|
||||||
//META_CONS("[MONSTER] ERROR: Error Creating Monster!" );
|
//META_CONS("[MONSTER] ERROR: Error Creating Monster!" );
|
||||||
LOG_MESSAGE(PLID, "ERROR: Error Creating Monster!");
|
LOG_MESSAGE(PLID, "ERROR: Error Creating Monster!");
|
||||||
return TRUE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
monsters[monster_index].respawn_index = respawn_index;
|
|
||||||
|
|
||||||
monster_pent = ENT(monsters[monster_index].pMonster->pev);
|
monster_pent = ENT(monsters[monster_index].pMonster->pev);
|
||||||
monsters[monster_index].monster_pent = monster_pent;
|
monsters[monster_index].monster_pent = monster_pent;
|
||||||
|
|
||||||
@@ -673,15 +667,19 @@ bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_i
|
|||||||
|
|
||||||
monsters[monster_index].pMonster->Spawn();
|
monsters[monster_index].pMonster->Spawn();
|
||||||
|
|
||||||
// Reverse fadecorpse behaviour
|
// Only modify starting spawnflags for monsters, not for entities!
|
||||||
if ( ( spawnflags & SF_MONSTER_FADECORPSE ) )
|
if ( monster_index <= 29 )
|
||||||
monster_pent->v.spawnflags &= ~SF_MONSTER_FADECORPSE;
|
{
|
||||||
else
|
// Reverse fadecorpse behaviour
|
||||||
monster_pent->v.spawnflags |= SF_MONSTER_FADECORPSE;
|
if ( ( spawnflags & SF_MONSTER_FADECORPSE ) )
|
||||||
|
monster_pent->v.spawnflags &= ~SF_MONSTER_FADECORPSE;
|
||||||
|
else
|
||||||
|
monster_pent->v.spawnflags |= SF_MONSTER_FADECORPSE;
|
||||||
|
}
|
||||||
|
|
||||||
monster_pent->v.fuser4 = monster_pent->v.health; // save the original health
|
monster_pent->v.fuser4 = monster_pent->v.health; // save the original health
|
||||||
|
|
||||||
return FALSE;
|
return monster_pent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -698,8 +696,7 @@ void check_respawn(void)
|
|||||||
|
|
||||||
for (int index=0; index < monster_spawn_count; index++)
|
for (int index=0; index < monster_spawn_count; index++)
|
||||||
{
|
{
|
||||||
if (monster_spawnpoint[index].need_to_respawn &&
|
if (monster_spawnpoint[index].need_to_respawn)
|
||||||
(monster_spawnpoint[index].respawn_time <= gpGlobals->time))
|
|
||||||
{
|
{
|
||||||
monster_spawnpoint[index].need_to_respawn = FALSE;
|
monster_spawnpoint[index].need_to_respawn = FALSE;
|
||||||
|
|
||||||
@@ -713,12 +710,10 @@ void check_respawn(void)
|
|||||||
|
|
||||||
keyvalue = monster_spawnpoint[index].keyvalue;
|
keyvalue = monster_spawnpoint[index].keyvalue;
|
||||||
|
|
||||||
if (spawn_monster(monster_type, origin, angles, index, spawnflags, keyvalue))
|
if (spawn_monster(monster_type, origin, angles, spawnflags, keyvalue) == NULL)
|
||||||
{
|
{
|
||||||
// spawn_monster failed, retry again after delay...
|
// spawn_monster failed
|
||||||
monster_spawnpoint[index].need_to_respawn = TRUE;
|
ALERT( at_error, "Failed to spawn %s at origin %f %f %f\n", monster_types[monster_type].name, origin.x, origin.y, origin.z );
|
||||||
monster_spawnpoint[index].respawn_time = gpGlobals->time +
|
|
||||||
monster_spawnpoint[index].delay;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -886,7 +881,7 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -914,9 +909,9 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -942,7 +937,7 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -969,7 +964,7 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -996,7 +991,7 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1023,7 +1018,7 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1294,8 +1289,9 @@ void mmDispatchTouch( edict_t *pentTouched, edict_t *pentOther )
|
|||||||
void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
CMAGrunt agrunt;
|
// Monsters
|
||||||
|
CMAGrunt agrunt; // 0
|
||||||
CMApache apache;
|
CMApache apache;
|
||||||
CMBarney barney;
|
CMBarney barney;
|
||||||
CMBigMomma bigmomma;
|
CMBigMomma bigmomma;
|
||||||
@@ -1324,7 +1320,10 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
|||||||
CMBabyGargantua babygargantua;
|
CMBabyGargantua babygargantua;
|
||||||
CMHWGrunt hwgrunt;
|
CMHWGrunt hwgrunt;
|
||||||
CMRGrunt rgrunt;
|
CMRGrunt rgrunt;
|
||||||
CMStukabat stukabat;
|
CMStukabat stukabat; // 29
|
||||||
|
|
||||||
|
// Extra entities
|
||||||
|
CMMonsterMaker monstermaker; // 32
|
||||||
|
|
||||||
g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" );
|
g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" );
|
||||||
|
|
||||||
@@ -1372,6 +1371,7 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
|||||||
case 27: hwgrunt.Precache(); break;
|
case 27: hwgrunt.Precache(); break;
|
||||||
case 28: rgrunt.Precache(); break;
|
case 28: rgrunt.Precache(); break;
|
||||||
case 29: stukabat.Precache(); break;
|
case 29: stukabat.Precache(); break;
|
||||||
|
case 32: monstermaker.Precache(); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
// Now that I think about it this looks slow and bad code >.>
|
// Now that I think about it this looks slow and bad code >.>
|
||||||
|
|
||||||
// A match is found. What is this?
|
// A match is found. What is this?
|
||||||
if (strncmp(monster_types[mIndex].name, "monster", 7) == 0)
|
if (strncmp(monster_types[mIndex].name, "monster_", 8) == 0)
|
||||||
{
|
{
|
||||||
// It's a monster, add it to the list
|
// It's a monster, add it to the list
|
||||||
if (monster_spawn_count == MAX_MONSTERS)
|
if (monster_spawn_count == MAX_MONSTERS)
|
||||||
@@ -110,6 +110,22 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
monster = TRUE;
|
monster = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strcmp(monster_types[mIndex].name, "monstermaker") == 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
|
||||||
@@ -142,7 +158,7 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
}
|
}
|
||||||
if (monster_types[mIndex].name[0] == 0)
|
if (monster_types[mIndex].name[0] == 0)
|
||||||
{
|
{
|
||||||
LOG_MESSAGE(PLID, "ERROR: unknown classname: %s", input); // print conflictive line
|
LOG_MESSAGE(PLID, "ERROR: unknown classname: %s", data[kvd_index-1].value); // print conflictive line
|
||||||
LOG_MESSAGE(PLID, "ERROR: nothing will spawn here!");
|
LOG_MESSAGE(PLID, "ERROR: nothing will spawn here!");
|
||||||
badent = TRUE;
|
badent = TRUE;
|
||||||
}
|
}
|
||||||
@@ -150,8 +166,8 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// What are you doing?!
|
// What are you doing?!
|
||||||
LOG_MESSAGE(PLID, "ERROR: BAD ENTITY STRUCTURE! Last line was %s", input); // print conflictive line
|
LOG_MESSAGE(PLID, "ERROR: BAD ENTITY STRUCTURE! Last line was %s", data[kvd_index-1].key); // print conflictive line
|
||||||
LOG_MESSAGE(PLID, "ERROR: nothing will spawn here!");
|
LOG_MESSAGE(PLID, "ERROR: classname MUST be the last entry of the entity!" );
|
||||||
badent = TRUE;
|
badent = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,23 +208,6 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
node_spawnpoint[node_spawn_count].origin[2] = z;
|
node_spawnpoint[node_spawn_count].origin[2] = z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strcmp(data[i].key, "delay") == 0)
|
|
||||||
{
|
|
||||||
// ToDo: Remove this keyvalue.
|
|
||||||
// Monsters spawned directly should not respawn.
|
|
||||||
if (monster)
|
|
||||||
{
|
|
||||||
if (sscanf(data[i].value, "%f", &x) != 1)
|
|
||||||
{
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: invalid delay: %s", input); // print conflictive line
|
|
||||||
|
|
||||||
// default to 30 seconds
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: entity respawn frequency will be set to 30 seconds");
|
|
||||||
x = 30;
|
|
||||||
}
|
|
||||||
monster_spawnpoint[monster_spawn_count].delay = x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(data[i].key, "angles") == 0)
|
else if (strcmp(data[i].key, "angles") == 0)
|
||||||
{
|
{
|
||||||
if (monster)
|
if (monster)
|
||||||
@@ -241,6 +240,30 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
monster_spawnpoint[monster_spawn_count].spawnflags = x;
|
monster_spawnpoint[monster_spawn_count].spawnflags = x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strcmp(data[i].key, "monstertype") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
// this keyvalue is only valid for monstermaker entity
|
||||||
|
if (strcmp(data[kvd_index-1].value, "monstermaker") == 0)
|
||||||
|
{
|
||||||
|
// process the entity precache here
|
||||||
|
int mIndex;
|
||||||
|
for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++)
|
||||||
|
{
|
||||||
|
if (strcmp(data[i].value, monster_types[mIndex].name) == 0)
|
||||||
|
{
|
||||||
|
monster_types[mIndex].need_to_precache = TRUE;
|
||||||
|
break; // only one monster at a time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pass the keyvalue to the entity
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
|
||||||
|
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.
|
||||||
@@ -255,8 +278,7 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
|
|
||||||
if (monster)
|
if (monster)
|
||||||
{
|
{
|
||||||
// Init monster
|
// Spawn right away
|
||||||
monster_spawnpoint[monster_spawn_count].respawn_time = gpGlobals->time + 0.1; // spawn (nearly) right away
|
|
||||||
monster_spawnpoint[monster_spawn_count].need_to_respawn = TRUE;
|
monster_spawnpoint[monster_spawn_count].need_to_respawn = TRUE;
|
||||||
monster_spawn_count++;
|
monster_spawn_count++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,6 +218,10 @@ SOURCE=.\monster_config.cpp
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\monstermaker.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\monsters.cpp
|
SOURCE=.\monsters.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
@@ -330,6 +334,10 @@ SOURCE=.\cmbase.h
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\cmbaseextra.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\cmbasemonster.h
|
SOURCE=.\cmbasemonster.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ typedef struct
|
|||||||
int monster_index;
|
int monster_index;
|
||||||
edict_t *monster_pent;
|
edict_t *monster_pent;
|
||||||
bool killed;
|
bool killed;
|
||||||
int respawn_index;
|
|
||||||
CMBaseMonster *pMonster;
|
CMBaseMonster *pMonster;
|
||||||
} monster_t;
|
} monster_t;
|
||||||
|
|
||||||
@@ -38,11 +37,9 @@ extern monster_t monsters[MAX_MONSTER_ENTS];
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
Vector origin;
|
Vector origin;
|
||||||
Vector angles;
|
Vector angles;
|
||||||
float delay;
|
|
||||||
unsigned char monster;
|
unsigned char monster;
|
||||||
int spawnflags;
|
int spawnflags;
|
||||||
pKVD *keyvalue;
|
pKVD *keyvalue;
|
||||||
float respawn_time;
|
|
||||||
bool need_to_respawn;
|
bool need_to_respawn;
|
||||||
} monster_spawnpoint_t;
|
} monster_spawnpoint_t;
|
||||||
|
|
||||||
|
|||||||
241
src/dlls/monstermaker.cpp
Normal file
241
src/dlls/monstermaker.cpp
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
/***
|
||||||
|
*
|
||||||
|
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* This product contains software technology licensed from Id
|
||||||
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use, distribution, and modification of this source code and/or resulting
|
||||||
|
* object code is restricted to non-commercial enhancements to products from
|
||||||
|
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||||
|
* without written permission from Valve LLC.
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
//=========================================================
|
||||||
|
// Monster Maker - this is an entity that creates monsters
|
||||||
|
// in the game.
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "cmbase.h"
|
||||||
|
#include "cmbasemonster.h"
|
||||||
|
#include "cmbaseextra.h"
|
||||||
|
#include "monsters.h"
|
||||||
|
|
||||||
|
// Monstermaker spawnflags
|
||||||
|
#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_MONSTERCLIP 8 // Children are blocked by monsterclip
|
||||||
|
|
||||||
|
extern monster_type_t monster_types[];
|
||||||
|
extern edict_t* spawn_monster(int monster_type, Vector origin, Vector angles, int spawnflags, pKVD *keyvalue);
|
||||||
|
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
void CMMonsterMaker :: KeyValue( KeyValueData *pkvd )
|
||||||
|
{
|
||||||
|
if ( FStrEq(pkvd->szKeyName, "monstercount") )
|
||||||
|
{
|
||||||
|
m_cNumMonsters = atoi(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if ( FStrEq(pkvd->szKeyName, "m_imaxlivechildren") )
|
||||||
|
{
|
||||||
|
m_iMaxLiveChildren = atoi(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CMBaseMonster::KeyValue( pkvd );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CMMonsterMaker :: Spawn( )
|
||||||
|
{
|
||||||
|
pev->solid = SOLID_NOT;
|
||||||
|
|
||||||
|
m_cLiveChildren = 0;
|
||||||
|
Precache();
|
||||||
|
if ( !FStringNull ( pev->targetname ) )
|
||||||
|
{
|
||||||
|
if ( pev->spawnflags & SF_MONSTERMAKER_CYCLIC )
|
||||||
|
{
|
||||||
|
SetUse ( &CMMonsterMaker::CyclicUse );// drop one monster each time we fire
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetUse ( &CMMonsterMaker::ToggleUse );// so can be turned on/off
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( FBitSet ( pev->spawnflags, SF_MONSTERMAKER_START_ON ) )
|
||||||
|
{// start making monsters as soon as monstermaker spawns
|
||||||
|
m_fActive = TRUE;
|
||||||
|
SetThink ( &CMMonsterMaker::MakerThink );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{// wait to be activated.
|
||||||
|
m_fActive = FALSE;
|
||||||
|
SetThink ( &CMMonsterMaker::SUB_DoNothing );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{// no targetname, just start.
|
||||||
|
pev->nextthink = gpGlobals->time + m_flDelay;
|
||||||
|
m_fActive = TRUE;
|
||||||
|
SetThink ( &CMMonsterMaker::MakerThink );
|
||||||
|
}
|
||||||
|
|
||||||
|
// always fade
|
||||||
|
m_fFadeChildren = TRUE;
|
||||||
|
|
||||||
|
m_flGround = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMMonsterMaker :: Precache( void )
|
||||||
|
{
|
||||||
|
CMBaseMonster::Precache();
|
||||||
|
// choosen monster is auto-precached
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// MakeMonster- this is the code that drops the monster
|
||||||
|
//=========================================================
|
||||||
|
void CMMonsterMaker::MakeMonster( void )
|
||||||
|
{
|
||||||
|
edict_t *pent;
|
||||||
|
int createSF = SF_MONSTER_FALL_TO_GROUND;
|
||||||
|
|
||||||
|
if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren )
|
||||||
|
{// not allowed to make a new one yet. Too many live ones out right now.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !m_flGround )
|
||||||
|
{
|
||||||
|
// set altitude. Now that I'm activated, any breakables, etc should be out from under me.
|
||||||
|
TraceResult tr;
|
||||||
|
|
||||||
|
UTIL_TraceLine ( pev->origin, pev->origin - Vector ( 0, 0, 2048 ), ignore_monsters, ENT(pev), &tr );
|
||||||
|
m_flGround = tr.vecEndPos.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector mins = pev->origin - Vector( 34, 34, 0 );
|
||||||
|
Vector maxs = pev->origin + Vector( 34, 34, 0 );
|
||||||
|
maxs.z = pev->origin.z;
|
||||||
|
mins.z = m_flGround;
|
||||||
|
|
||||||
|
edict_t *pList[2];
|
||||||
|
int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_CLIENT|FL_MONSTER );
|
||||||
|
if ( count )
|
||||||
|
{
|
||||||
|
// don't build a stack of monsters!
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should children hit monsterclip brushes?
|
||||||
|
if ( pev->spawnflags & SF_MONSTERMAKER_MONSTERCLIP )
|
||||||
|
createSF |= SF_MONSTER_HITMONSTERCLIP;
|
||||||
|
|
||||||
|
// Attempt to spawn monster
|
||||||
|
pent = spawn_monster(m_iMonsterIndex, pev->origin, pev->angles, createSF, NULL);
|
||||||
|
if ( pent == NULL )
|
||||||
|
{
|
||||||
|
ALERT ( at_console, "NULL Ent in MonsterMaker!\n" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If I have a target, fire!
|
||||||
|
if ( !FStringNull ( pev->target ) )
|
||||||
|
{
|
||||||
|
// delay already overloaded for this entity, so can't call SUB_UseTargets()
|
||||||
|
FireTargets( STRING(pev->target), this->edict(), this->edict(), USE_TOGGLE, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
pent->v.owner = edict();
|
||||||
|
|
||||||
|
if ( !FStringNull( pev->netname ) )
|
||||||
|
{
|
||||||
|
// if I have a netname (overloaded), give the child monster that name as a targetname
|
||||||
|
pent->v.targetname = pev->netname;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_cLiveChildren++;// count this monster
|
||||||
|
m_cNumMonsters--;
|
||||||
|
|
||||||
|
if ( m_cNumMonsters == 0 )
|
||||||
|
{
|
||||||
|
// Disable this forever. Don't kill it because it still gets death notices
|
||||||
|
SetThink( NULL );
|
||||||
|
SetUse( NULL );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// CyclicUse - drops one monster from the monstermaker
|
||||||
|
// each time we call this.
|
||||||
|
//=========================================================
|
||||||
|
void CMMonsterMaker::CyclicUse ( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value )
|
||||||
|
{
|
||||||
|
MakeMonster();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// ToggleUse - activates/deactivates the monster maker
|
||||||
|
//=========================================================
|
||||||
|
void CMMonsterMaker :: ToggleUse ( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value )
|
||||||
|
{
|
||||||
|
if ( !ShouldToggle( useType, m_fActive ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( m_fActive )
|
||||||
|
{
|
||||||
|
m_fActive = FALSE;
|
||||||
|
SetThink ( NULL );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_fActive = TRUE;
|
||||||
|
SetThink ( &CMMonsterMaker::MakerThink );
|
||||||
|
}
|
||||||
|
|
||||||
|
pev->nextthink = gpGlobals->time;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// MakerThink - creates a new monster every so often
|
||||||
|
//=========================================================
|
||||||
|
void CMMonsterMaker :: MakerThink ( void )
|
||||||
|
{
|
||||||
|
pev->nextthink = gpGlobals->time + m_flDelay;
|
||||||
|
|
||||||
|
MakeMonster();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
//=========================================================
|
||||||
|
void CMMonsterMaker :: DeathNotice ( entvars_t *pevChild )
|
||||||
|
{
|
||||||
|
// ok, we've gotten the deathnotice from our child, now clear out its owner if we don't want it to fade.
|
||||||
|
m_cLiveChildren--;
|
||||||
|
|
||||||
|
if ( !m_fFadeChildren )
|
||||||
|
{
|
||||||
|
pevChild->owner = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,9 +33,6 @@
|
|||||||
|
|
||||||
#define VOLTIGORE_MAX_BEAMS 8
|
#define VOLTIGORE_MAX_BEAMS 8
|
||||||
|
|
||||||
#define VOLTIGORE_CLASSNAME "monster_alien_voltigore"
|
|
||||||
#define VOLTIGORE_BABY_CLASSNAME "monster_alien_babyvoltigore"
|
|
||||||
|
|
||||||
#define VOLTIGORE_ZAP_RED 180
|
#define VOLTIGORE_ZAP_RED 180
|
||||||
#define VOLTIGORE_ZAP_GREEN 16
|
#define VOLTIGORE_ZAP_GREEN 16
|
||||||
#define VOLTIGORE_ZAP_BLUE 255
|
#define VOLTIGORE_ZAP_BLUE 255
|
||||||
|
|||||||
Reference in New Issue
Block a user