Fix Male Assassin unable to use the Sniper Rifle.

Partially fixed the Stukabat being unable to move when target is unreachable.
Removed zombie/gonome bullet resistance.
Add Global Model Replacement and Global Sound Replacement.
Update Tier milestones.
This commit is contained in:
Giegue
2023-04-21 20:55:47 -03:00
parent 66be4861a3
commit bfa59a2419
32 changed files with 448 additions and 212 deletions

View File

@@ -29,7 +29,7 @@ Not anymore...
The first goal of this project aims towards the recreation of the new features of the "obscured and updated" Monster Mod plugin. Taking botman's original 2002 plugin and working from the ground up, the mission is to rebuild it with the new features and monsters that only few were able to see.
The source code is completely free for everyone to use: In the event that the development of this project falls and becomes stagnant again, the plugin will live on, as the project's second goal is its preservation. The original botman's page where you can download the 2002 plugin will not stay up forever.
The source code is completely free for everyone to use: In the event that the development of this project falls and becomes stagnant again, the plugin will live on, as the project's second goal is its preservation. ~~The original botman's page where you can download the 2002 plugin will not stay up forever.~~ **April 2023 update**: The page is gone, the original 2002 plugin can no longer be found.
Under no circumstances shall we allow this project to fade away and become lost amidst the gears of time.
@@ -45,6 +45,8 @@ The plugin -should- be able to be used out-of-the-box by simply downloading the
Additional configuration files are included in the release files, each explaining it's usage and installation instructions.
Extra MonsterMod features can be unlocked with additional AMX Mod X plugins which are located in the `extra` folder. All these plugins are optional, and only required based on your use-case.
## Build Instructions
The [wiki](https://github.com/JulianR0/monstermod-redo/wiki) contains instructions on how to compile MonsterMod by yourself.
@@ -196,15 +198,21 @@ Current milestones are separated by "Tiers", which are as follows:
- Implement reading entities within the BSP itself. **[DONE]**
- Add build instructions. **[DONE]**
- Custom sound support, along with sentences.
- Fix all pending bugs.
- Global Model Replacement. **[DONE]**
- Global Sound Replacement. **[DONE]**
- Miscellaneous customization options, such as blood color.
- Individual sound replacement: "soundlist" keyvalue for monsters.
- Sentences support for speakable monsters.
- Attempt to fix bugs as they appear.
### Tier 5
- Enhance the AI.
- Add configurations to change AI behaviour.
- Optimize code and enhance the AI.
- Create "tool" entities for easier map customization.
- Do more fixes not covered in Tier 4.
- Optimize and clean the code.
- Add a wiki with full documentation.
- Fix **ALL** bugs, specially those not covered in Tier 4.
What will the future hold after all Tiers has been completed?

View File

@@ -19,12 +19,12 @@
#include "extdll.h"
#include "util.h"
#include "cmbase.h"
#include "cmbasemonster.h"
#include "cmbasemonster.h"
#include "monsters.h"
#include "schedule.h"
#include "weapons.h"
#include "hornet.h"
#include "skill.h"
#include "skill.h"
//=========================================================
@@ -532,7 +532,7 @@ void CMAGrunt :: Spawn()
{
Precache( );
SET_MODEL(ENT(pev), "models/agrunt.mdl");
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/agrunt.mdl"));
UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64));
pev->solid = SOLID_SLIDEBOX;
@@ -563,40 +563,23 @@ void CMAGrunt :: Spawn()
//=========================================================
void CMAGrunt :: Precache()
{
int i;
PRECACHE_MODEL("models/agrunt.mdl");
for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
PRECACHE_SOUND((char *)pAttackHitSounds[i]);
PRECACHE_SOUND_ARRAY( pAttackHitSounds );
PRECACHE_SOUND_ARRAY( pAttackHitSounds );
PRECACHE_SOUND_ARRAY( pAttackMissSounds );
PRECACHE_SOUND_ARRAY( pIdleSounds );
PRECACHE_SOUND_ARRAY( pDieSounds );
PRECACHE_SOUND_ARRAY( pPainSounds );
PRECACHE_SOUND_ARRAY( pAttackSounds );
PRECACHE_SOUND_ARRAY( pAlertSounds );
for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
PRECACHE_SOUND((char *)pAttackMissSounds[i]);
iAgruntMuzzleFlash = PRECACHE_MODELINDEX("sprites/muz4.spr");
for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ )
PRECACHE_SOUND((char *)pIdleSounds[i]);
for ( i = 0; i < ARRAYSIZE( pDieSounds ); i++ )
PRECACHE_SOUND((char *)pDieSounds[i]);
for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
PRECACHE_SOUND((char *)pPainSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ )
PRECACHE_SOUND((char *)pAttackSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ )
PRECACHE_SOUND((char *)pAlertSounds[i]);
PRECACHE_SOUND( "hassault/hw_shoot1.wav" );
iAgruntMuzzleFlash = PRECACHE_MODEL( "sprites/muz4.spr" );
CMHornet hornet;
hornet.Precache();
CMHornet hornet;
hornet.Precache();
}
//=========================================================
// AI Schedules Specific to this monster
//=========================================================
@@ -1030,7 +1013,7 @@ Schedule_t *CMAGrunt :: GetSchedule ( void )
// zap player!
if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) )
{
AttackSound();// this is a total hack. Should be parto f the schedule
AttackSound();// this is a total hack. Should be part of the schedule
return GetScheduleOfType ( SCHED_MELEE_ATTACK1 );
}

View File

