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]**
|
||||
- Global Model Replacement. **[DONE]**
|
||||
- Global Sound Replacement. **[DONE]**
|
||||
- Miscellaneous customization options, such as blood color.
|
||||
- Individual sound replacement: "soundlist" keyvalue for monsters.
|
||||
- Miscellaneous customization options, such as blood color. **[DONE]**
|
||||
- Individual sound replacement: "soundlist" keyvalue for monsters. **[DONE]**
|
||||
- Sentences support for speakable monsters.
|
||||
- Attempt to fix bugs as they appear.
|
||||
|
||||
|
||||
@@ -104,6 +104,10 @@ public:
|
||||
|
||||
string_t m_szMonsterName; // Monster name to display on HUD
|
||||
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;
|
||||
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
|
||||
@@ -1255,7 +1255,13 @@ int mmDispatchSpawn( edict_t *pent )
|
||||
for (index = 0; index < MAX_MONSTER_ENTS; index++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// free any allocated keyvalue memory
|
||||
|
||||
@@ -12,12 +12,6 @@
|
||||
|
||||
namespace REPLACER
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
char source[128];
|
||||
char destination[128];
|
||||
} REPLACER;
|
||||
|
||||
REPLACER *GMR;
|
||||
REPLACER *GSR;
|
||||
int numModels;
|
||||
@@ -77,6 +71,32 @@ bool AddGlobalSound(const char *from, const char *to)
|
||||
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 )
|
||||
{
|
||||
// Individually set models takes priority!
|
||||
@@ -103,14 +123,26 @@ const char* FindSoundReplacement( edict_t *pMonster, const char *from )
|
||||
if ( 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++)
|
||||
{
|
||||
if (strcmp(GSR[sound].source, from) == 0)
|
||||
{
|
||||
// If found, use that model instead
|
||||
// If found, use that sound instead
|
||||
return GSR[sound].destination;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,16 @@
|
||||
|
||||
namespace REPLACER
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
char source[128];
|
||||
char destination[128];
|
||||
} REPLACER;
|
||||
|
||||
void Init(void);
|
||||
bool AddGlobalModel(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 );
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (monster)
|
||||
@@ -946,7 +1052,6 @@ bool process_monster_cfg(void)
|
||||
return FALSE; // all ok
|
||||
}
|
||||
|
||||
|
||||
bool scan_monster_precache_cfg(FILE *fp)
|
||||
{
|
||||
char input[1024];
|
||||
|
||||
@@ -254,6 +254,17 @@ void CMMonsterMaker::MakeMonster( void )
|
||||
pent->v.renderamt = pev->renderamt;
|
||||
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_cNumMonsters--;
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ extern CGraph WorldGraph;// the world node graph
|
||||
|
||||
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.
|
||||
@@ -2643,6 +2643,14 @@ void CMBaseMonster :: KeyValue( KeyValueData *pkvd )
|
||||
}
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "soundlist"))
|
||||
{
|
||||
if (strlen( pkvd->szValue ))
|
||||
{
|
||||
process_monster_sound(edict(), pkvd->szValue);
|
||||
}
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
CMBaseToggle::KeyValue( pkvd );
|
||||
|
||||
Reference in New Issue
Block a user