shithub: choc

Download patch

ref: 90c196e4eb1d079fa946e764ed72a9ecd2c86dac
parent: b6938d1533d624a5815660c40aeda9125090f55e
author: James Haley <haleyjd@hotmail.com>
date: Sat Sep 11 17:12:06 EDT 2010

Added code (some possibly temporary?) to load voices.wad. Fixed several
problems with playing of voice sounds - especially had to add a dynamic
hashtable of voice sfxinfo_t's because Choco won't tolerate overwriting
them once they've been used (see channel_playing array in i_sdlsound.c)
- PROBLEM: Random Z_Malloc failures when trying to play sounds. Cannot
catch in debugger so far.

Subversion-branch: /branches/strife-branch
Subversion-revision: 2065

--- a/src/d_iwad.c
+++ b/src/d_iwad.c
@@ -50,6 +50,7 @@
     { "heretic.wad",  heretic,   retail,     "Heretic" },
     { "heretic1.wad", heretic,   shareware,  "Heretic Shareware" },
     { "hexen.wad",    hexen,     commercial, "Hexen" },
+    //{ "strife0.wad",  strife,    commercial, "Strife" }, // haleyjd: STRIFE-FIXME
     { "strife1.wad",  strife,    commercial, "Strife" },
 };
 
--- a/src/strife/d_main.c
+++ b/src/strife/d_main.c
@@ -127,6 +127,10 @@
 
 boolean		advancedemo;
 
+// haleyjd 09/11/10: [STRIFE] Game type variables
+boolean         isregistered;
+boolean         isdemoversion;
+
 // Store demo, do not accept any inputs
 // haleyjd [STRIFE] Unused.
 //boolean         storedemo;
@@ -696,7 +700,54 @@
     return gamename;
 }
 
+// 
+// haleyjd: STRIFE-FIXME: Temporary?
+// Code borrowed from Eternity, and modified to return separator char
 //
+char M_GetFilePath(const char *fn, char *dest, size_t len)
+{
+   boolean found_slash = false;
+   char *p;
+   char sepchar = '\0';
+
+   memset(dest, 0, len);
+
+   p = dest + len - 1;
+
+   strncpy(dest, fn, len);
+   
+   while(p >= dest)
+   {
+      if(*p == '/' || *p == '\\')
+      {
+         sepchar = *p;
+         found_slash = true; // mark that the path ended with a slash
+         *p = '\0';
+         break;
+      }
+      *p = '\0';
+      p--;
+   }
+
+   // haleyjd: in the case that no slash was ever found, yet the
+   // path string is empty, we are dealing with a file local to the
+   // working directory. The proper path to return for such a string is
+   // not "", but ".", since the format strings add a slash now. When
+   // the string is empty but a slash WAS found, we really do want to
+   // return the empty string, since the path is relative to the root.
+   if(!found_slash && *dest == '\0')
+      *dest = '.';
+
+   // if a separator is not found, default to forward, because Windows 
+   // supports that too.
+   if(sepchar == '\0') 
+       sepchar = '/';
+
+   return sepchar;
+}
+
+
+//
 // Find out what version of Doom is playing.
 //
 
@@ -707,59 +758,59 @@
     // IdentifyIWADByName.  However, if the iwad does not match
     // any known IWAD name, we may have a dilemma.  Try to 
     // identify by its contents.
+    
+    // STRIFE-TODO: some elaborate checks? for now we assume...
+    // The logic in strife1.exe is simple:
+    // * if strife1.wad is found, set isregistered = true
+    // * if strife0.wad is found, set isdemoversion = true
 
-    if (gamemission == none)
+    // Make sure gamemode is set up correctly
+    gamemode = commercial;
+    gamemission = strife;
+    isregistered = true;
+
+    // Load voices.wad 
+    if(isregistered)
     {
-        unsigned int i;
+        char *name = D_FindWADByName("voices.wad");
 
-        for (i=0; i<numlumps; ++i)
+        if(!name) // not found?
         {
-            if (!strncasecmp(lumpinfo[i].name, "MAP01", 8))
+            int p;
+
+            // haleyjd STRIFE-FIXME: Temporary?
+            // If -iwad was used, check and see if voices.wad exists on the
+            // same filepath.
+            if((p = M_CheckParm("-iwad")) && p < myargc - 1)
             {
-                gamemission = doom2;
-                break;
-            } 
-            else if (!strncasecmp(lumpinfo[i].name, "E1M1", 8))
-            {
-                gamemission = doom;
-                break;
-            }
-        }
+                char   *iwad     = myargv[p + 1];
+                size_t  len      = strlen(iwad) + 24;
+                char   *filename = malloc(len);
+                char    sepchar;
 
-        if (gamemission == none)
-        {
-            // Still no idea.  I don't think this is going to work.
+                // how the heck is Choco surviving without this routine?
+                sepchar = M_GetFilePath(iwad, filename, len);
+                filename[strlen(filename)] = sepchar;
+                strcat(filename, "voices.wad");
 
-            I_Error("Unknown or invalid IWAD file.");
+                if(!M_FileExists(filename))
+                    disable_voices = 1;
+                else
+                    name = filename; // STRIFE-FIXME: memory leak!!
+            }
+            else
+                disable_voices = 1;
         }