@@ -213,7 +213,7 @@ void SequencePrecache( void *pmodel, const char *pSequenceName )
ALERT( at_error, "Bad sound event %d in sequence %s :: %s (sound is \"%s\")\n", pevent[i].event, pstudiohdr->name, pSequenceName, pevent[i].options );
}
PRECACHE_SOUND( (char *)(gpGlobals->pStringBase + ALLOC_STRING(pevent[i].options) ) );
PRECACHE_SOUND2( (char *)(gpGlobals->pStringBase + ALLOC_STRING(pevent[i].options) ) );
}
}
}

View File

@@ -105,14 +105,14 @@ void CMApache::Precache( void )
PRECACHE_SOUND("weapons/mortarhit.wav");
m_iSpriteTexture = PRECACHE_MODEL( "sprites/white.spr" );
m_iSpriteTexture = PRECACHE_MODELINDEX( "sprites/white.spr" );
PRECACHE_SOUND("turret/tu_fire1.wav");
PRECACHE_MODEL("sprites/lgtning.spr");
m_iExplode = PRECACHE_MODEL( "sprites/fexplo.spr" );
m_iBodyGibs = PRECACHE_MODEL( "models/metalplategibs_green.mdl" );
m_iExplode = PRECACHE_MODELINDEX( "sprites/fexplo.spr" );
m_iBodyGibs = PRECACHE_MODELINDEX( "models/metalplategibs_green.mdl" );
CMApacheHVR apache_rocket;
apache_rocket.Precache();
@@ -178,7 +178,7 @@ void CMApache :: DyingThink( void )
if (m_flNextRocket > gpGlobals->time )
{
if (g_sModelIndexFireball == 0)
g_sModelIndexFireball = PRECACHE_MODEL ("sprites/zerogxplode.spr"); // fireball
g_sModelIndexFireball = PRECACHE_MODELINDEX("sprites/zerogxplode.spr"); // fireball
// random explosions
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
@@ -193,7 +193,7 @@ void CMApache :: DyingThink( void )
MESSAGE_END();
if (g_sModelIndexSmoke == 0)
g_sModelIndexSmoke = PRECACHE_MODEL ("sprites/steam1.spr"); // smoke
g_sModelIndexSmoke = PRECACHE_MODELINDEX("sprites/steam1.spr"); // smoke
// lots of smoke
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
@@ -930,7 +930,7 @@ void CMApacheHVR :: Spawn( void )
void CMApacheHVR :: Precache( void )
{
PRECACHE_MODEL("models/HVR.mdl");
m_iTrail = PRECACHE_MODEL("sprites/smoke.spr");
m_iTrail = PRECACHE_MODELINDEX("sprites/smoke.spr");
PRECACHE_SOUND ("weapons/rocket1.wav");
}

View File

@@ -648,8 +648,8 @@ void CMBigMomma :: Precache()
// TEMP: Squid
PRECACHE_MODEL("sprites/mommaspit.spr");// spit projectile.
gSpitSprite = PRECACHE_MODEL("sprites/mommaspout.spr");// client side spittle.
gSpitDebrisSprite = PRECACHE_MODEL("sprites/mommablob.spr" );
gSpitSprite = PRECACHE_MODELINDEX("sprites/mommaspout.spr");// client side spittle.
gSpitDebrisSprite = PRECACHE_MODELINDEX("sprites/mommablob.spr" );
PRECACHE_SOUND( "bullchicken/bc_acid1.wav" );
PRECACHE_SOUND( "bullchicken/bc_spithit1.wav" );

View File

@@ -642,7 +642,7 @@ void CMBullsquid :: Precache()
PRECACHE_MODEL("sprites/bigspit.spr");// spit projectile.
iSquidSpitSprite = PRECACHE_MODEL("sprites/tinyspit.spr");// client side spittle.
iSquidSpitSprite = PRECACHE_MODELINDEX("sprites/tinyspit.spr");// client side spittle.
PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event

View File

@@ -608,3 +608,7 @@ template <class T> T * CreateClassPtr( T *a )
return a;
}
#ifndef GLOBALREPLACE_H
#include "globalreplace.h"
#endif

View File

