Add "soundlist" keyvalue for individual sound replacements.
This commit is contained in:
@@ -103,8 +103,8 @@ Current milestones are separated by "Tiers", which are as follows:
|
|||||||
- Add build instructions. **[DONE]**
|
- Add build instructions. **[DONE]**
|
||||||
- Global Model Replacement. **[DONE]**
|
- Global Model Replacement. **[DONE]**
|
||||||
- Global Sound Replacement. **[DONE]**
|
- Global Sound Replacement. **[DONE]**
|
||||||
- Miscellaneous customization options, such as blood color.
|
- Miscellaneous customization options, such as blood color. **[DONE]**
|
||||||
- Individual sound replacement: "soundlist" keyvalue for monsters.
|
- Individual sound replacement: "soundlist" keyvalue for monsters. **[DONE]**
|
||||||
- Sentences support for speakable monsters.
|
- Sentences support for speakable monsters.
|
||||||
- Attempt to fix bugs as they appear.
|
- Attempt to fix bugs as they appear.
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,10 @@ public:
|
|||||||
|
|
||||||
string_t m_szMonsterName; // Monster name to display on HUD
|
string_t m_szMonsterName; // Monster name to display on HUD
|
||||||
int m_iClassifyOverride; // Overriden classification for this monster
|
int m_iClassifyOverride; // Overriden classification for this monster
|
||||||
|
|
||||||
|
REPLACER::REPLACER *m_srSoundList; // individual sound replacements for this monster
|
||||||
|
int m_isrSounds; // number of replaced sounds
|
||||||
|
|
||||||
float m_flLastYawTime;
|
float m_flLastYawTime;
|
||||||
|
|
||||||
void KeyValue( KeyValueData *pkvd );
|
void KeyValue( KeyValueData *pkvd );
|
||||||
|
|||||||
@@ -1255,7 +1255,13 @@ int mmDispatchSpawn( edict_t *pent )
|
|||||||
for (index = 0; index < MAX_MONSTER_ENTS; index++)
|
for (index = 0; index < MAX_MONSTER_ENTS; index++)
|
||||||
{
|
{
|
||||||
if (monsters[index].pMonster != NULL)
|
if (monsters[index].pMonster != NULL)
|
||||||
|
{
|
||||||
|
// free the soundlists first!
|
||||||
|
if (monsters[index].pMonster->m_srSoundList != NULL)
|
||||||
|
free(monsters[index].pMonster->m_srSoundList);
|
||||||
|
|
||||||
delete monsters[index].pMonster;
|
delete monsters[index].pMonster;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// free any allocated keyvalue memory
|
// free any allocated keyvalue memory
|
||||||
|
|||||||
@@ -12,12 +12,6 @@
|
|||||||
|
|
||||||
namespace REPLACER
|
namespace REPLACER
|
||||||
{
|
{
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
char source[128];
|
|
||||||
char destination[128];
|
|
||||||
} REPLACER;
|
|
||||||
|
|
||||||
REPLACER *GMR;
|
REPLACER *GMR;
|
||||||
REPLACER *GSR;
|
REPLACER *GSR;
|
||||||
int numModels;
|
int numModels;
|
||||||
@@ -77,6 +71,32 @@ bool AddGlobalSound(const char *from, const char *to)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AddIndividualSound(edict_t *pMonster, const char *from, const char *to)
|
||||||
|
{
|
||||||
|
CMBaseMonster *castMonster = GetClassPtr((CMBaseMonster *)VARS(pMonster));
|
||||||
|
|
||||||
|
if ( castMonster == NULL )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int m_iSounds = castMonster->m_isrSounds;
|
||||||
|
|
||||||
|
if (m_iSounds < MAX_REPLACEMENTS)
|
||||||
|
{
|
||||||
|
// allocate for the first time
|
||||||
|
if (!m_iSounds)
|
||||||
|
castMonster->m_srSoundList = (REPLACER*)calloc(MAX_REPLACEMENTS, sizeof(*castMonster->m_srSoundList));
|
||||||
|
|
||||||
|
strcpy(castMonster->m_srSoundList[m_iSounds].source, from);
|
||||||
|
strcpy(castMonster->m_srSoundList[m_iSounds].destination, to);
|
||||||
|
|
||||||
|
castMonster->m_isrSounds++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_MESSAGE(PLID, "Can't replace sound '%s', too many sounds in list.", from);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const char* FindModelReplacement( edict_t *pMonster, const char *from )
|
const char* FindModelReplacement( edict_t *pMonster, const char *from )
|
||||||
{
|
{
|
||||||
// Individually set models takes priority!
|
// Individually set models takes priority!
|
||||||
@@ -103,14 +123,26 @@ const char* FindSoundReplacement( edict_t *pMonster, const char *from )
|
|||||||
if ( pMonster )
|
if ( pMonster )
|
||||||
{
|
{
|
||||||
CMBaseMonster *castMonster = GetClassPtr((CMBaseMonster *)VARS(pMonster));
|
CMBaseMonster *castMonster = GetClassPtr((CMBaseMonster *)VARS(pMonster));
|
||||||
//placeholder for soundlist keyvalue;
|
if (castMonster->m_isrSounds)
|
||||||
|
{
|
||||||
|
for (int sound = 0; sound < castMonster->m_isrSounds; sound++)
|
||||||
|
{
|
||||||
|
if (strcmp(castMonster->m_srSoundList[sound].source, from) == 0)
|
||||||
|
{
|
||||||
|
// If found, use it
|
||||||
|
return castMonster->m_srSoundList[sound].destination;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If nothing is found stick to GSR if available
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int sound = 0; sound < numSounds; sound++)
|
for (int sound = 0; sound < numSounds; sound++)
|
||||||
{
|
{
|
||||||
if (strcmp(GSR[sound].source, from) == 0)
|
if (strcmp(GSR[sound].source, from) == 0)
|
||||||
{
|
{
|
||||||
// If found, use that model instead
|
// If found, use that sound instead
|
||||||
return GSR[sound].destination;
|
return GSR[sound].destination;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,16 @@
|
|||||||
|
|
||||||
namespace REPLACER
|
namespace REPLACER
|
||||||
{
|
{
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char source[128];
|
||||||
|
char destination[128];
|
||||||
|
} REPLACER;
|
||||||
|
|
||||||
void Init(void);
|
void Init(void);
|
||||||
bool AddGlobalModel(const char *from, const char *to);
|
bool AddGlobalModel(const char *from, const char *to);
|
||||||
bool AddGlobalSound(const char *from, const char *to);
|
bool AddGlobalSound(const char *from, const char *to);
|
||||||
|
bool AddIndividualSound(edict_t *pMonster, const char *from, const char *to);
|
||||||
|
|
||||||
const char* FindModelReplacement( edict_t *pMonster, const char *from );
|
const char* FindModelReplacement( edict_t *pMonster, const char *from );
|
||||||
inline const char* FindModelReplacement( const char *from ) { return FindModelReplacement( NULL, from ); }
|
inline const char* FindModelReplacement( const char *from ) { return FindModelReplacement( NULL, from ); }
|
||||||
|
|||||||
@@ -68,6 +68,80 @@ bool get_input(FILE *fp, char *input)
|
|||||||
return FALSE; // no input found
|
return FALSE; // no input found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void scan_monster_sound(FILE *fp, edict_t *pMonster )
|
||||||
|
{
|
||||||
|
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 ( pMonster )
|
||||||
|
REPLACER::AddIndividualSound( pMonster, source, destination );
|
||||||
|
else
|
||||||
|
PRECACHE_SOUND2(destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_monster_sound(edict_t *pMonster, char *fileName)
|
||||||
|
{
|
||||||
|
char game_dir[256];
|
||||||
|
FILE *fp = NULL;
|
||||||
|
|
||||||
|
// find the directory name of the currently running MOD...
|
||||||
|
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
||||||
|
|
||||||
|
char srPath[192];
|
||||||
|
|
||||||
|
// SC soundlist path starts from sound/MAPNAME
|
||||||
|
sprintf(srPath, "%s/sound/%s/%s", game_dir, STRING(gpGlobals->mapname), fileName);
|
||||||
|
|
||||||
|
if (access(srPath, 0) == 0)
|
||||||
|
{
|
||||||
|
if ((fp = fopen(srPath, "r")) != NULL)
|
||||||
|
{
|
||||||
|
scan_monster_sound(fp, pMonster);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void scan_monster_cfg(FILE *fp)
|
void scan_monster_cfg(FILE *fp)
|
||||||
{
|
{
|
||||||
// Let's make a full rework of this. -Giegue
|
// Let's make a full rework of this. -Giegue
|
||||||
@@ -277,6 +351,22 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strcmp(data[i].key, "soundlist") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
// file handling, string must not be empty
|
||||||
|
if (strlen(data[i].value))
|
||||||
|
{
|
||||||
|
// process and precache the replacement sounds
|
||||||
|
process_monster_sound( NULL, data[i].value );
|
||||||
|
|
||||||
|
// the entity will need the keyvalue
|
||||||
|
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 if (strcmp(data[i].key, "new_model") == 0)
|
else if (strcmp(data[i].key, "new_model") == 0)
|
||||||
{
|
{
|
||||||
if (monster)
|
if (monster)
|
||||||
@@ -640,6 +730,22 @@ void scan_monster_bsp(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strcmp(data[i].key, "soundlist") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
// file handling, string must not be empty
|
||||||
|
if (strlen(data[i].value))
|
||||||
|
{
|
||||||
|
// process and precache the replacement sounds
|
||||||
|
process_monster_sound( NULL, data[i].value );
|
||||||
|
|
||||||
|
// the entity will need the keyvalue
|
||||||
|
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 if (strcmp(data[i].key, "new_model") == 0)
|
else if (strcmp(data[i].key, "new_model") == 0)
|
||||||
{
|
{
|
||||||
if (monster)
|
if (monster)
|
||||||
@@ -946,7 +1052,6 @@ bool process_monster_cfg(void)
|
|||||||
return FALSE; // all ok
|
return FALSE; // all ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool scan_monster_precache_cfg(FILE *fp)
|
bool scan_monster_precache_cfg(FILE *fp)
|
||||||
{
|
{
|
||||||
char input[1024];
|
char input[1024];
|
||||||
|
|||||||
@@ -254,6 +254,17 @@ void CMMonsterMaker::MakeMonster( void )
|
|||||||
pent->v.renderamt = pev->renderamt;
|
pent->v.renderamt = pev->renderamt;
|
||||||
pent->v.rendercolor = pev->rendercolor;
|
pent->v.rendercolor = pev->rendercolor;
|
||||||
|
|
||||||
|
// Soundlist isn't "exactly" a keyvalue so pass it here
|
||||||
|
if ( m_srSoundList != NULL )
|
||||||
|
{
|
||||||
|
// it needs to be allocated first
|
||||||
|
CMBaseMonster *pChild = GetClassPtr((CMBaseMonster *)VARS(pent));
|
||||||
|
pChild->m_srSoundList = (REPLACER::REPLACER*)calloc(MAX_REPLACEMENTS, sizeof(*pChild->m_srSoundList));
|
||||||
|
|
||||||
|
memcpy(pChild->m_srSoundList, m_srSoundList, sizeof(REPLACER::REPLACER));
|
||||||
|
pChild->m_isrSounds = m_isrSounds;
|
||||||
|
}
|
||||||
|
|
||||||
m_cLiveChildren++;// count this monster
|
m_cLiveChildren++;// count this monster
|
||||||
m_cNumMonsters--;
|
m_cNumMonsters--;
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ extern CGraph WorldGraph;// the world node graph
|
|||||||
|
|
||||||
extern cvar_t *monster_turn_coeficient;
|
extern cvar_t *monster_turn_coeficient;
|
||||||
|
|
||||||
|
extern void process_monster_sound(edict_t *pMonster, char *fileName);
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
// Eat - makes a monster full for a little while.
|
// Eat - makes a monster full for a little while.
|
||||||
@@ -2643,6 +2643,14 @@ void CMBaseMonster :: KeyValue( KeyValueData *pkvd )
|
|||||||
}
|
}
|
||||||
pkvd->fHandled = TRUE;
|
pkvd->fHandled = TRUE;
|
||||||
}
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "soundlist"))
|
||||||
|
{
|
||||||
|
if (strlen( pkvd->szValue ))
|
||||||
|
{
|
||||||
|
process_monster_sound(edict(), pkvd->szValue);
|
||||||
|
}
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CMBaseToggle::KeyValue( pkvd );
|
CMBaseToggle::KeyValue( pkvd );
|
||||||
|
|||||||
Reference in New Issue
Block a user