-    }
 
-    // Make sure gamemode is set up correctly
-
-    if (gamemission == doom)
-    {
-        // Doom 1.  But which version?
-
-        if (W_CheckNumForName("E4M1") > 0)
+        if(disable_voices) // voices disabled?
         {
-            // Ultimate Doom
-
-            gamemode = retail;
-        } 
-        else if (W_CheckNumForName("E3M1") > 0)
-        {
-            gamemode = registered;
+            // STRIFE-FIXME:
+            // if(debugmode)
+                 printf("Voices disabled\n");
+            return;
         }
-        else
-        {
-            gamemode = shareware;
-        }
-    }
-    else
-    {
-        // Doom 2 of some kind.
 
-        gamemode = commercial;
+        D_AddFile(name);
     }
 }
 
@@ -1625,7 +1676,7 @@
 #endif
 
     DEH_printf("S_Init: Setting up sound.\n");
-    S_Init (sfxVolume * 8, musicVolume * 8);
+    S_Init (sfxVolume * 8, musicVolume * 8, voiceVolume * 8); // [STRIFE]: voice
 
     DEH_printf("D_CheckNetGame: Checking network game status.\n");
     D_CheckNetGame ();
--- a/src/strife/p_dialog.c
+++ b/src/strife/p_dialog.c
@@ -1151,7 +1151,8 @@
 
     currentchoice = &(currentdialog->choices[choice]);
 
