Add "soundlist" keyvalue for individual sound replacements.

This commit is contained in:
Giegue
2023-04-29 02:04:40 -03:00
parent 92d14a6fd3
commit efd801bdea
8 changed files with 185 additions and 12 deletions

View File

@@ -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.

View File

@@ -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 );

View File

@@ -1255,8 +1255,14 @@ 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
for (index = 0; index < MAX_MONSTERS; index++) for (index = 0; index < MAX_MONSTERS; index++)

View File

@@ -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;
} }
} }

View File

@@ -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 ); }

View File

@@ -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];

View File

@@ -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--;

View File

@@ -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 );