@@ -809,18 +809,18 @@ DLL_GLOBAL short g_sModelIndexLaserDot;// holds the index for the laser beam dot
void world_precache(void)
{
g_sModelIndexFireball = PRECACHE_MODEL ("sprites/zerogxplode.spr");// fireball
g_sModelIndexSmoke = PRECACHE_MODEL ("sprites/steam1.spr");// smoke
g_sModelIndexTinySpit = PRECACHE_MODEL ("sprites/tinyspit.spr");// spore
g_sModelIndexWExplosion = PRECACHE_MODEL ("sprites/WXplo1.spr");// underwater fireball
g_sModelIndexBubbles = PRECACHE_MODEL ("sprites/bubble.spr");//bubbles
g_sModelIndexBloodSpray = PRECACHE_MODEL ("sprites/bloodspray.spr"); // initial blood
g_sModelIndexBloodDrop = PRECACHE_MODEL ("sprites/blood.spr"); // splattered blood
g_sModelIndexFireball = PRECACHE_MODELINDEX("sprites/zerogxplode.spr");// fireball
g_sModelIndexSmoke = PRECACHE_MODELINDEX("sprites/steam1.spr");// smoke
g_sModelIndexTinySpit = PRECACHE_MODELINDEX("sprites/tinyspit.spr");// spore
g_sModelIndexWExplosion = PRECACHE_MODELINDEX("sprites/WXplo1.spr");// underwater fireball
g_sModelIndexBubbles = PRECACHE_MODELINDEX("sprites/bubble.spr");//bubbles
g_sModelIndexBloodSpray = PRECACHE_MODELINDEX("sprites/bloodspray.spr"); // initial blood
g_sModelIndexBloodDrop = PRECACHE_MODELINDEX("sprites/blood.spr"); // splattered blood
g_sModelIndexLaser = PRECACHE_MODEL( (char *)g_pModelNameLaser );
g_sModelIndexLaserDot = PRECACHE_MODEL("sprites/laserdot.spr");
g_sModelIndexLaser = PRECACHE_MODELINDEX( (char *)g_pModelNameLaser );
g_sModelIndexLaserDot = PRECACHE_MODELINDEX("sprites/laserdot.spr");
PRECACHE_MODEL ("models/w_grenade.mdl");
PRECACHE_MODEL("models/w_grenade.mdl");
}
void MonsterCommand(void)
@@ -1265,7 +1265,9 @@ int mmDispatchSpawn( edict_t *pent )
for (index = 0; monster_types[index].name[0]; index++)
monster_types[index].need_to_precache = FALSE;
world_precache();
CVAR_SET_STRING("monster_gmr", "");
CVAR_SET_STRING("monster_gsr", "");
REPLACER::Init();
monster_spawn_count = 0;
node_spawn_count = 0;
@@ -1276,6 +1278,9 @@ int mmDispatchSpawn( edict_t *pent )
process_monster_cfg();
// precache last in the event of a GMR being present
world_precache();
// node support. -Giegue
// init the WorldGraph.
WorldGraph.InitGraph();
@@ -1818,7 +1823,7 @@ void mmMessageEnd_Post( void )
RETURN_META( MRES_IGNORED );
}
/*
enginefuncs_t meta_engfuncs =
{
NULL, // pfnPrecacheModel()
@@ -2042,7 +2047,7 @@ C_DLLEXPORT int GetEngineFunctions(enginefuncs_t *pengfuncsFromEngine, int *inte
memcpy(pengfuncsFromEngine, &meta_engfuncs, sizeof(enginefuncs_t));
return TRUE;
}
*/
enginefuncs_t meta_engfuncs_post =
{
NULL, // pfnPrecacheModel()

View File

@@ -114,7 +114,7 @@ void CMBeam::BeamInit( const char *pSpriteName, int width )
SetFrame( 0 );
SetScrollRate( 0 );
pev->model = MAKE_STRING( pSpriteName );
SetTexture( PRECACHE_MODEL( (char *)pSpriteName ) );
SetTexture( PRECACHE_MODELINDEX( (char *)pSpriteName ) );
SetWidth( width );
pev->skin = 0;
pev->sequence = 0;

View File

@@ -23,10 +23,10 @@ extern enginefuncs_t g_engfuncs;
// The actual engine callbacks
#define GETPLAYERUSERID (*g_engfuncs.pfnGetPlayerUserId)
#define PRECACHE_MODEL (*g_engfuncs.pfnPrecacheModel)
#define PRECACHE_SOUND (*g_engfuncs.pfnPrecacheSound)
#define PRECACHE_MODEL2 (*g_engfuncs.pfnPrecacheModel)
#define PRECACHE_SOUND2 (*g_engfuncs.pfnPrecacheSound)
#define PRECACHE_GENERIC (*g_engfuncs.pfnPrecacheGeneric)
#define SET_MODEL (*g_engfuncs.pfnSetModel)
#define SET_MODEL2 (*g_engfuncs.pfnSetModel)
#define MODEL_INDEX (*g_engfuncs.pfnModelIndex)
#define MODEL_FRAMES (*g_engfuncs.pfnModelFrames)
#define SET_SIZE (*g_engfuncs.pfnSetSize)

View File

@@ -54,7 +54,7 @@ void CMShower::Spawn( void )
pev->speed = RANDOM_FLOAT( 0.5, 1.5 );
pev->angles = g_vecZero;
pev->classname = MAKE_STRING( "_spark_shower" );
pev->classname = MAKE_STRING( "spark_shower" );
}
@@ -172,7 +172,7 @@ void CMEnvExplosion::Spawn( void )
}
m_spriteScale = (int)flSpriteScale;
pev->classname = MAKE_STRING( "_env_explosion" );
pev->classname = MAKE_STRING( "env_explosion" );
}
void CMEnvExplosion::DelayUse( void )

View File

