foxygit / doom Log in
commit 90c196e4eb1d079fa946e764ed72a9ecd2c86dac
Author:     James Haley <haleyjd@hotmail.com>
AuthorDate: Sat Sep 11 21:12:06 2010 +0000
Commit:     James Haley <haleyjd@hotmail.com>
CommitDate: Sat Sep 11 21:12:06 2010 +0000

    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
---
 src/d_iwad.c          |   1 +
 src/strife/d_main.c   | 137 ++++++++++++++++++++++++++++++++++----------------
 src/strife/p_dialog.c |   5 +-
 src/strife/s_sound.c  | 117 +++++++++++++++++++++++++++++++++++-------
 src/strife/s_sound.h  |   4 +-
 5 files changed, 200 insertions(+), 64 deletions(-)

diff --git a/src/d_iwad.c b/src/d_iwad.c
index 0e3220a8..e7f25234 100644
--- a/src/d_iwad.c
+++ b/src/d_iwad.c
@@ -50,6 +50,7 @@ static iwad_t iwads[] =
     { "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" },
 };

diff --git a/src/strife/d_main.c b/src/strife/d_main.c
index e7ed01be..041a4bc8 100644
--- a/src/strife/d_main.c
+++ b/src/strife/d_main.c
@@ -127,6 +127,10 @@ FILE*		debugfile;

 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,6 +700,53 @@ static char *GetGameName(char *gamename)
     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 @@ void D_IdentifyVersion(void)
     // IdentifyIWADByName.  However, if the iwad does not match
     // any known IWAD name, we may have a dilemma.  Try to
     // identify by its contents.
-
-    if (gamemission == none)
-    {
-        unsigned int i;
-
-        for (i=0; i<numlumps; ++i)
-        {
-            if (!strncasecmp(lumpinfo[i].name, "MAP01", 8))
-            {
-                gamemission = doom2;
-                break;
-            }
-            else if (!strncasecmp(lumpinfo[i].name, "E1M1", 8))
-            {
-                gamemission = doom;
-                break;
-            }
-        }
-
-        if (gamemission == none)
-        {
-            // Still no idea.  I don't think this is going to work.
-
-            I_Error("Unknown or invalid IWAD file.");
-        }
-    }
+
+    // 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

     // Make sure gamemode is set up correctly
+    gamemode = commercial;
+    gamemission = strife;
+    isregistered = true;

-    if (gamemission == doom)
+    // Load voices.wad
+    if(isregistered)
     {
-        // Doom 1.  But which version?
+        char *name = D_FindWADByName("voices.wad");

-        if (W_CheckNumForName("E4M1") > 0)
+        if(!name) // not found?
         {
-            // Ultimate Doom
+            int p;

-            gamemode = retail;
-        }
-        else if (W_CheckNumForName("E3M1") > 0)
-        {
-            gamemode = registered;
+            // 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)
+            {
+                char   *iwad     = myargv[p + 1];
+                size_t  len      = strlen(iwad) + 24;
+                char   *filename = malloc(len);
+                char    sepchar;
+
+                // how the heck is Choco surviving without this routine?
+                sepchar = M_GetFilePath(iwad, filename, len);
+                filename[strlen(filename)] = sepchar;
+                strcat(filename, "voices.wad");
+
+                if(!M_FileExists(filename))
+                    disable_voices = 1;
+                else
+                    name = filename; // STRIFE-FIXME: memory leak!!
+            }
+            else
+                disable_voices = 1;
         }
-        else
+
+        if(disable_voices) // voices disabled?
         {
-            gamemode = shareware;
+            // STRIFE-FIXME:
+            // if(debugmode)
+                 printf("Voices disabled\n");
+            return;
         }
-    }
-    else
-    {
-        // Doom 2 of some kind.

-        gamemode = commercial;
+        D_AddFile(name);
     }
 }

@@ -1625,7 +1676,7 @@ void D_DoomMain (void)
 #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 ();
diff --git a/src/strife/p_dialog.c b/src/strife/p_dialog.c
index 8e4b1bc1..bd32ee33 100644
--- a/src/strife/p_dialog.c
+++ b/src/strife/p_dialog.c
@@ -1151,7 +1151,8 @@ void P_DialogDoChoice(int choice)

     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 @@ void P_DialogStart(player_t *player)
         V_DrawPatchDirect(0, 0, W_CacheLumpNum(pic, PU_CACHE));

     // get voice
-    //I_StartVoice(currentdialog->voice);
+    I_StartVoice(currentdialog->voice);

     // get bye text
     switch(rnd)
diff --git a/src/strife/s_sound.c b/src/strife/s_sound.c
index 52751e10..6a6ddd15 100644
--- a/src/strife/s_sound.c
+++ b/src/strife/s_sound.c
@@ -137,8 +137,9 @@ int disable_voices = 0;
 // 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 @@ void S_Init(int sfxVolume, int musicVolume)

     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 @@ void S_StopSound(mobj_t *origin)

     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 @@ static int S_GetChannel(mobj_t *origin, sfxinfo_t *sfxinfo, boolean isvoice)
     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,7 +501,81 @@ void S_StartSound(void *origin_p, int sfx_id)
     }

     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
@@ -508,14 +588,14 @@ void S_StartSound(void *origin_p, int sfx_id)
 //
 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 @@ void I_StartVoice(const char *lumpname)
         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);
     }
 }

diff --git a/src/strife/s_sound.h b/src/strife/s_sound.h
index 1cb70fa0..5e763014 100644
--- 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
@@ -97,5 +97,7 @@ void S_SetVoiceVolume(int volume); // haleyjd 09/11/10: [STRIFE]

 extern int snd_channels;

+extern int disable_voices;
+
 #endif