-    // I_StartVoice(0); -- verify (should stop previous voice I believe)
+    I_StartVoice(NULL); // STRIFE-TODO: verify (should stop previous voice I believe)
+
     // villsa 09/08/10: converted into for loop
     for(i = 0; i < MDLG_MAXITEMS; i++)
     {
@@ -1364,7 +1365,7 @@
         V_DrawPatchDirect(0, 0, W_CacheLumpNum(pic, PU_CACHE));
 
     // get voice
-    //I_StartVoice(currentdialog->voice);
+    I_StartVoice(currentdialog->voice);
 
     // get bye text
     switch(rnd)
--- a/src/strife/s_sound.c
+++ b/src/strife/s_sound.c
@@ -137,8 +137,9 @@
 // Sets channels, SFX and music volume,
 //  allocates channel buffer, sets S_sfx lookup.
 //
-
-void S_Init(int sfxVolume, int musicVolume)
+// haleyjd 09/11/10: Added voice volume
+//
+void S_Init(int sfxVolume, int musicVolume, int voiceVolume)
 {  
     int i;
 
@@ -149,6 +150,7 @@
 
     S_SetSfxVolume(sfxVolume);
     S_SetMusicVolume(musicVolume);
+    S_SetVoiceVolume(voiceVolume);
 
     // Allocating the internal channels for mixing
     // (the maximum numer of sounds rendered
@@ -257,6 +259,10 @@
 
     for (cnum=0 ; cnum<snd_channels ; cnum++)
     {
+        // haleyjd: do not stop voice here.
+        if(cnum == i_voicehandle)
+            continue;
+
         if (channels[cnum].sfxinfo && channels[cnum].origin == origin)
         {
             S_StopChannel(cnum);
@@ -280,7 +286,7 @@
     channel_t*        c;
 
     // Find an open channel
-    for (cnum=0 ; cnum<snd_channels ; cnum++)
+     for (cnum=0 ; cnum<snd_channels ; cnum++)
     {
         if (!channels[cnum].sfxinfo)
         {
@@ -495,9 +501,83 @@
     }
 
     channels[cnum].handle = I_StartSound(sfx, cnum, volume, sep);
-}        
+}
 
+
+// haleyjd 09/11/10: [STRIFE]
+// None of this was necessary in the vanilla EXE but Choco's low-level code
+// won't play nice with a temporary sfxinfo because it insists that the
+// "driver_data" member remain valid from the last time the sound was used,
+// even if it has already stopped playing. Thanks to this cuteness I get
+// to maintain a dynamic cache of sfxinfo objects!
+
+typedef struct voiceinfo_s
+{
+    sfxinfo_t sfx;
+    struct voiceinfo_s *next; // next on hash chain
+} voiceinfo_t;
+
+#define NUMVOICECHAINS 257
+
 //
+// Ripped from Eternity.
+//
+static unsigned int S_voiceHash(const char *str)
+{
+   const char *c = str;
+   unsigned int h = 0;
+
+   if(!str)
+      I_Error("S_voiceHash: cannot hash NULL string!\n");
+
+   // note: this needs to be case insensitive for lump names
+   while(*c)
+   {
+      h = 5 * h + toupper(*c);
+      ++c;
+   }
+
+   return h;}
+
+static voiceinfo_t *voices[NUMVOICECHAINS];
+
+//
+// S_getVoice
+//
+// Gets an entry from the voice table, if it exists. If it does not, one will be
+// created.
+//
+static voiceinfo_t *S_getVoice(const char *name, int lumpnum)
+{
+    voiceinfo_t *voice;
+    int hashkey = S_voiceHash(name) % NUMVOICECHAINS;
+
+    voice = voices[hashkey];
+
+    while(voice && strcasecmp(voice->sfx.name, name))
+        voice = voice->next;
+
+    if(!voice)
+    {
+        voice = calloc(1, sizeof(voiceinfo_t));
+
+        strncpy(voice->sfx.name, name, 8);
+        voice->sfx.priority = INT_MIN; // make highest possible priority
+        voice->sfx.pitch = -1;
+        voice->sfx.volume = -1;
+        voice->sfx.numchannels = -1;
+        voice->sfx.usefulness = -1;
+        voice->sfx.lumpnum = lumpnum;
+
+        // throw it onto the table.
+        voice->next = voices[hashkey];
+        voices[hashkey] = voice;
+    }
+
+    return voice;
+}
+
+//
 // I_StartVoice
 //
 // haleyjd 09/11/10: [STRIFE] New function
@@ -508,14 +588,14 @@
 //
 void I_StartVoice(const char *lumpname)
 {
-    static sfxinfo_t voicesfx; // a static "fake" sfxinfo for voices.
     int lumpnum;
+    voiceinfo_t *voice; // choco-specific
 
     // no voices in deathmatch mode.
     if(netgame)
         return;
 
-    // TODO: checks if sfx_SndDevice == 83
+    // STRIFE-TODO: checks if snd_SfxDevice == 83
     // This is probably turning off voice if using PC speaker...
 
     // user has disabled voices?
@@ -523,25 +603,26 @@
         return;
 
     // have a voice playing already? stop it.
-    if (i_voicehandle > 0)
+    if (i_voicehandle >= 0)
         S_StopChannel(i_voicehandle);
 
-    // haleyjd: Choco-specific: initialize the voicesfx structure
-    memset(&voicesfx, 0, sizeof(sfxinfo_t));
-    strncpy(voicesfx.name, lumpname, 8);
-    voicesfx.priority = INT_MIN; // make highest possible priority
-    voicesfx.pitch = -1;
-    voicesfx.volume = -1;
-    voicesfx.numchannels = -1;
-    voicesfx.usefulness = -1;
+    // Vanilla STRIFE appears to have stopped any current voice without
+    // starting a new one if NULL was passed in here, though I cannot 
+    // find an explicit check for NULL in the assembly. Either way, it 
+    // didn't crash, so do a check now:
+    if(lumpname == NULL)
+        return;
 
     if((lumpnum = W_CheckNumForName(lumpname)) != -1)
     {
+        // haleyjd: Choco-specific: get a voice structure
+        voice = S_getVoice(lumpname, lumpnum);
+
         // get a channel for the voice
-        i_voicehandle = S_GetChannel(NULL, &voicesfx, true);
-        voicesfx.lumpnum = lumpnum;
+        i_voicehandle = S_GetChannel(NULL, &voice->sfx, true);
+        
         channels[i_voicehandle].handle 
-            = I_StartSound(&voicesfx, i_voicehandle, snd_VoiceVolume, NORM_SEP);
+            = I_StartSound(&voice->sfx, i_voicehandle, snd_VoiceVolume, NORM_SEP);
     }
 }
 
--- a/src/strife/s_sound.h
+++ b/src/strife/s_sound.h
@@ -37,7 +37,7 @@
 //  allocates channel buffer, sets S_sfx lookup.
 //
 
-void S_Init(int sfxVolume, int musicVolume);
+void S_Init(int sfxVolume, int musicVolume, int voiceVolume);
 
 
 // Shut down sound 
@@ -96,6 +96,8 @@
 void S_SetVoiceVolume(int volume); // haleyjd 09/11/10: [STRIFE]
 
 extern int snd_channels;
+
+extern int disable_voices;
 
 #endif