@@ -712,48 +712,25 @@ void CMGargantua :: Spawn()
//=========================================================
void CMGargantua :: Precache()
{
int i;
PRECACHE_MODEL("models/garg.mdl");
PRECACHE_MODEL( GARG_EYE_SPRITE_NAME );
PRECACHE_MODEL( GARG_BEAM_SPRITE_NAME );
PRECACHE_MODEL( GARG_BEAM_SPRITE2 );
gStompSprite = PRECACHE_MODEL( GARG_STOMP_SPRITE_NAME );
gGargGibModel = PRECACHE_MODEL( GARG_GIB_MODEL );
gStompSprite = PRECACHE_MODELINDEX( GARG_STOMP_SPRITE_NAME );
gGargGibModel = PRECACHE_MODELINDEX( GARG_GIB_MODEL );
PRECACHE_SOUND( GARG_STOMP_BUZZ_SOUND );
for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
PRECACHE_SOUND((char *)pAttackHitSounds[i]);
for ( i = 0; i < ARRAYSIZE( pBeamAttackSounds ); i++ )
PRECACHE_SOUND((char *)pBeamAttackSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
PRECACHE_SOUND((char *)pAttackMissSounds[i]);
for ( i = 0; i < ARRAYSIZE( pRicSounds ); i++ )
PRECACHE_SOUND((char *)pRicSounds[i]);
for ( i = 0; i < ARRAYSIZE( pFootSounds ); i++ )
PRECACHE_SOUND((char *)pFootSounds[i]);
for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ )
PRECACHE_SOUND((char *)pIdleSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ )
PRECACHE_SOUND((char *)pAlertSounds[i]);
for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
PRECACHE_SOUND((char *)pPainSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ )
PRECACHE_SOUND((char *)pAttackSounds[i]);
for ( i = 0; i < ARRAYSIZE( pStompSounds ); i++ )
PRECACHE_SOUND((char *)pStompSounds[i]);
for ( i = 0; i < ARRAYSIZE( pBreatheSounds ); i++ )
PRECACHE_SOUND((char *)pBreatheSounds[i]);
PRECACHE_SOUND_ARRAY(pAttackHitSounds);
PRECACHE_SOUND_ARRAY(pBeamAttackSounds);
PRECACHE_SOUND_ARRAY(pAttackMissSounds);
PRECACHE_SOUND_ARRAY(pRicSounds);
PRECACHE_SOUND_ARRAY(pFootSounds);
PRECACHE_SOUND_ARRAY(pIdleSounds);
PRECACHE_SOUND_ARRAY(pAlertSounds);
PRECACHE_SOUND_ARRAY(pPainSounds);
PRECACHE_SOUND_ARRAY(pAttackSounds);
PRECACHE_SOUND_ARRAY(pStompSounds);
PRECACHE_SOUND_ARRAY(pBreatheSounds);
}
@@ -1379,51 +1356,26 @@ void CMBabyGargantua::Spawn()
//=========================================================
void CMBabyGargantua::Precache()
{
int i;
PRECACHE_MODEL("models/babygarg.mdl");
PRECACHE_MODEL( GARG_EYE_SPRITE_NAME );
PRECACHE_MODEL( GARG_BEAM_SPRITE_NAME );
PRECACHE_MODEL( GARG_BEAM_SPRITE2 );
gStompSprite = PRECACHE_MODEL( GARG_STOMP_SPRITE_NAME );
gGargGibModel = PRECACHE_MODEL( GARG_GIB_MODEL );
gStompSprite = PRECACHE_MODELINDEX( GARG_STOMP_SPRITE_NAME );
gGargGibModel = PRECACHE_MODELINDEX( GARG_GIB_MODEL );
PRECACHE_SOUND( GARG_STOMP_BUZZ_SOUND );
for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
PRECACHE_SOUND((char *)pAttackHitSounds[i]);
for ( i = 0; i < ARRAYSIZE( pBeamAttackSounds ); i++ )
PRECACHE_SOUND((char *)pBeamAttackSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
PRECACHE_SOUND((char *)pAttackMissSounds[i]);
for ( i = 0; i < ARRAYSIZE( pRicSounds ); i++ )
PRECACHE_SOUND((char *)pRicSounds[i]);
for ( i = 0; i < ARRAYSIZE( pFootSounds ); i++ )
PRECACHE_SOUND((char *)pFootSounds[i]);
for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ )
PRECACHE_SOUND((char *)pIdleSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ )
PRECACHE_SOUND((char *)pAlertSounds[i]);
for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
PRECACHE_SOUND((char *)pPainSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ )
PRECACHE_SOUND((char *)pAttackSounds[i]);
for ( i = 0; i < ARRAYSIZE( pStompSounds ); i++ )
PRECACHE_SOUND((char *)pStompSounds[i]);
for ( i = 0; i < ARRAYSIZE( pBreatheSounds ); i++ )
PRECACHE_SOUND((char *)pBreatheSounds[i]);
for ( i = 0; i < ARRAYSIZE( pDieSounds ); i++ )
PRECACHE_SOUND((char *)pDieSounds[i]);
PRECACHE_SOUND_ARRAY(pAttackHitSounds);
PRECACHE_SOUND_ARRAY(pBeamAttackSounds);
PRECACHE_SOUND_ARRAY(pAttackMissSounds);
PRECACHE_SOUND_ARRAY(pRicSounds);
PRECACHE_SOUND_ARRAY(pFootSounds);
PRECACHE_SOUND_ARRAY(pIdleSounds);
PRECACHE_SOUND_ARRAY(pAlertSounds);
PRECACHE_SOUND_ARRAY(pPainSounds);
PRECACHE_SOUND_ARRAY(pAttackSounds);
PRECACHE_SOUND_ARRAY(pStompSounds);
PRECACHE_SOUND_ARRAY(pBreatheSounds);
PRECACHE_SOUND_ARRAY(pDieSounds);
}
void CMBabyGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )

121
src/dlls/globalreplace.cpp Normal file
View File

@@ -0,0 +1,121 @@
//=========================================================
// Global Replacement:
// Tool to replace all default models/sounds with a
// customized list.
//=========================================================
#include "extdll.h"
#include "dllapi.h"
#include "meta_api.h"
#include "cmbase.h"
#include "cmbasemonster.h"
namespace REPLACER
{
typedef struct
{
char source[128];
char destination[128];
} REPLACER;
REPLACER *GMR;
REPLACER *GSR;
int numModels;
int numSounds;
void Init(void)
{
if ( GMR != NULL )
{
free( GMR );
GMR = NULL;
}
if ( GSR != NULL )
{
free( GSR );
GSR = NULL;
}
numModels = 0;
numSounds = 0;
}
bool AddGlobalModel(const char *from, const char *to)
{
if (numModels < MAX_REPLACEMENTS)
{
// allocate for the first time
if (!numModels)
GMR = (REPLACER*)calloc(MAX_REPLACEMENTS, sizeof(*GMR));
strcpy(GMR[numModels].source, from);
strcpy(GMR[numModels].destination, to);
numModels++;
return true;
}
LOG_MESSAGE(PLID, "Can't replace model '%s', too many models in GMR.", from);
return false;
}
bool AddGlobalSound(const char *from, const char *to)
{
if (numSounds < MAX_REPLACEMENTS)
{
// allocate for the first time
if (!numSounds)
GSR = (REPLACER*)calloc(MAX_REPLACEMENTS, sizeof(*GSR));
strcpy(GSR[numSounds].source, from);
strcpy(GSR[numSounds].destination, to);
numSounds++;
return true;
}
LOG_MESSAGE(PLID, "Can't replace sound '%s', too many sounds in GSR.", from);
return false;
}
const char* FindModelReplacement( edict_t *pMonster, const char *from )
{
// Individually set models takes priority!
if ( pMonster && !FStringNull(pMonster->v.model))
return STRING(pMonster->v.model);
// Find the model
for (int model = 0; model < numModels; model++)
{
if (strcmp(GMR[model].source, from) == 0)
{
// If found, use that model instead
return GMR[model].destination;
}
}
// Nothing found, stick with default
return from;
}
const char* FindSoundReplacement( edict_t *pMonster, const char *from )
{
// Individually set sounds takes priority!
if ( pMonster )
{
CMBaseMonster *castMonster = GetClassPtr((CMBaseMonster *)VARS(pMonster));
//placeholder for soundlist keyvalue;
}
for (int sound = 0; sound < numSounds; sound++)
{
if (strcmp(GSR[sound].source, from) == 0)
{
// If found, use that model instead
return GSR[sound].destination;
}
}
// Nothing found, stick with default
return from;
}
}

19
src/dlls/globalreplace.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef GLOBALREPLACE_H
#define GLOBALREPLACE_H
#define MAX_REPLACEMENTS 255
namespace REPLACER
{
void Init(void);
bool AddGlobalModel(const char *from, const char *to);
bool AddGlobalSound(const char *from, const char *to);
const char* FindModelReplacement( edict_t *pMonster, const char *from );
inline const char* FindModelReplacement( const char *from ) { return FindModelReplacement( NULL, from ); }
const char* FindSoundReplacement( edict_t *pMonster, const char *from );
inline const char* FindSoundReplacement( const char *from ) { return FindSoundReplacement( NULL, from ); }
}
#endif

View File

@@ -256,7 +256,7 @@ void CMHAssassin :: Precache()
PRECACHE_SOUND("debris/beamstart1.wav");
m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell
m_iShell = PRECACHE_MODELINDEX("models/shell.mdl");// brass shell
}

View File

@@ -937,8 +937,8 @@ void CMHGrunt :: Precache()
else
m_voicePitch = 100;
m_iBrassShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell
m_iShotgunShell = PRECACHE_MODEL ("models/shotgunshell.mdl");
m_iBrassShell = PRECACHE_MODELINDEX("models/shell.mdl");// brass shell
m_iShotgunShell = PRECACHE_MODELINDEX("models/shotgunshell.mdl");
}
//=========================================================

View File

@@ -104,8 +104,8 @@ void CMHornet :: Precache()
PRECACHE_SOUND( "hornet/ag_hornethit2.wav" );
PRECACHE_SOUND( "hornet/ag_hornethit3.wav" );
iHornetPuff = PRECACHE_MODEL( "sprites/muz1.spr" );
iHornetTrail = PRECACHE_MODEL("sprites/laserbeam.spr");
iHornetPuff = PRECACHE_MODELINDEX( "sprites/muz1.spr" );
iHornetTrail = PRECACHE_MODELINDEX("sprites/laserbeam.spr");
}
//=========================================================

View File

@@ -326,7 +326,7 @@ void CMHoundeye :: Precache()
PRECACHE_SOUND("houndeye/he_blast2.wav");
PRECACHE_SOUND("houndeye/he_blast3.wav");
m_iSpriteTexture = PRECACHE_MODEL( "sprites/shockwave.spr" );
m_iSpriteTexture = PRECACHE_MODELINDEX( "sprites/shockwave.spr" );
}
//=========================================================

View File

@@ -451,8 +451,6 @@ void CMISlave :: Spawn()
//=========================================================
void CMISlave :: Precache()
{
int i;
PRECACHE_MODEL("models/islave.mdl");
PRECACHE_MODEL("sprites/lgtning.spr");
PRECACHE_SOUND("debris/zap1.wav");
@@ -463,17 +461,10 @@ void CMISlave :: Precache()
PRECACHE_SOUND("headcrab/hc_headbite.wav");
PRECACHE_SOUND("weapons/cbar_miss1.wav");
for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
PRECACHE_SOUND((char *)pAttackHitSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
PRECACHE_SOUND((char *)pAttackMissSounds[i]);
for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
PRECACHE_SOUND((char *)pPainSounds[i]);
for ( i = 0; i < ARRAYSIZE( pDeathSounds ); i++ )
PRECACHE_SOUND((char *)pDeathSounds[i]);
PRECACHE_SOUND_ARRAY(pAttackHitSounds);
PRECACHE_SOUND_ARRAY(pAttackMissSounds);
PRECACHE_SOUND_ARRAY(pPainSounds);
PRECACHE_SOUND_ARRAY(pDeathSounds);
}

View File

@@ -314,7 +314,7 @@ void CMMassn::Precache()
else
m_voicePitch = 100;
m_iBrassShell = PRECACHE_MODEL("models/shell.mdl");// brass shell
m_iBrassShell = PRECACHE_MODELINDEX("models/shell.mdl");// brass shell
}
//=========================================================

View File

@@ -48,7 +48,7 @@ static META_FUNCTIONS gMetaFunctionTable =
GetEntityAPI2_Post, // pfnGetEntityAPI2_Post META; called after game DLL
NULL, // pfnGetNewDLLFunctions HL SDK2; called before game DLL
NULL, // pfnGetNewDLLFunctions_Post META; called after game DLL
GetEngineFunctions, // pfnGetEngineFunctions META; called before HL engine
NULL, // pfnGetEngineFunctions META; called before HL engine
GetEngineFunctions_Post, // pfnGetEngineFunctions_Post META; called after HL engine
};
@@ -91,6 +91,10 @@ cvar_t init_monster_turn_coeficient = {"monster_turn_coeficient", "1.75", FCVAR_
cvar_t *monster_turn_coeficient = NULL;
cvar_t init_monster_entity_config = {"monster_entity_config", "1", FCVAR_EXTDLL, 0, NULL};
cvar_t *monster_entity_config = NULL;
cvar_t init_globalmodellist = {"monster_gmr", "", FCVAR_EXTDLL, 0, NULL};
cvar_t *globalmodellist = NULL;
cvar_t init_globalsoundlist = {"monster_gsr", "", FCVAR_EXTDLL, 0, NULL};
cvar_t *globalsoundlist = NULL;
// Metamod requesting info about this plugin:
@@ -156,6 +160,11 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m
CVAR_REGISTER(&init_monster_entity_config);
monster_entity_config = CVAR_GET_POINTER("monster_entity_config");
CVAR_REGISTER(&init_globalmodellist);
globalmodellist = CVAR_GET_POINTER("monster_gmr");
CVAR_REGISTER(&init_globalsoundlist);
globalsoundlist = CVAR_GET_POINTER("monster_gsr");
return(TRUE);
}

View File

@@ -14,10 +14,14 @@
#include "monster_plugin.h"
#include "ripent.h"
#include "globalreplace.h"
extern cvar_t *dllapi_log;
extern cvar_t *monster_entity_config;
extern cvar_t *globalmodellist;
extern cvar_t *globalsoundlist;
extern monster_type_t monster_types[];
extern int monster_spawn_count;
extern int node_spawn_count;
@@ -716,11 +720,107 @@ void scan_monster_bsp(void)
}
}
void scan_extra_cfg(FILE *fp)
{
char input[1024];
while (get_input(fp, input))
{
char *cmd = strtok(input, " ");
char *value = strtok(NULL, " ");
// Remove all quotes from "value"
char parse[128] = {0};
int skip = 0;
for (unsigned i = 0; i < strlen(value); i++)
{
if (value[i] == '"')
{
skip++;
continue;
}
parse[i-skip] = value[i];
}
parse[strlen(parse)] = '\0';
strcpy(value, parse);
if (strcmp(cmd, "globalmodellist") == 0)
{
// ugh...
//globalmodellist->string = value;
CVAR_SET_STRING( "monster_gmr", value );
// Verbose if logging is enabled
if (dllapi_log->value)
LOG_CONSOLE(PLID, "[DEBUG] Using global model replacement file: %s", value);
}
else if (strcmp(cmd, "globalsoundlist") == 0)
{
//globalsoundlist->string = value;
CVAR_SET_STRING( "monster_gsr", value );
// Verbose if logging is enabled
if (dllapi_log->value)
LOG_CONSOLE(PLID, "[DEBUG] Using global sound replacement file: %s", value);
}
}
}
void scan_monster_replace(FILE *fp, bool toGSR )
{
char input[1024];
while (get_input(fp, input))
{
char *source = strtok(input, " ");
char *destination = strtok(NULL, " ");
// Remove all quotes
char parse[128] = {0};
int skip;
// source
skip = 0;
for (unsigned i = 0; i < strlen(source); i++)
{
if (source[i] == '"')
{
skip++;
continue;
}
parse[i-skip] = source[i];
}
parse[strlen(parse)] = '\0';
strcpy(source, parse);
// destination
memset(parse, 0, sizeof(parse));
skip = 0;
for (unsigned i = 0; i < strlen(destination); i++)
{
if (destination[i] == '"')
{
skip++;
continue;
}
parse[i-skip] = destination[i];
}
parse[strlen(parse)] = '\0';
strcpy(destination, parse);
if ( toGSR )
REPLACER::AddGlobalSound( source, destination );
else
REPLACER::AddGlobalModel( source, destination );
}
}
bool process_monster_cfg(void)
{
char game_dir[256];
char BSPfilename[256];
char CFGfilename[256];
char BSPfilename[256]; // to read ents directly from BSP
char CFGfilename[256]; // read ents from MAPNAME_monster.cfg file
char EXTfilename[256]; // extra map configs from MAPNAME.cfg
FILE *fp = NULL;
monster_spawn_count = 0;
@@ -729,18 +829,17 @@ bool process_monster_cfg(void)
// find the directory name of the currently running MOD...
(*g_engfuncs.pfnGetGameDir)(game_dir);
// build route...
strcpy(CFGfilename, game_dir);
#ifdef __linux__
strcat(CFGfilename, "/maps/");
#else
strcat(CFGfilename, "\\maps\\");
#endif
strcat(CFGfilename, STRING(gpGlobals->mapname));
strcpy(BSPfilename, CFGfilename);
strcpy(EXTfilename, CFGfilename);
strcat(BSPfilename, ".bsp");
strcat(CFGfilename, "_monster.cfg");
strcat(EXTfilename, ".cfg");
// process config files?
// -1 = don't process monster config, dynamic spawns only
// 0 = read entities from BSP file
@@ -783,6 +882,55 @@ bool process_monster_cfg(void)
}
}
/* The code is only getting worse from here, I have to finish T4 quickly
* so I can move into making actual clean and optimized code for the final tier...
* -Giegue */
// extra map configs
if (access(EXTfilename, 0) == 0)
{
// first read configs
if ((fp = fopen(EXTfilename, "r")) != NULL)
{
scan_extra_cfg(fp);
fclose(fp);
}
// then process them here
if (strlen(globalmodellist->string))
{
char gmrPath[192];
// SC globalmodellist path starts from models/MAPNAME
sprintf(gmrPath, "%s/models/%s/%s", game_dir, STRING(gpGlobals->mapname), globalmodellist->string);
if (access(gmrPath, 0) == 0)
{
if ((fp = fopen(gmrPath, "r")) != NULL)
{
scan_monster_replace(fp, false);
fclose(fp);
}
}
}
if (strlen(globalsoundlist->string))
{
char gsrPath[192];
// SC globalsoundlist path starts from sound/MAPNAME
sprintf(gsrPath, "%s/sound/%s/%s", game_dir, STRING(gpGlobals->mapname), globalsoundlist->string);
if (access(gsrPath, 0) == 0)
{
if ((fp = fopen(gsrPath, "r")) != NULL)
{
scan_monster_replace(fp, true);
fclose(fp);
}
}
}
}
return FALSE; // all ok
}

View File

@@ -605,7 +605,7 @@ void CMPitdrone::Precache()
{
PRECACHE_MODEL("models/pit_drone.mdl");
PRECACHE_MODEL("models/pit_drone_gibs.mdl");
iPitdroneSpitSprite = PRECACHE_MODEL("sprites/tinyspit.spr");// client side spittle.
iPitdroneSpitSprite = PRECACHE_MODELINDEX("sprites/tinyspit.spr");// client side spittle.
PRECACHE_SOUND_ARRAY(pAttackMissSounds);
PRECACHE_SOUND_ARRAY(pIdleSounds);
@@ -642,7 +642,7 @@ void CMPitdrone::Precache()
PRECACHE_SOUND("weapons/xbow_hitbod2.wav");
PRECACHE_SOUND("weapons/xbow_hit1.wav");
#if FEATURE_PITDRONE_SPIKE_TRAIL
iSpikeTrail = PRECACHE_MODEL("sprites/spike_trail.spr");
iSpikeTrail = PRECACHE_MODELINDEX("sprites/spike_trail.spr");
#endif
}

View File

@@ -387,7 +387,7 @@ void CMRGrunt::Precache()
{
PRECACHE_MODEL("models/rgrunt.mdl");
m_iBodyGibs = PRECACHE_MODEL( "models/metalplategibs_green.mdl" );
m_iBodyGibs = PRECACHE_MODELINDEX( "models/metalplategibs_green.mdl" );
PRECACHE_SOUND("hgrunt/gr_mgun1.wav");
PRECACHE_SOUND("hgrunt/gr_mgun2.wav");
@@ -419,5 +419,5 @@ void CMRGrunt::Precache()
m_voicePitch = 100;
*/
m_iBrassShell = PRECACHE_MODEL("models/shell.mdl");// brass shell
m_iBrassShell = PRECACHE_MODELINDEX("models/shell.mdl");// brass shell
}

View File

@@ -540,19 +540,18 @@ int SENTENCEG_Lookup(const char *sample, char *sentencenum)
return -1;
}
void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation,
int flags, int pitch)
void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch)
{
if (sample && *sample == '!')
{
char name[32];
if (SENTENCEG_Lookup(sample, name) >= 0)
EMIT_SOUND_DYN2(entity, channel, name, volume, attenuation, flags, pitch);
EMIT_SOUND_DYN2(entity, channel, name, volume, attenuation, flags, pitch);
else
ALERT( at_aiconsole, "Unable to find %s in sentences.txt\n", sample );
}
else
EMIT_SOUND_DYN2(entity, channel, sample, volume, attenuation, flags, pitch);
EMIT_SOUND_DYN2(entity, channel, REPLACER::FindSoundReplacement( entity, sample ), volume, attenuation, flags, pitch);
}
// play a specific sentence over the HEV suit speaker - just pass player entity, and !sentencename

View File

@@ -31,9 +31,9 @@ void CMSporeGrenade::Precache()
{
PRECACHE_MODEL("models/spore.mdl");
PRECACHE_MODEL("sprites/glow02.spr");
g_sModelIndexTinySpit = PRECACHE_MODEL("sprites/tinyspit.spr");
gSporeExplode = PRECACHE_MODEL("sprites/spore_exp_01.spr");
gSporeExplodeC = PRECACHE_MODEL("sprites/spore_exp_c_01.spr");
g_sModelIndexTinySpit = PRECACHE_MODELINDEX("sprites/tinyspit.spr");
gSporeExplode = PRECACHE_MODELINDEX("sprites/spore_exp_01.spr");
gSporeExplodeC = PRECACHE_MODELINDEX("sprites/spore_exp_c_01.spr");
PRECACHE_SOUND("weapons/splauncher_bounce.wav");
PRECACHE_SOUND("weapons/splauncher_impact.wav");
}

View File

@@ -443,7 +443,7 @@ void CMStrooper::Precache()
{
PRECACHE_MODEL("models/strooper.mdl");
PRECACHE_MODEL("models/strooper_gibs.mdl");
iStrooperMuzzleFlash = PRECACHE_MODEL(STROOPER_MUZZLEFLASH);
iStrooperMuzzleFlash = PRECACHE_MODELINDEX(STROOPER_MUZZLEFLASH);
PRECACHE_SOUND("shocktrooper/shock_trooper_attack.wav");
PRECACHE_SOUND("shocktrooper/shock_trooper_die1.wav");
@@ -480,7 +480,7 @@ void CMStrooper::Precache()
else
m_voicePitch = 100;
m_iBrassShell = PRECACHE_MODEL("models/shell.mdl");// brass shell
m_iBrassShell = PRECACHE_MODELINDEX("models/shell.mdl");// brass shell
}

View File

@@ -111,7 +111,7 @@ void CMStukabat :: Spawn()
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE;
m_pFlapSound = "stukabat/stukabat_flap1.wav";
m_pFlapSound = REPLACER::FindSoundReplacement( "stukabat/stukabat_flap1.wav" );
MonsterInit();
@@ -130,7 +130,7 @@ void CMStukabat :: Precache()
{
PRECACHE_MODEL("models/stukabat.mdl");
PRECACHE_SOUND("stukabat/stukabat_flap1.wav"); // flying sound
PRECACHE_SOUND("stukabat/stukabat_flap1.wav" ); // flying sound
PRECACHE_SOUND("headcrab/hc_headbite.wav"); // bite sound
}

View File

@@ -2141,7 +2141,7 @@ bool UTIL_IsBSPModel( edict_t *pent )
void UTIL_TakeDamageExternal( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
{
// Tell AMXX to call TakeDamage for us.
// Tell AMXX to call TakeDamage for us if it can.
char extCmd[64];
sprintf( extCmd, "monster_hurt_entity %i %i %i %f %i\n", ENTINDEX( pEdict ), ENTINDEX( ENT( pevInflictor ) ), ENTINDEX( ENT( pevAttacker ) ), flDamage, bitsDamageType );
SERVER_COMMAND( extCmd );

View File

@@ -436,6 +436,18 @@ extern DLL_GLOBAL const Vector g_vecZero;
#define SF_TRIG_PUSH_ONCE 1
// Override a few engine callbacks for model replacements
#include "globalreplace.h"
#define SET_MODEL( entity, model ) \
{ SET_MODEL2( entity, REPLACER::FindModelReplacement( entity, model ) ); }
#define PRECACHE_MODEL( model ) \
{ PRECACHE_MODEL2( (char*)REPLACER::FindModelReplacement( model ) ); }
#define PRECACHE_SOUND( sound ) \
{ PRECACHE_SOUND2( (char*)REPLACER::FindSoundReplacement( sound ) ); }
inline int PRECACHE_MODELINDEX( char* model )
{
return PRECACHE_MODEL2( (char*)REPLACER::FindModelReplacement( model ) );
}
// Sound Utilities
@@ -469,9 +481,7 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int
// EMIT_SOUND_DYN with pitch != 100 should be used sparingly, as it's not quite as
// fast as EMIT_SOUND (the pitchshift mixer is not native coded).
void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation,
int flags, int pitch);
void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch);
inline void EMIT_SOUND(edict_t *entity, int channel, const char *sample, float volume, float attenuation)
{
@@ -488,7 +498,7 @@ void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg);
void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname);
#define PRECACHE_SOUND_ARRAY( a ) \
{ for (int i = 0; i < ARRAYSIZE( a ); i++ ) PRECACHE_SOUND((char *) a [i]); }
{ for (int i = 0; i < ARRAYSIZE( a ); i++ ) PRECACHE_SOUND2((char *) REPLACER::FindSoundReplacement(a[i])); }
#define EMIT_SOUND_ARRAY_DYN( chan, array ) \
EMIT_SOUND_DYN ( ENT(pev), chan , array [ RANDOM_LONG(0,ARRAYSIZE( array )-1) ], 1.0, ATTN_NORM, 0, RANDOM_LONG(95,105) );
@@ -541,4 +551,4 @@ Vector UTIL_Center(edict_t *pEdict);
edict_t *UTIL_GetNextTarget( edict_t *pEntity );
edict_t *UTIL_FindNearestPlayer(edict_t *pEdict, float m_flFieldOfView);
bool UTIL_IsBSPModel( edict_t *pent );
void UTIL_TakeDamageExternal( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
void UTIL_TakeDamageExternal( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );

View File

@@ -692,7 +692,7 @@ void CMVoltigore::PrecacheImpl(char *modelName)
PRECACHE_SOUND("debris/beamstart1.wav");
m_beamTexture = PRECACHE_MODEL(VOLTIGORE_ZAP_BEAM);
m_beamTexture = PRECACHE_MODELINDEX(VOLTIGORE_ZAP_BEAM);
PRECACHE_MODEL(VOLTIGORE_GLOW_SPRITE);
PRECACHE_MODEL("sprites/lgtning.spr");

View File

@@ -263,27 +263,14 @@ void CMZombie :: Spawn()
//=========================================================
void CMZombie :: Precache()
{
int i;
PRECACHE_MODEL("models/zombie.mdl");
for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
PRECACHE_SOUND((char *)pAttackHitSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
PRECACHE_SOUND((char *)pAttackMissSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ )
PRECACHE_SOUND((char *)pAttackSounds[i]);
for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ )
PRECACHE_SOUND((char *)pIdleSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ )
PRECACHE_SOUND((char *)pAlertSounds[i]);
for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
PRECACHE_SOUND((char *)pPainSounds[i]);
PRECACHE_SOUND_ARRAY(pAttackHitSounds);
PRECACHE_SOUND_ARRAY(pAttackMissSounds);
PRECACHE_SOUND_ARRAY(pAttackSounds);
PRECACHE_SOUND_ARRAY(pIdleSounds);
PRECACHE_SOUND_ARRAY(pAlertSounds);
PRECACHE_SOUND_ARRAY(pPainSounds);
}
//=========================================================