shithub: choc

Download patch

ref: c996c125b7dc26ea47bfce278208a5eab458b6b8
parent: 2e1a244af4ec358529cba5d0bdd3242be4a29f6b
author: Mike Swanson <mikeonthecomputer@gmail.com>
date: Tue Jun 7 06:03:34 EDT 2016

Convert files from CRLF to LF line endings.

--- a/src/doom/statdump.c
+++ b/src/doom/statdump.c
@@ -1,356 +1,356 @@
- /*
-
- Copyright(C) 2005-2014 Simon Howard
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- --
-
- Functions for presenting the information captured from the statistics
- buffer to a file.
-
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "d_player.h"
-#include "d_mode.h"
-#include "m_argv.h"
-
-#include "statdump.h"
-
-/* Par times for E1M1-E1M9. */
-static const int doom1_par_times[] =
-{
-    30, 75, 120, 90, 165, 180, 180, 30, 165,
-};
-
-/* Par times for MAP01-MAP09. */
-static const int doom2_par_times[] =
-{
-    30, 90, 120, 120, 90, 150, 120, 120, 270,
-};
-
-/* Player colors. */
-static const char *player_colors[] =
-{
-    "Green", "Indigo", "Brown", "Red"
-};
-
-// Array of end-of-level statistics that have been captured.
-
-#define MAX_CAPTURES 32
-static wbstartstruct_t captured_stats[MAX_CAPTURES];
-static int num_captured_stats = 0;
-
-static GameMission_t discovered_gamemission = none;
-
-/* Try to work out whether this is a Doom 1 or Doom 2 game, by looking
- * at the episode and map, and the par times.  This is used to decide
- * how to format the level name.  Unfortunately, in some cases it is
- * impossible to determine whether this is Doom 1 or Doom 2. */
-
-static void DiscoverGamemode(wbstartstruct_t *stats, int num_stats)
-{
-    int partime;
-    int level;
-    int i;
-
-    if (discovered_gamemission != none)
-    {
-        return;
-    }
-
-    for (i=0; i<num_stats; ++i)
-    {
-        level = stats[i].last;
-
-        /* If episode 2, 3 or 4, this is Doom 1. */
-
-        if (stats[i].epsd > 0)
-        {
-            discovered_gamemission = doom;
-            return;
-        }
-
-        /* This is episode 1.  If this is level 10 or higher,
-           it must be Doom 2. */
-
-        if (level >= 9)
-        {
-            discovered_gamemission = doom2;
-            return;
-        }
-
-        /* Try to work out if this is Doom 1 or Doom 2 by looking
-           at the par time. */
-
-        partime = stats[i].partime;
-
-        if (partime == doom1_par_times[level] * TICRATE
-         && partime != doom2_par_times[level] * TICRATE)
-        {
-            discovered_gamemission = doom;
-            return;
-        }
-
-        if (partime != doom1_par_times[level] * TICRATE
-         && partime == doom2_par_times[level] * TICRATE)
-        {
-            discovered_gamemission = doom2;
-            return;
-        }
-    }
-}
-
-/* Returns the number of players active in the given stats buffer. */
-
-static int GetNumPlayers(wbstartstruct_t *stats)
-{
-    int i;
-    int num_players = 0;
-
-    for (i=0; i<MAXPLAYERS; ++i)
-    {
-        if (stats->plyr[i].in)
-        {
-            ++num_players;
-        }
-    }
-
-    return num_players;
-}
-
-static void PrintBanner(FILE *stream)
-{
-    fprintf(stream, "===========================================\n");
-}
-
-static void PrintPercentage(FILE *stream, int amount, int total)
-{
-    if (total == 0)
-    {
-        fprintf(stream, "0");
-    }
-    else
-    {
-        fprintf(stream, "%i / %i", amount, total);
-
-        // statdump.exe is a 16-bit program, so very occasionally an
-        // integer overflow can occur when doing this calculation with
-        // a large value. Therefore, cast to short to give the same
-        // output.
-
-        fprintf(stream, " (%i%%)", (short) (amount * 100) / total);
-    }
-}
-
-/* Display statistics for a single player. */
-
-static void PrintPlayerStats(FILE *stream, wbstartstruct_t *stats,
-        int player_num)
-{
-    wbplayerstruct_t *player = &stats->plyr[player_num];
-
-    fprintf(stream, "Player %i (%s):\n", player_num + 1,
-            player_colors[player_num]);
-
-    /* Kills percentage */
-
-    fprintf(stream, "\tKills: ");
-    PrintPercentage(stream, player->skills, stats->maxkills);
-    fprintf(stream, "\n");
-
-    /* Items percentage */
-
-    fprintf(stream, "\tItems: ");
-    PrintPercentage(stream, player->sitems, stats->maxitems);
-    fprintf(stream, "\n");
-
-    /* Secrets percentage */
-
-    fprintf(stream, "\tSecrets: ");
-    PrintPercentage(stream, player->ssecret, stats->maxsecret);
-    fprintf(stream, "\n");
-}
-
-/* Frags table for multiplayer games. */
-
-static void PrintFragsTable(FILE *stream, wbstartstruct_t *stats)
-{
-    int x, y;
-
-    fprintf(stream, "Frags:\n");
-
-    /* Print header */
-
-    fprintf(stream, "\t\t");
-
-    for (x=0; x<MAXPLAYERS; ++x)
-    {
-
-        if (!stats->plyr[x].in)
-        {
-            continue;
-        }
-
-        fprintf(stream, "%s\t", player_colors[x]);
-    }
-
-    fprintf(stream, "\n");
-
-    fprintf(stream, "\t\t-------------------------------- VICTIMS\n");
-
-    /* Print table */
-
-    for (y=0; y<MAXPLAYERS; ++y)
-    {
-        if (!stats->plyr[y].in)
-        {
-            continue;
-        }
-
-        fprintf(stream, "\t%s\t|", player_colors[y]);
-
-        for (x=0; x<MAXPLAYERS; ++x)
-        {
-            if (!stats->plyr[x].in)
-            {
-                continue;
-            }
-
-            fprintf(stream, "%i\t", stats->plyr[y].frags[x]);
-        }
-
-        fprintf(stream, "\n");
-    }
-
-    fprintf(stream, "\t\t|\n");
-    fprintf(stream, "\t     KILLERS\n");
-}
-
-/* Displays the level name: MAPxy or ExMy, depending on game mode. */
-
-static void PrintLevelName(FILE *stream, int episode, int level)
-{
-    PrintBanner(stream);
-
-    switch (discovered_gamemission)
-    {
-
-        case doom:
-            fprintf(stream, "E%iM%i\n", episode + 1, level + 1);
-            break;
-        case doom2:
-            fprintf(stream, "MAP%02i\n", level + 1);
-            break;
-        default:
-        case none:
-            fprintf(stream, "E%iM%i / MAP%02i\n", 
-                    episode + 1, level + 1, level + 1);
-            break;
-    }
-
-    PrintBanner(stream);
-}
-
-/* Print details of a statistics buffer to the given file. */
-
-static void PrintStats(FILE *stream, wbstartstruct_t *stats)
-{
-    int leveltime, partime;
-    int i;
-
-    PrintLevelName(stream, stats->epsd, stats->last);
-    fprintf(stream, "\n");
-
-    leveltime = stats->plyr[0].stime / TICRATE;
-    partime = stats->partime / TICRATE;
-    fprintf(stream, "Time: %i:%02i", leveltime / 60, leveltime % 60);
-    fprintf(stream, " (par: %i:%02i)\n", partime / 60, partime % 60);
-    fprintf(stream, "\n");
-
-    for (i=0; i<MAXPLAYERS; ++i)
-    {
-        if (stats->plyr[i].in)
-        {
-            PrintPlayerStats(stream, stats, i);
-        }
-    }
-
-    if (GetNumPlayers(stats) >= 2)
-    {
-        PrintFragsTable(stream, stats);
-    }
-
-    fprintf(stream, "\n");
-}
-
-void StatCopy(wbstartstruct_t *stats)
-{
-    if (M_ParmExists("-statdump") && num_captured_stats < MAX_CAPTURES)
-    {
-        memcpy(&captured_stats[num_captured_stats], stats,
-               sizeof(wbstartstruct_t));
-        ++num_captured_stats;
-    }
-}
-
-void StatDump(void)
-{
-    FILE *dumpfile;
-    int i;
-
-    //!
-    // @category compat
-    // @arg <filename>
-    //
-    // Dump statistics information to the specified file on the levels
-    // that were played. The output from this option matches the output
-    // from statdump.exe (see ctrlapi.zip in the /idgames archive).
-    //
-
-    i = M_CheckParmWithArgs("-statdump", 1);
-
-    if (i > 0)
-    {
-        printf("Statistics captured for %i level(s)\n", num_captured_stats);
-
-        // We actually know what the real gamemission is, but this has
-        // to match the output from statdump.exe.
-
-        DiscoverGamemode(captured_stats, num_captured_stats);
-
-        // Allow "-" as output file, for stdout.
-
-        if (strcmp(myargv[i + 1], "-") != 0)
-        {
-            dumpfile = fopen(myargv[i + 1], "w");
-        }
-        else
-        {
-            dumpfile = NULL;
-        }
-
-        for (i = 0; i < num_captured_stats; ++i)
-        {
-            PrintStats(dumpfile, &captured_stats[i]);
-        }
-
-        if (dumpfile != NULL)
-        {
-            fclose(dumpfile);
-        }
-    }
-}
-
+ /*
+
+ Copyright(C) 2005-2014 Simon Howard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ --
+
+ Functions for presenting the information captured from the statistics
+ buffer to a file.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "d_player.h"
+#include "d_mode.h"
+#include "m_argv.h"
+
+#include "statdump.h"
+
+/* Par times for E1M1-E1M9. */
+static const int doom1_par_times[] =
+{
+    30, 75, 120, 90, 165, 180, 180, 30, 165,
+};
+
+/* Par times for MAP01-MAP09. */
+static const int doom2_par_times[] =
+{
+    30, 90, 120, 120, 90, 150, 120, 120, 270,
+};
+
+/* Player colors. */
+static const char *player_colors[] =
+{
+    "Green", "Indigo", "Brown", "Red"
+};
+
+// Array of end-of-level statistics that have been captured.
+
+#define MAX_CAPTURES 32
+static wbstartstruct_t captured_stats[MAX_CAPTURES];
+static int num_captured_stats = 0;
+
+static GameMission_t discovered_gamemission = none;
+
+/* Try to work out whether this is a Doom 1 or Doom 2 game, by looking
+ * at the episode and map, and the par times.  This is used to decide
+ * how to format the level name.  Unfortunately, in some cases it is
+ * impossible to determine whether this is Doom 1 or Doom 2. */
+
+static void DiscoverGamemode(wbstartstruct_t *stats, int num_stats)
+{
+    int partime;
+    int level;
+    int i;
+
+    if (discovered_gamemission != none)
+    {
+        return;
+    }
+
+    for (i=0; i<num_stats; ++i)
+    {
+        level = stats[i].last;
+
+        /* If episode 2, 3 or 4, this is Doom 1. */
+
+        if (stats[i].epsd > 0)
+        {
+            discovered_gamemission = doom;
+            return;
+        }
+
+        /* This is episode 1.  If this is level 10 or higher,
+           it must be Doom 2. */
+
+        if (level >= 9)
+        {
+            discovered_gamemission = doom2;
+            return;
+        }
+
+        /* Try to work out if this is Doom 1 or Doom 2 by looking
+           at the par time. */
+
+        partime = stats[i].partime;
+
+        if (partime == doom1_par_times[level] * TICRATE
+         && partime != doom2_par_times[level] * TICRATE)
+        {
+            discovered_gamemission = doom;
+            return;
+        }
+
+        if (partime != doom1_par_times[level] * TICRATE
+         && partime == doom2_par_times[level] * TICRATE)
+        {
+            discovered_gamemission = doom2;
+            return;
+        }
+    }
+}
+
+/* Returns the number of players active in the given stats buffer. */
+
+static int GetNumPlayers(wbstartstruct_t *stats)
+{
+    int i;
+    int num_players = 0;
+
+    for (i=0; i<MAXPLAYERS; ++i)
+    {
+        if (stats->plyr[i].in)
+        {
+            ++num_players;
+        }
+    }
+
+    return num_players;
+}
+
+static void PrintBanner(FILE *stream)
+{
+    fprintf(stream, "===========================================\n");
+}
+
+static void PrintPercentage(FILE *stream, int amount, int total)
+{
+    if (total == 0)
+    {
+        fprintf(stream, "0");
+    }
+    else
+    {
+        fprintf(stream, "%i / %i", amount, total);
+
+        // statdump.exe is a 16-bit program, so very occasionally an
+        // integer overflow can occur when doing this calculation with
+        // a large value. Therefore, cast to short to give the same
+        // output.
+
+        fprintf(stream, " (%i%%)", (short) (amount * 100) / total);
+    }
+}
+
+/* Display statistics for a single player. */
+
+static void PrintPlayerStats(FILE *stream, wbstartstruct_t *stats,
+        int player_num)
+{
+    wbplayerstruct_t *player = &stats->plyr[player_num];
+
+    fprintf(stream, "Player %i (%s):\n", player_num + 1,
+            player_colors[player_num]);
+
+    /* Kills percentage */
+
+    fprintf(stream, "\tKills: ");
+    PrintPercentage(stream, player->skills, stats->maxkills);
+    fprintf(stream, "\n");
+
+    /* Items percentage */
+
+    fprintf(stream, "\tItems: ");
+    PrintPercentage(stream, player->sitems, stats->maxitems);
+    fprintf(stream, "\n");
+
+    /* Secrets percentage */
+
+    fprintf(stream, "\tSecrets: ");
+    PrintPercentage(stream, player->ssecret, stats->maxsecret);
+    fprintf(stream, "\n");
+}
+
+/* Frags table for multiplayer games. */
+
+static void PrintFragsTable(FILE *stream, wbstartstruct_t *stats)
+{
+    int x, y;
+
+    fprintf(stream, "Frags:\n");
+
+    /* Print header */
+
+    fprintf(stream, "\t\t");
+
+    for (x=0; x<MAXPLAYERS; ++x)
+    {
+
+        if (!stats->plyr[x].in)
+        {
+            continue;
+        }
+
+        fprintf(stream, "%s\t", player_colors[x]);
+    }
+
+    fprintf(stream, "\n");
+
+    fprintf(stream, "\t\t-------------------------------- VICTIMS\n");
+
+    /* Print table */
+
+    for (y=0; y<MAXPLAYERS; ++y)
+    {
+        if (!stats->plyr[y].in)
+        {
+            continue;
+        }
+
+        fprintf(stream, "\t%s\t|", player_colors[y]);
+
+        for (x=0; x<MAXPLAYERS; ++x)
+        {
+            if (!stats->plyr[x].in)
+            {
+                continue;
+            }
+
+            fprintf(stream, "%i\t", stats->plyr[y].frags[x]);
+        }
+
+        fprintf(stream, "\n");
+    }
+
+    fprintf(stream, "\t\t|\n");
+    fprintf(stream, "\t     KILLERS\n");
+}
+
+/* Displays the level name: MAPxy or ExMy, depending on game mode. */
+
+static void PrintLevelName(FILE *stream, int episode, int level)
+{
+    PrintBanner(stream);
+
+    switch (discovered_gamemission)
+    {
+
+        case doom:
+            fprintf(stream, "E%iM%i\n", episode + 1, level + 1);
+            break;
+        case doom2:
+            fprintf(stream, "MAP%02i\n", level + 1);
+            break;
+        default:
+        case none:
+            fprintf(stream, "E%iM%i / MAP%02i\n", 
+                    episode + 1, level + 1, level + 1);
+            break;
+    }
+
+    PrintBanner(stream);
+}
+
+/* Print details of a statistics buffer to the given file. */
+
+static void PrintStats(FILE *stream, wbstartstruct_t *stats)
+{
+    int leveltime, partime;
+    int i;
+
+    PrintLevelName(stream, stats->epsd, stats->last);
+    fprintf(stream, "\n");
+
+    leveltime = stats->plyr[0].stime / TICRATE;
+    partime = stats->partime / TICRATE;
+    fprintf(stream, "Time: %i:%02i", leveltime / 60, leveltime % 60);
+    fprintf(stream, " (par: %i:%02i)\n", partime / 60, partime % 60);
+    fprintf(stream, "\n");
+
+    for (i=0; i<MAXPLAYERS; ++i)
+    {
+        if (stats->plyr[i].in)
+        {
+            PrintPlayerStats(stream, stats, i);
+        }
+    }
+
+    if (GetNumPlayers(stats) >= 2)
+    {
+        PrintFragsTable(stream, stats);
+    }
+
+    fprintf(stream, "\n");
+}
+
+void StatCopy(wbstartstruct_t *stats)
+{
+    if (M_ParmExists("-statdump") && num_captured_stats < MAX_CAPTURES)
+    {
+        memcpy(&captured_stats[num_captured_stats], stats,
+               sizeof(wbstartstruct_t));
+        ++num_captured_stats;
+    }
+}
+
+void StatDump(void)
+{
+    FILE *dumpfile;
+    int i;
+
+    //!
+    // @category compat
+    // @arg <filename>
+    //
+    // Dump statistics information to the specified file on the levels
+    // that were played. The output from this option matches the output
+    // from statdump.exe (see ctrlapi.zip in the /idgames archive).
+    //
+
+    i = M_CheckParmWithArgs("-statdump", 1);
+
+    if (i > 0)
+    {
+        printf("Statistics captured for %i level(s)\n", num_captured_stats);
+
+        // We actually know what the real gamemission is, but this has
+        // to match the output from statdump.exe.
+
+        DiscoverGamemode(captured_stats, num_captured_stats);
+
+        // Allow "-" as output file, for stdout.
+
+        if (strcmp(myargv[i + 1], "-") != 0)
+        {
+            dumpfile = fopen(myargv[i + 1], "w");
+        }
+        else
+        {
+            dumpfile = NULL;
+        }
+
+        for (i = 0; i < num_captured_stats; ++i)
+        {
+            PrintStats(dumpfile, &captured_stats[i]);
+        }
+
+        if (dumpfile != NULL)
+        {
+            fclose(dumpfile);
+        }
+    }
+}
+
--- a/src/doom/statdump.h
+++ b/src/doom/statdump.h
@@ -1,23 +1,23 @@
- /*
-
- Copyright(C) 2005-2014 Simon Howard
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- */
-
-#ifndef DOOM_STATDUMP_H
-#define DOOM_STATDUMP_H
-
-void StatCopy(wbstartstruct_t *stats);
-void StatDump(void);
-
-#endif /* #ifndef DOOM_STATDUMP_H */
+ /*
+
+ Copyright(C) 2005-2014 Simon Howard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ */
+
+#ifndef DOOM_STATDUMP_H
+#define DOOM_STATDUMP_H
+
+void StatCopy(wbstartstruct_t *stats);
+void StatDump(void);
+
+#endif /* #ifndef DOOM_STATDUMP_H */
--- a/src/strife/m_saves.c
+++ b/src/strife/m_saves.c
@@ -1,528 +1,528 @@
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 2010 James Haley, Samuel Villarreal
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// DESCRIPTION:
-//
-// [STRIFE] New Module
-//
-// Strife Hub Saving Code
-//
-
-// For GNU C and POSIX targets, dirent.h should be available. Otherwise, for
-// Visual C++, we need to include the win_opendir module.
-#if defined(_MSC_VER)
-#include <win_opendir.h>
-#elif defined(__GNUC__) || defined(POSIX)
-#include <dirent.h>
-#else
-#error Need an include for dirent.h!
-#endif
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "z_zone.h"
-#include "i_system.h"
-#include "d_player.h"
-#include "deh_str.h"
-#include "doomstat.h"
-#include "m_misc.h"
-#include "m_saves.h"
-#include "p_dialog.h"
-
-//
-// File Paths
-//
-// Strife maintains multiple file paths related to savegames.
-//
-char *savepath;     // The actual path of the selected saveslot
-char *savepathtemp; // The path of the temporary saveslot (strfsav6.ssg)
-char *loadpath;     // Path used while loading the game
-
-char character_name[CHARACTER_NAME_LEN]; // Name of "character" for saveslot
-
-//
-// ClearTmp
-//
-// Clear the temporary save directory
-//
-void ClearTmp(void)
-{
-    DIR *sp2dir = NULL;
-    struct dirent *f = NULL;
-
-    if(savepathtemp == NULL)
-        I_Error("you fucked up savedir man!");
-
-    if(!(sp2dir = opendir(savepathtemp)))
-        I_Error("ClearTmp: Couldn't open dir %s", savepathtemp);
-
-    while((f = readdir(sp2dir)))
-    {
-        char *filepath = NULL;
-
-        // haleyjd: skip "." and ".." without assuming they're the
-        // first two entries like the original code did.
-        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
-            continue;
-
-        // haleyjd: use M_SafeFilePath, not sprintf
-        filepath = M_SafeFilePath(savepathtemp, f->d_name);
-        remove(filepath);
-
-        Z_Free(filepath);
-    }
-
-    closedir(sp2dir);
-}
-
-//
-// ClearSlot
-//
-// Clear a single save slot folder
-//
-void ClearSlot(void)
-{
-    DIR *spdir = NULL;
-    struct dirent *f = NULL;
-
-    if(savepath == NULL)
-        I_Error("userdir is fucked up man!");
-
-    if(!(spdir = opendir(savepath)))
-        I_Error("ClearSlot: Couldn't open dir %s", savepath);
-
-    while((f = readdir(spdir)))
-    {
-        char *filepath = NULL;
-
-        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
-            continue;
-        
-        // haleyjd: use M_SafeFilePath, not sprintf
-        filepath = M_SafeFilePath(savepath, f->d_name);
-        remove(filepath);
-
-        Z_Free(filepath);
-    }
-
-    closedir(spdir);
-}
-
-//
-// FromCurr
-//
-// Copying files from savepathtemp to savepath
-//
-void FromCurr(void)
-{
-    DIR *sp2dir = NULL;
-    struct dirent *f = NULL;
-
-    if(!(sp2dir = opendir(savepathtemp)))
-        I_Error("FromCurr: Couldn't open dir %s", savepathtemp);
-
-    while((f = readdir(sp2dir)))
-    {
-        byte *filebuffer  = NULL;
-        int   filelen     = 0;
-        char *srcfilename = NULL;
-        char *dstfilename = NULL;
-
-        // haleyjd: skip "." and ".." without assuming they're the
-        // first two entries like the original code did.
-        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
-            continue;
-
-        // haleyjd: use M_SafeFilePath, NOT sprintf.
-        srcfilename = M_SafeFilePath(savepathtemp, f->d_name);
-        dstfilename = M_SafeFilePath(savepath,     f->d_name);
-
-        filelen = M_ReadFile(srcfilename, &filebuffer);
-        M_WriteFile(dstfilename, filebuffer, filelen);
-
-        Z_Free(filebuffer);
-        Z_Free(srcfilename);
-        Z_Free(dstfilename);
-    }
-
-    closedir(sp2dir);
-}
-
-//
-// ToCurr
-//
-// Copying files from savepath to savepathtemp
-//
-void ToCurr(void)
-{
-    DIR *spdir = NULL;
-    struct dirent *f = NULL;
-
-    ClearTmp();
-
-    // BUG: Rogue copypasta'd this error message, which is why we don't know
-    // the real original name of this function.
-    if(!(spdir = opendir(savepath)))
-        I_Error("ClearSlot: Couldn't open dir %s", savepath);
-
-    while((f = readdir(spdir)))
-    {
-        byte *filebuffer  = NULL;
-        int   filelen     = 0;
-        char *srcfilename = NULL;
-        char *dstfilename = NULL;
-
-        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
-            continue;
-
-        // haleyjd: use M_SafeFilePath, NOT sprintf.
-        srcfilename = M_SafeFilePath(savepath,     f->d_name);
-        dstfilename = M_SafeFilePath(savepathtemp, f->d_name);
-
-        filelen = M_ReadFile(srcfilename, &filebuffer);
-        M_WriteFile(dstfilename, filebuffer, filelen);
-
-        Z_Free(filebuffer);
-        Z_Free(srcfilename);
-        Z_Free(dstfilename);
-    }
-
-    closedir(spdir);
-}
-
-//
-// M_SaveMoveMapToHere
-//
-// Moves a map to the "HERE" save.
-//
-void M_SaveMoveMapToHere(void)
-{
-    char *mapsave  = NULL;
-    char *heresave = NULL;
-    char tmpnum[33];
-
-    // haleyjd: no itoa available...
-    M_snprintf(tmpnum, sizeof(tmpnum), "%d", gamemap);
-
-    // haleyjd: use M_SafeFilePath, not sprintf
-    mapsave  = M_SafeFilePath(savepath, tmpnum);
-    heresave = M_SafeFilePath(savepath, "here");
-
-    // haleyjd: use M_FileExists, not access
-    if(M_FileExists(mapsave))
-    {
-        remove(heresave);
-        rename(mapsave, heresave);
-    }
-
-    Z_Free(mapsave);
-    Z_Free(heresave);
-}
-
-//
-// M_SaveMoveHereToMap
-//
-// Moves the "HERE" save to a map.
-//
-void M_SaveMoveHereToMap(void)
-{
-    char *mapsave  = NULL;
-    char *heresave = NULL;
-    char tmpnum[33];
-
-    // haleyjd: no itoa available...
-    M_snprintf(tmpnum, sizeof(tmpnum), "%d", gamemap);
-
-    mapsave  = M_SafeFilePath(savepathtemp, tmpnum);
-    heresave = M_SafeFilePath(savepathtemp, "here");
-
-    if(M_FileExists(heresave))
-    {
-        remove(mapsave);
-        rename(heresave, mapsave);
-    }
-
-    Z_Free(mapsave);
-    Z_Free(heresave);
-}
-
-//
-// M_SaveMisObj
-//
-// Writes the mission objective into the MIS_OBJ file.
-//
-boolean M_SaveMisObj(const char *path)
-{
-    boolean result;
-    char *destpath = NULL;
-
-    // haleyjd 20110210: use M_SafeFilePath, not sprintf
-    destpath = M_SafeFilePath(path, "mis_obj");
-    result   = M_WriteFile(destpath, mission_objective, OBJECTIVE_LEN);
-
-    Z_Free(destpath);
-    return result;
-}
-
-//
-// M_ReadMisObj
-//
-// Reads the mission objective from the MIS_OBJ file.
-//
-void M_ReadMisObj(void)
-{
-    FILE *f = NULL;
-    char *srcpath = NULL;
-
-    // haleyjd: use M_SafeFilePath, not sprintf
-    srcpath = M_SafeFilePath(savepathtemp, "mis_obj");
-
-    if((f = fopen(srcpath, "rb")))
-    {
-        fread(mission_objective, 1, OBJECTIVE_LEN, f);
-        fclose(f);
-    }
-
-    Z_Free(srcpath);
-}
-
-//=============================================================================
-//
-// Original Routines
-//
-// haleyjd - None of the below code is derived from Strife itself, but has been
-// adapted or created in order to provide secure, portable filepath handling
-// for the purposes of savegame support. This is partially needed to allow for
-// differences in Choco due to it being multiplatform. The rest exists because
-// I cannot stand programming in an impoverished ANSI C environment that
-// calls sprintf on fixed-size buffers. :P
-//
-
-//
-// M_Calloc
-//
-// haleyjd 20110210 - original routine
-// Because Choco doesn't have Z_Calloc O_o
-//
-void *M_Calloc(size_t n1, size_t n2)
-{
-    return (n1 *= n2) ? memset(Z_Malloc(n1, PU_STATIC, NULL), 0, n1) : NULL;
-}
-
-//
-// M_StringAlloc
-//
-// haleyjd: This routine takes any number of strings and a number of extra
-// characters, calculates their combined length, and calls Z_Alloca to create
-// a temporary buffer of that size. This is extremely useful for allocation of
-// file paths, and is used extensively in d_main.c.  The pointer returned is
-// to a temporary Z_Alloca buffer, which lives until the next main loop
-// iteration, so don't cache it. Note that this idiom is not possible with the
-// normal non-standard alloca function, which allocates stack space.
-//
-// [STRIFE] - haleyjd 20110210
-// This routine is taken from the Eternity Engine and adapted to do without
-// Z_Alloca. I need secure string concatenation for filepath handling. The
-// only difference from use in EE is that the pointer returned in *str must
-// be manually freed.
-//
-int M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...)
-{
-    va_list args;
-    size_t len = extra;
-
-    if(numstrs < 1)
-        I_Error("M_StringAlloc: invalid input\n");
-
-    len += strlen(str1);
-
-    --numstrs;
-
-    if(numstrs != 0)
-    {   
-        va_start(args, str1);
-
-        while(numstrs != 0)
-        {
-            const char *argstr = va_arg(args, const char *);
-
-            len += strlen(argstr);
-
-            --numstrs;
-        }
-
-        va_end(args);
-    }
-
-    ++len;
-
-    *str = (char *)(M_Calloc(1, len));
-
-    return len;
-}
-
-//
-// M_NormalizeSlashes
-//
-// Remove trailing slashes, translate backslashes to slashes
-// The string to normalize is passed and returned in str
-//
-// killough 11/98: rewritten
-//
-// [STRIFE] - haleyjd 20110210: Borrowed from Eternity and adapted to respect 
-// the DIR_SEPARATOR define used by Choco Doom. This routine originated in
-// BOOM.
-//
-void M_NormalizeSlashes(char *str)
-{
-    char *p;
-   
-    // Convert all slashes/backslashes to DIR_SEPARATOR
-    for(p = str; *p; p++)
-    {
-        if((*p == '/' || *p == '\\') && *p != DIR_SEPARATOR)
-            *p = DIR_SEPARATOR;
-    }
-
-    // Remove trailing slashes
-    while(p > str && *--p == DIR_SEPARATOR)
-        *p = 0;
-
-    // Collapse multiple slashes
-    for(p = str; (*str++ = *p); )
-        if(*p++ == DIR_SEPARATOR)
-            while(*p == DIR_SEPARATOR)
-                p++;
-}
-
-//
-// M_SafeFilePath
-//
-// haleyjd 20110210 - original routine.
-// This routine performs safe, portable concatenation of a base file path
-// with another path component or file name. The returned string is Z_Malloc'd
-// and should be freed when it has exhausted its usefulness.
-//
-char *M_SafeFilePath(const char *basepath, const char *newcomponent)
-{
-    int   newstrlen = 0;
-    char *newstr = NULL;
-
-    if (!strcmp(basepath, ""))
-    {
-        basepath = ".";
-    }
-
-    // Always throw in a slash. M_NormalizeSlashes will remove it in the case
-    // that either basepath or newcomponent includes a redundant slash at the
-    // end or beginning respectively.
-    newstrlen = M_StringAlloc(&newstr, 3, 1, basepath, "/", newcomponent);
-    M_snprintf(newstr, newstrlen, "%s/%s", basepath, newcomponent);
-    M_NormalizeSlashes(newstr);
-
-    return newstr;
-}
-
-//
-// M_CreateSaveDirs
-//
-// haleyjd 20110210: Vanilla Strife went tits-up if it didn't have the full set
-// of save folders which were created externally by the installer. fraggle says
-// that's no good for Choco purposes, and I agree, so this routine will create
-// the full set of folders under the configured savegamedir.
-//
-void M_CreateSaveDirs(const char *savedir)
-{
-    int i;
-
-    for(i = 0; i < 7; i++)
-    {
-        char *compositedir;
-
-        // compose the full path by concatenating with savedir
-        compositedir = M_SafeFilePath(savedir, M_MakeStrifeSaveDir(i, ""));
-
-        M_MakeDirectory(compositedir);
-
-        Z_Free(compositedir);
-    }
-}
-
-//
-// M_MakeStrifeSaveDir
-//
-// haleyjd 20110211: Convenience routine
-//
-char *M_MakeStrifeSaveDir(int slotnum, const char *extra)
-{
-    static char tmpbuffer[32];
-
-    M_snprintf(tmpbuffer, sizeof(tmpbuffer),
-               "strfsav%d.ssg%s", slotnum, extra);
-
-    return tmpbuffer;
-}
-
-// 
-// M_GetFilePath
-//
-// 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;
-
-    M_StringCopy(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;
-}
-
-// EOF
-
-
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2010 James Haley, Samuel Villarreal
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// DESCRIPTION:
+//
+// [STRIFE] New Module
+//
+// Strife Hub Saving Code
+//
+
+// For GNU C and POSIX targets, dirent.h should be available. Otherwise, for
+// Visual C++, we need to include the win_opendir module.
+#if defined(_MSC_VER)
+#include <win_opendir.h>
+#elif defined(__GNUC__) || defined(POSIX)
+#include <dirent.h>
+#else
+#error Need an include for dirent.h!
+#endif
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "z_zone.h"
+#include "i_system.h"
+#include "d_player.h"
+#include "deh_str.h"
+#include "doomstat.h"
+#include "m_misc.h"
+#include "m_saves.h"
+#include "p_dialog.h"
+
+//
+// File Paths
+//
+// Strife maintains multiple file paths related to savegames.
+//
+char *savepath;     // The actual path of the selected saveslot
+char *savepathtemp; // The path of the temporary saveslot (strfsav6.ssg)
+char *loadpath;     // Path used while loading the game
+
+char character_name[CHARACTER_NAME_LEN]; // Name of "character" for saveslot
+
+//
+// ClearTmp
+//
+// Clear the temporary save directory
+//
+void ClearTmp(void)
+{
+    DIR *sp2dir = NULL;
+    struct dirent *f = NULL;
+
+    if(savepathtemp == NULL)
+        I_Error("you fucked up savedir man!");
+
+    if(!(sp2dir = opendir(savepathtemp)))
+        I_Error("ClearTmp: Couldn't open dir %s", savepathtemp);
+
+    while((f = readdir(sp2dir)))
+    {
+        char *filepath = NULL;
+
+        // haleyjd: skip "." and ".." without assuming they're the
+        // first two entries like the original code did.
+        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+            continue;
+
+        // haleyjd: use M_SafeFilePath, not sprintf
+        filepath = M_SafeFilePath(savepathtemp, f->d_name);
+        remove(filepath);
+
+        Z_Free(filepath);
+    }
+
+    closedir(sp2dir);
+}
+
+//
+// ClearSlot
+//
+// Clear a single save slot folder
+//
+void ClearSlot(void)
+{
+    DIR *spdir = NULL;
+    struct dirent *f = NULL;
+
+    if(savepath == NULL)
+        I_Error("userdir is fucked up man!");
+
+    if(!(spdir = opendir(savepath)))
+        I_Error("ClearSlot: Couldn't open dir %s", savepath);
+
+    while((f = readdir(spdir)))
+    {
+        char *filepath = NULL;
+
+        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+            continue;
+        
+        // haleyjd: use M_SafeFilePath, not sprintf
+        filepath = M_SafeFilePath(savepath, f->d_name);
+        remove(filepath);
+
+        Z_Free(filepath);
+    }
+
+    closedir(spdir);
+}
+
+//
+// FromCurr
+//
+// Copying files from savepathtemp to savepath
+//
+void FromCurr(void)
+{
+    DIR *sp2dir = NULL;
+    struct dirent *f = NULL;
+
+    if(!(sp2dir = opendir(savepathtemp)))
+        I_Error("FromCurr: Couldn't open dir %s", savepathtemp);
+
+    while((f = readdir(sp2dir)))
+    {
+        byte *filebuffer  = NULL;
+        int   filelen     = 0;
+        char *srcfilename = NULL;
+        char *dstfilename = NULL;
+
+        // haleyjd: skip "." and ".." without assuming they're the
+        // first two entries like the original code did.
+        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+            continue;
+
+        // haleyjd: use M_SafeFilePath, NOT sprintf.
+        srcfilename = M_SafeFilePath(savepathtemp, f->d_name);
+        dstfilename = M_SafeFilePath(savepath,     f->d_name);
+
+        filelen = M_ReadFile(srcfilename, &filebuffer);
+        M_WriteFile(dstfilename, filebuffer, filelen);
+
+        Z_Free(filebuffer);
+        Z_Free(srcfilename);
+        Z_Free(dstfilename);
+    }
+
+    closedir(sp2dir);
+}
+
+//
+// ToCurr
+//
+// Copying files from savepath to savepathtemp
+//
+void ToCurr(void)
+{
+    DIR *spdir = NULL;
+    struct dirent *f = NULL;
+
+    ClearTmp();
+
+    // BUG: Rogue copypasta'd this error message, which is why we don't know
+    // the real original name of this function.
+    if(!(spdir = opendir(savepath)))
+        I_Error("ClearSlot: Couldn't open dir %s", savepath);
+
+    while((f = readdir(spdir)))
+    {
+        byte *filebuffer  = NULL;
+        int   filelen     = 0;
+        char *srcfilename = NULL;
+        char *dstfilename = NULL;
+
+        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+            continue;
+
+        // haleyjd: use M_SafeFilePath, NOT sprintf.
+        srcfilename = M_SafeFilePath(savepath,     f->d_name);
+        dstfilename = M_SafeFilePath(savepathtemp, f->d_name);
+
+        filelen = M_ReadFile(srcfilename, &filebuffer);
+        M_WriteFile(dstfilename, filebuffer, filelen);
+
+        Z_Free(filebuffer);
+        Z_Free(srcfilename);
+        Z_Free(dstfilename);
+    }
+
+    closedir(spdir);
+}
+
+//
+// M_SaveMoveMapToHere
+//
+// Moves a map to the "HERE" save.
+//
+void M_SaveMoveMapToHere(void)
+{
+    char *mapsave  = NULL;
+    char *heresave = NULL;
+    char tmpnum[33];
+
+    // haleyjd: no itoa available...
+    M_snprintf(tmpnum, sizeof(tmpnum), "%d", gamemap);
+
+    // haleyjd: use M_SafeFilePath, not sprintf
+    mapsave  = M_SafeFilePath(savepath, tmpnum);
+    heresave = M_SafeFilePath(savepath, "here");
+
+    // haleyjd: use M_FileExists, not access
+    if(M_FileExists(mapsave))
+    {
+        remove(heresave);
+        rename(mapsave, heresave);
+    }
+
+    Z_Free(mapsave);
+    Z_Free(heresave);
+}
+
+//
+// M_SaveMoveHereToMap
+//
+// Moves the "HERE" save to a map.
+//
+void M_SaveMoveHereToMap(void)
+{
+    char *mapsave  = NULL;
+    char *heresave = NULL;
+    char tmpnum[33];
+
+    // haleyjd: no itoa available...
+    M_snprintf(tmpnum, sizeof(tmpnum), "%d", gamemap);
+
+    mapsave  = M_SafeFilePath(savepathtemp, tmpnum);
+    heresave = M_SafeFilePath(savepathtemp, "here");
+
+    if(M_FileExists(heresave))
+    {
+        remove(mapsave);
+        rename(heresave, mapsave);
+    }
+
+    Z_Free(mapsave);
+    Z_Free(heresave);
+}
+
+//
+// M_SaveMisObj
+//
+// Writes the mission objective into the MIS_OBJ file.
+//
+boolean M_SaveMisObj(const char *path)
+{
+    boolean result;
+    char *destpath = NULL;
+
+    // haleyjd 20110210: use M_SafeFilePath, not sprintf
+    destpath = M_SafeFilePath(path, "mis_obj");
+    result   = M_WriteFile(destpath, mission_objective, OBJECTIVE_LEN);
+
+    Z_Free(destpath);
+    return result;
+}
+
+//
+// M_ReadMisObj
+//
+// Reads the mission objective from the MIS_OBJ file.
+//
+void M_ReadMisObj(void)
+{
+    FILE *f = NULL;
+    char *srcpath = NULL;
+
+    // haleyjd: use M_SafeFilePath, not sprintf
+    srcpath = M_SafeFilePath(savepathtemp, "mis_obj");
+
+    if((f = fopen(srcpath, "rb")))
+    {
+        fread(mission_objective, 1, OBJECTIVE_LEN, f);
+        fclose(f);
+    }
+
+    Z_Free(srcpath);
+}
+
+//=============================================================================
+//
+// Original Routines
+//
+// haleyjd - None of the below code is derived from Strife itself, but has been
+// adapted or created in order to provide secure, portable filepath handling
+// for the purposes of savegame support. This is partially needed to allow for
+// differences in Choco due to it being multiplatform. The rest exists because
+// I cannot stand programming in an impoverished ANSI C environment that
+// calls sprintf on fixed-size buffers. :P
+//
+
+//
+// M_Calloc
+//
+// haleyjd 20110210 - original routine
+// Because Choco doesn't have Z_Calloc O_o
+//
+void *M_Calloc(size_t n1, size_t n2)
+{
+    return (n1 *= n2) ? memset(Z_Malloc(n1, PU_STATIC, NULL), 0, n1) : NULL;
+}
+
+//
+// M_StringAlloc
+//
+// haleyjd: This routine takes any number of strings and a number of extra
+// characters, calculates their combined length, and calls Z_Alloca to create
+// a temporary buffer of that size. This is extremely useful for allocation of
+// file paths, and is used extensively in d_main.c.  The pointer returned is
+// to a temporary Z_Alloca buffer, which lives until the next main loop
+// iteration, so don't cache it. Note that this idiom is not possible with the
+// normal non-standard alloca function, which allocates stack space.
+//
+// [STRIFE] - haleyjd 20110210
+// This routine is taken from the Eternity Engine and adapted to do without
+// Z_Alloca. I need secure string concatenation for filepath handling. The
+// only difference from use in EE is that the pointer returned in *str must
+// be manually freed.
+//
+int M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...)
+{
+    va_list args;
+    size_t len = extra;
+
+    if(numstrs < 1)
+        I_Error("M_StringAlloc: invalid input\n");
+
+    len += strlen(str1);
+
+    --numstrs;
+
+    if(numstrs != 0)
+    {   
+        va_start(args, str1);
+
+        while(numstrs != 0)
+        {
+            const char *argstr = va_arg(args, const char *);
+
+            len += strlen(argstr);
+
+            --numstrs;
+        }
+
+        va_end(args);
+    }
+
+    ++len;
+
+    *str = (char *)(M_Calloc(1, len));
+
+    return len;
+}
+
+//
+// M_NormalizeSlashes
+//
+// Remove trailing slashes, translate backslashes to slashes
+// The string to normalize is passed and returned in str
+//
+// killough 11/98: rewritten
+//
+// [STRIFE] - haleyjd 20110210: Borrowed from Eternity and adapted to respect 
+// the DIR_SEPARATOR define used by Choco Doom. This routine originated in
+// BOOM.
+//
+void M_NormalizeSlashes(char *str)
+{
+    char *p;
+   
+    // Convert all slashes/backslashes to DIR_SEPARATOR
+    for(p = str; *p; p++)
+    {
+        if((*p == '/' || *p == '\\') && *p != DIR_SEPARATOR)
+            *p = DIR_SEPARATOR;
+    }
+
+    // Remove trailing slashes
+    while(p > str && *--p == DIR_SEPARATOR)
+        *p = 0;
+
+    // Collapse multiple slashes
+    for(p = str; (*str++ = *p); )
+        if(*p++ == DIR_SEPARATOR)
+            while(*p == DIR_SEPARATOR)
+                p++;
+}
+
+//
+// M_SafeFilePath
+//
+// haleyjd 20110210 - original routine.
+// This routine performs safe, portable concatenation of a base file path
+// with another path component or file name. The returned string is Z_Malloc'd
+// and should be freed when it has exhausted its usefulness.
+//
+char *M_SafeFilePath(const char *basepath, const char *newcomponent)
+{
+    int   newstrlen = 0;
+    char *newstr = NULL;
+
+    if (!strcmp(basepath, ""))
+    {
+        basepath = ".";
+    }
+
+    // Always throw in a slash. M_NormalizeSlashes will remove it in the case
+    // that either basepath or newcomponent includes a redundant slash at the
+    // end or beginning respectively.
+    newstrlen = M_StringAlloc(&newstr, 3, 1, basepath, "/", newcomponent);
+    M_snprintf(newstr, newstrlen, "%s/%s", basepath, newcomponent);
+    M_NormalizeSlashes(newstr);
+
+    return newstr;
+}
+
+//
+// M_CreateSaveDirs
+//
+// haleyjd 20110210: Vanilla Strife went tits-up if it didn't have the full set
+// of save folders which were created externally by the installer. fraggle says
+// that's no good for Choco purposes, and I agree, so this routine will create
+// the full set of folders under the configured savegamedir.
+//
+void M_CreateSaveDirs(const char *savedir)
+{
+    int i;
+
+    for(i = 0; i < 7; i++)
+    {
+        char *compositedir;
+
+        // compose the full path by concatenating with savedir
+        compositedir = M_SafeFilePath(savedir, M_MakeStrifeSaveDir(i, ""));
+
+        M_MakeDirectory(compositedir);
+
+        Z_Free(compositedir);
+    }
+}
+
+//
+// M_MakeStrifeSaveDir
+//
+// haleyjd 20110211: Convenience routine
+//
+char *M_MakeStrifeSaveDir(int slotnum, const char *extra)
+{
+    static char tmpbuffer[32];
+
+    M_snprintf(tmpbuffer, sizeof(tmpbuffer),
+               "strfsav%d.ssg%s", slotnum, extra);
+
+    return tmpbuffer;
+}
+
+// 
+// M_GetFilePath
+//
+// 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;
+
+    M_StringCopy(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;
+}
+
+// EOF
+
+
--- a/src/strife/m_saves.h
+++ b/src/strife/m_saves.h
@@ -1,56 +1,56 @@
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 2010 James Haley, Samuel Villareal
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// DESCRIPTION:
-//
-// [STRIFE] New Module
-//
-// Strife Hub Saving Code
-//
-
-#ifndef M_SAVES_H__
-#define M_SAVES_H__
-
-#define CHARACTER_NAME_LEN 32
-
-extern char *savepath;
-extern char *savepathtemp;
-extern char *loadpath;
-extern char character_name[CHARACTER_NAME_LEN];
-
-// Strife Savegame Functions
-void ClearTmp(void);
-void ClearSlot(void);
-void FromCurr(void);
-void ToCurr(void);
-void M_SaveMoveMapToHere(void);
-void M_SaveMoveHereToMap(void);
-
-boolean M_SaveMisObj(const char *path);
-void    M_ReadMisObj(void);
-
-// Custom Utilities for Filepath Handling
-void *M_Calloc(size_t n1, size_t n2);
-void  M_NormalizeSlashes(char *str);
-int   M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...);
-char *M_SafeFilePath(const char *basepath, const char *newcomponent);
-char  M_GetFilePath(const char *fn, char *dest, size_t len);
-char *M_MakeStrifeSaveDir(int slotnum, const char *extra);
-void  M_CreateSaveDirs(const char *savedir);
-
-#endif
-
-// EOF
-
-
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2010 James Haley, Samuel Villareal
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// DESCRIPTION:
+//
+// [STRIFE] New Module
+//
+// Strife Hub Saving Code
+//
+
+#ifndef M_SAVES_H__
+#define M_SAVES_H__
+
+#define CHARACTER_NAME_LEN 32
+
+extern char *savepath;
+extern char *savepathtemp;
+extern char *loadpath;
+extern char character_name[CHARACTER_NAME_LEN];
+
+// Strife Savegame Functions
+void ClearTmp(void);
+void ClearSlot(void);
+void FromCurr(void);
+void ToCurr(void);
+void M_SaveMoveMapToHere(void);
+void M_SaveMoveHereToMap(void);
+
+boolean M_SaveMisObj(const char *path);
+void    M_ReadMisObj(void);
+
+// Custom Utilities for Filepath Handling
+void *M_Calloc(size_t n1, size_t n2);
+void  M_NormalizeSlashes(char *str);
+int   M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...);
+char *M_SafeFilePath(const char *basepath, const char *newcomponent);
+char  M_GetFilePath(const char *fn, char *dest, size_t len);
+char *M_MakeStrifeSaveDir(int slotnum, const char *extra);
+void  M_CreateSaveDirs(const char *savedir);
+
+#endif
+
+// EOF
+
+
--- a/src/strife/p_dialog.c
+++ b/src/strife/p_dialog.c
@@ -1,1413 +1,1413 @@
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 2010 James Haley, Samuel Villarreal
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// DESCRIPTION:
-//
-// [STRIFE] New Module
-//
-// Dialog Engine for Strife
-//
-
-#include <stdlib.h>
-
-#include "z_zone.h"
-#include "w_wad.h"
-#include "deh_str.h"
-#include "d_main.h"
-#include "d_mode.h"
-#include "d_player.h"
-#include "doomstat.h"
-#include "m_random.h"
-#include "m_menu.h"
-#include "m_misc.h"
-#include "r_main.h"
-#include "v_video.h"
-#include "p_local.h"
-#include "sounds.h"
-#include "p_dialog.h"
-#include "s_sound.h"
-#include "p_local.h"
-#include "p_inter.h"
-
-//
-// Defines and Macros
-//
-
-// haleyjd: size of the original Strife mapdialog_t structure.
-#define ORIG_MAPDIALOG_SIZE 0x5EC
-
-#define DIALOG_INT(field, ptr)    \
-    field = ((int)ptr[0]        | \
-            ((int)ptr[1] <<  8) | \
-            ((int)ptr[2] << 16) | \
-            ((int)ptr[3] << 24)); \
-    ptr += 4;
-
-#define DIALOG_STR(field, ptr, len) \
-    memcpy(field, ptr, len);        \
-    ptr += len;
-
-//
-// Globals
-//
-
-// This can be toggled at runtime to determine if the full dialog messages
-// are subtitled on screen or not. Defaults to off.
-int dialogshowtext = false;
-
-// The global mission objective buffer. This gets written to and read from file,
-// and is set by dialogs and line actions.
-char mission_objective[OBJECTIVE_LEN];
-
-//
-// Static Globals
-//
-
-// True if SCRIPT00 is loaded.
-static boolean script0loaded;
-
-// Number of dialogs defined in the current level's script.
-static int numleveldialogs;
-
-// The actual level dialogs. This didn't exist in Strife, but is new to account
-// for structure alignment/packing concerns, given that Chocolate Doom is
-// multiplatform.
-static mapdialog_t *leveldialogs;
-
-// The actual script00 dialogs. As above.
-static mapdialog_t *script0dialogs;
-
-// Number of dialogs defined in the SCRIPT00 lump.
-static int numscript0dialogs;
-
-// The player engaged in dialog. This is always player 1, though, since Rogue
-// never completed the ability to use dialog outside of single-player mode.
-static player_t *dialogplayer;
-
-// The object to which the player is speaking.
-static mobj_t   *dialogtalker;
-
-// The talker's current angle
-static angle_t dialogtalkerangle;
-
-// The currently active mapdialog object.
-static mapdialog_t *currentdialog;
-
-// Text at the end of the choices
-static char dialoglastmsgbuffer[48];
-
-// Item to display to player when picked up or recieved
-static char pickupstring[46];
-
-// Health based on gameskill given by the front's medic
-static const int healthamounts[] = { -100 , -75, -50, -50, -100 };
-
-//=============================================================================
-//
-// Dialog State Sets
-//
-// These are used to animate certain actors in response to what happens in
-// their dialog sequences.
-//
-
-typedef struct dialogstateset_s
-{
-    mobjtype_t type;  // the type of object
-    statenum_t greet; // greeting state, for start of dialog
-    statenum_t yes;   // "yes" state, for an affirmative response
-    statenum_t no;    // "no" state, when you don't have the right items
-} dialogstateset_t;
-
-static dialogstateset_t dialogstatesets[] =
-{
-    { MT_PLAYER,       S_NULL,    S_NULL,    S_NULL    },
-    { MT_SHOPKEEPER_W, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
-    { MT_SHOPKEEPER_B, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
-    { MT_SHOPKEEPER_A, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
-    { MT_SHOPKEEPER_M, S_MRGT_00, S_MRYS_00, S_MRNO_00 }
-};
-
-// Rogue stored this in a static global rather than making it a define...
-static int numdialogstatesets = arrlen(dialogstatesets);
-
-// Current dialog talker state
-static dialogstateset_t *dialogtalkerstates;
-
-//=============================================================================
-//
-// Random Messages
-//
-// Rogue hard-coded these so they wouldn't have to repeat them several times
-// in the SCRIPT00 lump, apparently.
-//
-
-#define MAXRNDMESSAGES 10
-
-typedef struct rndmessage_s
-{
-    const char *type_name;
-    int nummessages;
-    char *messages[MAXRNDMESSAGES];
-} rndmessage_t;
-
-static rndmessage_t rndMessages[] = 
-{
-    // Peasants
-    {
-        "PEASANT",
-        10,
-        {
-            "PLEASE DON'T HURT ME.",
-            
-            "IF YOU'RE LOOKING TO HURT ME, I'M \n"
-            "NOT REALLY WORTH THE EFFORT.",
-            
-            "I DON'T KNOW ANYTHING.",
-            
-            "GO AWAY OR I'LL CALL THE GUARDS!",
-            
-            "I WISH SOMETIMES THAT ALL THESE \n"
-            "REBELS WOULD JUST LEARN THEIR \n"
-            "PLACE AND STOP THIS NONSENSE.",
-
-            "JUST LEAVE ME ALONE, OK?",
-
-            "I'M NOT SURE, BUT SOMETIMES I THINK \n"
-            "THAT I KNOW SOME OF THE ACOLYTES.",
-
-            "THE ORDER'S GOT EVERYTHING AROUND HERE PRETTY WELL LOCKED UP TIGHT.",
-
-            "THERE'S NO WAY THAT THIS IS JUST A \n"
-            "SECURITY FORCE.",
-
-            "I'VE HEARD THAT THE ORDER IS REALLY \n"
-            "NERVOUS ABOUT THE FRONT'S \n"
-            "ACTIONS AROUND HERE."
-        }
-    },
-    // Rebel
-    {
-        "REBEL",
-        10,
-        {
-            "THERE'S NO WAY THE ORDER WILL \n"
-            "STAND AGAINST US.",
-
-            "WE'RE ALMOST READY TO STRIKE. \n"
-            "MACIL'S PLANS ARE FALLING IN PLACE.",
-
-            "WE'RE ALL BEHIND YOU, DON'T WORRY.",
-
-            "DON'T GET TOO CLOSE TO ANY OF THOSE BIG ROBOTS. THEY'LL MELT YOU DOWN \n"
-            "FOR SCRAP!",
-
-            "THE DAY OF OUR GLORY WILL SOON \n"
-            "COME, AND THOSE WHO OPPOSE US WILL \n"
-            "BE CRUSHED!",
-
-            "DON'T GET TOO COMFORTABLE. WE'VE \n"
-            "STILL GOT OUR WORK CUT OUT FOR US.",
-
-            "MACIL SAYS THAT YOU'RE THE NEW \n"
-            "HOPE. BEAR THAT IN MIND.",
-
-            "ONCE WE'VE TAKEN THESE CHARLATANS DOWN, WE'LL BE ABLE TO REBUILD THIS "
-            "WORLD AS IT SHOULD BE.",
-
-            "REMEMBER THAT YOU AREN'T FIGHTING \n"
-            "JUST FOR YOURSELF, BUT FOR \n"
-            "EVERYONE HERE AND OUTSIDE.",
-
-            "AS LONG AS ONE OF US STILL STANDS, \n"
-            "WE WILL WIN."
-        }
-    },
-    // Acolyte
-    {
-        "AGUARD",
-        10,
-        {
-            "MOVE ALONG,  PEASANT.",
-
-            "FOLLOW THE TRUE FAITH, ONLY THEN \n"
-            "WILL YOU BEGIN TO UNDERSTAND.",
-
-            "ONLY THROUGH DEATH CAN ONE BE \n"
-            "TRULY REBORN.",
-
-            "I'M NOT INTERESTED IN YOUR USELESS \n"
-            "DRIVEL.",
-
-            "IF I HAD WANTED TO TALK TO YOU I \n"
-            "WOULD HAVE TOLD YOU SO.",
-
-            "GO AND ANNOY SOMEONE ELSE!",
-
-            "KEEP MOVING!",
-
-            "IF THE ALARM GOES OFF, JUST STAY OUT OF OUR WAY!",
-
-            "THE ORDER WILL CLEANSE THE WORLD \n"
-            "AND USHER IT INTO THE NEW ERA.",
-
-            "PROBLEM?  NO, I THOUGHT NOT.",
-        }
-    },
-    // Beggar
-    {
-        "BEGGAR",
-        10,
-        {
-            "ALMS FOR THE POOR?",
-
-            "WHAT ARE YOU LOOKING AT, SURFACER?",
-
-            "YOU WOULDN'T HAVE ANY EXTRA FOOD, WOULD YOU?",
-
-            "YOU  SURFACE PEOPLE WILL NEVER \n"
-            "                                                                 "
-            "                                      UNDERSTAND US.",
-
-            "HA, THE GUARDS CAN'T FIND US.  THOSE \n"
-            "IDIOTS DON'T EVEN KNOW WE EXIST.",
-
-            "ONE DAY EVERYONE BUT THOSE WHO SERVE THE ORDER WILL BE FORCED TO "
-            "  JOIN US.",
-
-            "STARE NOW,  BUT YOU KNOW THAT THIS WILL BE YOUR OWN FACE ONE DAY.",
-
-            // Note: "NOTHING THING" is an authentic typo
-            "THERE'S NOTHING THING MORE \n"
-            "ANNOYING THAN A SURFACER WITH AN ATTITUDE!",
-
-            "THE ORDER WILL MAKE SHORT WORK OF YOUR PATHETIC FRONT.",
-
-            "WATCH YOURSELF SURFACER. WE KNOW OUR ENEMIES!"
-        }
-    },
-    // Templar
-    {
-        "PGUARD",
-        10,
-        {
-            "WE ARE THE HANDS OF FATE. TO EARN \n"
-            "OUR WRATH IS TO FIND OBLIVION!",
-
-            "THE ORDER WILL CLEANSE THE WORLD \n"
-            "OF THE WEAK AND CORRUPT!",
-
-            "OBEY THE WILL OF THE MASTERS!",
-
-            "LONG LIFE TO THE BROTHERS OF THE \n"
-            "ORDER!",
-
-            "FREE WILL IS AN ILLUSION THAT BINDS \n"
-            "THE WEAK MINDED.",
-
-            "POWER IS THE PATH TO GLORY. TO \n"
-            "FOLLOW THE ORDER IS TO WALK THAT \n"
-            "PATH!",
-
-            "TAKE YOUR PLACE AMONG THE \n"
-            "RIGHTEOUS, JOIN US!",
-
-            "THE ORDER PROTECTS ITS OWN.",
-
-            "ACOLYTES?  THEY HAVE YET TO SEE THE FULL GLORY OF THE ORDER.",
-
-            "IF THERE IS ANY HONOR INSIDE THAT \n"
-            "PATHETIC SHELL OF A BODY, \n"
-            "YOU'LL ENTER INTO THE ARMS OF THE \n"
-            "ORDER."
-        }
-    }
-};
-
-// And again, this could have been a define, but was a variable.
-static int numrndmessages = arrlen(rndMessages);
-
-//=============================================================================
-//
-// Dialog Menu Structure
-//
-// The Strife dialog system is actually just a serious abuse of the DOOM menu
-// engine. Hence why it doesn't work in multiplayer games or during demo
-// recording.
-//
-
-#define NUMDIALOGMENUITEMS 6
-
-static void P_DialogDrawer(void);
-
-static menuitem_t dialogmenuitems[] =
-{
-    { 1, "", P_DialogDoChoice, '1' }, // These items are loaded dynamically
-    { 1, "", P_DialogDoChoice, '2' },
-    { 1, "", P_DialogDoChoice, '3' },
-    { 1, "", P_DialogDoChoice, '4' },
-    { 1, "", P_DialogDoChoice, '5' },
-    { 1, "", P_DialogDoChoice, '6' }  // Item 6 is always the dismissal item
-};
-
-static menu_t dialogmenu =
-{
-    NUMDIALOGMENUITEMS, 
-    NULL, 
-    dialogmenuitems, 
-    P_DialogDrawer, 
-    42, 
-    75, 
-    0
-};
-
-// Lump number of the dialog background picture, if any.
-static int dialogbgpiclumpnum;
-
-// Name of current speaking character.
-static char *dialogname;
-
-// Current dialog text.
-static const char *dialogtext;
-
-//=============================================================================
-//
-// Routines
-//
-
-//
-// P_ParseDialogLump
-//
-// haleyjd 09/02/10: This is an original function added to parse out the 
-// dialogs from the dialog lump rather than reading them raw from the lump 
-// pointer. This avoids problems with structure packing.
-//
-static void P_ParseDialogLump(byte *lump, mapdialog_t **dialogs, 
-                              int numdialogs, int tag)
-{
-    int i;
-    byte *rover = lump;
-
-    *dialogs = Z_Malloc(numdialogs * sizeof(mapdialog_t), tag, NULL);
-
-    for(i = 0; i < numdialogs; i++)
-    {
-        int j;
-        mapdialog_t *curdialog = &((*dialogs)[i]);
-
-        DIALOG_INT(curdialog->speakerid,    rover);
-        DIALOG_INT(curdialog->dropitem,     rover);
-        DIALOG_INT(curdialog->checkitem[0], rover);
-        DIALOG_INT(curdialog->checkitem[1], rover);
-        DIALOG_INT(curdialog->checkitem[2], rover);
-        DIALOG_INT(curdialog->jumptoconv,   rover);
-        DIALOG_STR(curdialog->name,         rover, MDLG_NAMELEN);
-        DIALOG_STR(curdialog->voice,        rover, MDLG_LUMPLEN);
-        DIALOG_STR(curdialog->backpic,      rover, MDLG_LUMPLEN);
-        DIALOG_STR(curdialog->text,         rover, MDLG_TEXTLEN);
-
-        // copy choices
-        for(j = 0; j < 5; j++)
-        {
-            mapdlgchoice_t *curchoice = &(curdialog->choices[j]);
-            DIALOG_INT(curchoice->giveitem,         rover);
-            DIALOG_INT(curchoice->needitems[0],     rover);
-            DIALOG_INT(curchoice->needitems[1],     rover);
-            DIALOG_INT(curchoice->needitems[2],     rover);
-            DIALOG_INT(curchoice->needamounts[0],   rover);
-            DIALOG_INT(curchoice->needamounts[1],   rover);
-            DIALOG_INT(curchoice->needamounts[2],   rover);
-            DIALOG_STR(curchoice->text,             rover, MDLG_CHOICELEN);
-            DIALOG_STR(curchoice->textok,           rover, MDLG_MSGLEN);
-            DIALOG_INT(curchoice->next,             rover);
-            DIALOG_INT(curchoice->objective,        rover);
-            DIALOG_STR(curchoice->textno,           rover, MDLG_MSGLEN);
-        }
-    }
-}
-
-//
-// P_DialogLoad
-//
-// [STRIFE] New function
-// haleyjd 09/02/10: Loads the dialog script for the current map. Also loads 
-// SCRIPT00 if it has not yet been loaded.
-//
-void P_DialogLoad(void)
-{
-    char lumpname[9];
-    int  lumpnum;
-
-    // load the SCRIPTxy lump corresponding to MAPxy, if it exists.
-    DEH_snprintf(lumpname, sizeof(lumpname), "script%02d", gamemap);
-    if((lumpnum = W_CheckNumForName(lumpname)) == -1)
-        numleveldialogs = 0;
-    else
-    {
-        byte *leveldialogptr = W_CacheLumpNum(lumpnum, PU_STATIC);
-        numleveldialogs = W_LumpLength(lumpnum) / ORIG_MAPDIALOG_SIZE;
-        P_ParseDialogLump(leveldialogptr, &leveldialogs, numleveldialogs, 
-                          PU_LEVEL);
-        Z_Free(leveldialogptr); // haleyjd: free the original lump
-    }
-
-    // also load SCRIPT00 if it has not been loaded yet
-    if(!script0loaded)
-    {
-        byte *script0ptr;
-
-        script0loaded = true; 
-        // BUG: Rogue should have used W_GetNumForName here...
-        lumpnum = W_CheckNumForName(DEH_String("script00")); 
-        script0ptr = W_CacheLumpNum(lumpnum, PU_STATIC);
-        numscript0dialogs = W_LumpLength(lumpnum) / ORIG_MAPDIALOG_SIZE;
-        P_ParseDialogLump(script0ptr, &script0dialogs, numscript0dialogs,
-                          PU_STATIC);
-        Z_Free(script0ptr); // haleyjd: free the original lump
-    }
-}
-
-//
-// P_PlayerHasItem
-//
-// [STRIFE] New function
-// haleyjd 09/02/10: Checks for inventory items, quest flags, etc. for dialogs.
-// Returns the amount possessed, or 0 if none.
-//
-int P_PlayerHasItem(player_t *player, mobjtype_t type)
-{
-    int i;
-
-    if(type > 0)
-    {
-        // check keys
-        if(type >= MT_KEY_BASE && type < MT_INV_SHADOWARMOR)
-            return (player->cards[type - MT_KEY_BASE]);
-
-        // check sigil pieces
-        if(type >= MT_SIGIL_A && type <= MT_SIGIL_E)
-            return (type - MT_SIGIL_A <= player->sigiltype);
-
-        // check quest tokens
-        if(type >= MT_TOKEN_QUEST1 && type <= MT_TOKEN_QUEST31)
-            return (player->questflags & (1 << (type - MT_TOKEN_QUEST1)));
-
-        // check inventory
-        for(i = 0; i < 32; i++)
-        {
-            if(type == player->inventory[i].type)
-                return player->inventory[i].amount;
-        }
-    }
-    return 0;
-}
-
-//
-// P_DialogFind
-//
-// [STRIFE] New function
-// haleyjd 09/03/10: Looks for a dialog definition matching the given 
-// Script ID # for an mobj.
-//
-mapdialog_t *P_DialogFind(mobjtype_t type, int jumptoconv)
-{
-    int i;
-
-    // check the map-specific dialogs first
-    for(i = 0; i < numleveldialogs; i++)
-    {
-        if(type == leveldialogs[i].speakerid)
-        {
-            if(jumptoconv <= 1)
-                return &leveldialogs[i];
-            else
-                --jumptoconv;
-        }
-    }
-
-    // check SCRIPT00 dialogs next
-    for(i = 0; i < numscript0dialogs; i++)
-    {
-        if(type == script0dialogs[i].speakerid)
-            return &script0dialogs[i];
-    }
-
-    // the default dialog is script 0 in the SCRIPT00 lump.
-    return &script0dialogs[0];
-}
-
-//
-// P_DialogGetStates
-//
-// [STRIFE] New function
-// haleyjd 09/03/10: Find the set of special dialog states (greetings, yes, no)
-// for a particular thing type.
-//
-static dialogstateset_t *P_DialogGetStates(mobjtype_t type)
-{
-    int i;
-
-    // look for a match by type
-    for(i = 0; i < numdialogstatesets; i++)
-    {
-        if(type == dialogstatesets[i].type)
-            return &dialogstatesets[i];
-    }
-
-    // return the default 0 record if no match.
-    return &dialogstatesets[0];
-}
-
-//
-// P_DialogGetMsg
-//
-// [STRIFE] New function
-// haleyjd 09/03/10: Redirects dialog messages when the script indicates that
-// the actor should use a random message stored in the executable instead.
-//
-static const char *P_DialogGetMsg(const char *message)
-{
-    // if the message starts with "RANDOM"...
-    if(!strncasecmp(message, DEH_String("RANDOM"), 6))
-    {
-        int i;
-        const char *nameloc = message + 7;
-
-        // look for a match in rndMessages for the string starting 
-        // 7 chars after "RANDOM_"
-        for(i = 0; i < numrndmessages; i++)
-        {
-            if(!strncasecmp(nameloc, rndMessages[i].type_name, 4))
-            {
-                // found a match, so return a random message
-                int rnd = M_Random();
-                int nummessages = rndMessages[i].nummessages;
-                return DEH_String(rndMessages[i].messages[rnd % nummessages]);
-            }
-        }
-    }
-
-    // otherwise, just return the message passed in.
-    return message;
-}
-
-//
-// P_GiveInventoryItem
-//
-// [STRIFE] New function
-// haleyjd 09/03/10: Give an inventory item to the player, if possible.
-// villsa 09/09/10: Fleshed out routine
-//
-boolean P_GiveInventoryItem(player_t *player, int sprnum, mobjtype_t type)
-{
-    int curinv = 0;
-    int i;
-    boolean ok = false;
-    mobjtype_t item = 0;
-    inventory_t* invtail;
-
-    // repaint the status bar due to inventory changing
-    player->st_update = true;
-
-    while(1)
-    {
-        // inventory is full
-        if(curinv > player->numinventory)
-            return true;
-
-        item = player->inventory[curinv].type;
-        if(type < item)
-        {
-            if(curinv != MAXINVENTORYSLOTS)
-            {
-                // villsa - sort inventory item if needed
-                invtail = &player->inventory[player->numinventory - 1];
-                if(player->numinventory >= (curinv + 1))
-                {
-                    for(i = player->numinventory; i >= (curinv + 1); --i)    
-                    {
-                        invtail[1].sprite   = invtail[0].sprite;
-                        invtail[1].type     = invtail[0].type;
-                        invtail[1].amount   = invtail[0].amount;
-
-                        invtail--;
-                    }
-                }
-
-                // villsa - add inventory item
-                player->inventory[curinv].amount = 1;
-                player->inventory[curinv].sprite = sprnum;
-                player->inventory[curinv].type = type;
-
-                // sort cursor if needed
-                if(player->numinventory)
-                {
-                    if(curinv <= player->inventorycursor)
-                        player->inventorycursor++;
-                }
-
-                player->numinventory++;
-
-                return true;
-            }
-
-            return false;
-        }
-
-        if(type == item)
-            break;
-
-        curinv++;
-    }
-
-    // check amount of inventory item by using the mass from mobjinfo
-    if(player->inventory[curinv].amount < mobjinfo[item].mass)
-    {
-        player->inventory[curinv].amount++;
-        ok = true;
-    }
-    else
-        ok = false;
-
-    return ok;
-}
-
-//
-// P_GiveItemToPlayer
-//
-// [STRIFE] New function
-// haleyjd 09/03/10: Sorts out how to give something to the player.
-// Not strictly just for inventory items.
-// villsa 09/09/10: Fleshed out function
-//
-boolean P_GiveItemToPlayer(player_t *player, int sprnum, mobjtype_t type)
-{
-    int i = 0;
-    line_t junk;
-    int sound = sfx_itemup; // haleyjd 09/21/10: different sounds for items
-
-    // set quest if mf_givequest flag is set
-    if(mobjinfo[type].flags & MF_GIVEQUEST)
-        player->questflags |= 1 << (mobjinfo[type].speed - 1);
-
-    // check for keys
-    if(type >= MT_KEY_BASE && type <= MT_NEWKEY5)
-    {
-        P_GiveCard(player, type - MT_KEY_BASE);
-        return true;
-    }
-
-    // check for quest tokens
-    if(type >= MT_TOKEN_QUEST1 && type <= MT_TOKEN_QUEST31)
-    {
-        if(mobjinfo[type].name)
-        {
-            M_StringCopy(pickupstring, DEH_String(mobjinfo[type].name), 39);
-            player->message = pickupstring;
-        }
-        player->questflags |= 1 << (type - MT_TOKEN_QUEST1);
-
-        if(player == &players[consoleplayer])
-            S_StartSound(NULL, sound);
-        return true;
-    }
-
-    // haleyjd 09/22/10: Refactored to give sprites higher priority than
-    // mobjtypes and to implement missing logic.
-    switch(sprnum)
-    {
-    case SPR_HELT: // This is given only by the "DONNYTRUMP" cheat (aka Midas)
-        P_GiveInventoryItem(player, SPR_HELT, MT_TOKEN_TOUGHNESS);
-        P_GiveInventoryItem(player, SPR_GUNT, MT_TOKEN_ACCURACY);
-
-        // [STRIFE] Bizarre...
-        for(i = 0; i < 5 * player->accuracy + 300; i++)
-            P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
-        break;
-
-    case SPR_ARM1: // Armor 1
-        if(!P_GiveArmor(player, -2))
-            P_GiveInventoryItem(player, sprnum, type);
-        break;
-
-    case SPR_ARM2: // Armor 2
-        if(!P_GiveArmor(player, -1))
-            P_GiveInventoryItem(player, sprnum, type);
-        break;
-
-    case SPR_COIN: // 1 Gold
-        P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
-        break;
-
-    case SPR_CRED: // 10 Gold
-        for(i = 0; i < 10; i++)
-            P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
-        break;
-
-    case SPR_SACK: // 25 gold
-        for(i = 0; i < 25; i++)
-            P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
-        break;
-
-    case SPR_CHST: // 50 gold
-        for(i = 0; i < 50; i++)
-            P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
-        break; // haleyjd 20141215: missing break, caused Rowan to not take ring from you.
-
-    case SPR_BBOX: // Box of Bullets
-        if(!P_GiveAmmo(player, am_bullets, 5))
-            return false;
-        break;
-
-    case SPR_BLIT: // Bullet Clip
-        if(!P_GiveAmmo(player, am_bullets, 1))
-            return false;
-        break;
-
-    case SPR_PMAP: // Map powerup
-        if(!P_GivePower(player, pw_allmap))
-            return false;
-        sound = sfx_yeah; // bluh-doop!
-        break;
-
-    case SPR_COMM: // Communicator
-        if(!P_GivePower(player, pw_communicator))
-            return false;
-        sound = sfx_yeah; // bluh-doop!
-        break;
-
-    case SPR_MSSL: // Mini-missile
-        if(!P_GiveAmmo(player, am_missiles, 1))
-            return false;
-        break;
-
-    case SPR_ROKT: // Crate of missiles
-        if(!P_GiveAmmo(player, am_missiles, 5))
-            return false;
-        break;
-
-    case SPR_BRY1: // Battery cell
-        if(!P_GiveAmmo(player, am_cell, 1))
-            return false;
-        break;
-
-    case SPR_CPAC: // Cell pack
-        if(!P_GiveAmmo(player, am_cell, 5))
-            return false;
-        break;
-
-    case SPR_PQRL: // Poison bolts
-        if(!P_GiveAmmo(player, am_poisonbolts, 5))
-            return false;
-        break;
-
-    case SPR_XQRL: // Electric bolts
-        if(!P_GiveAmmo(player, am_elecbolts, 5))
-            return false;
-        break;
-
-    case SPR_GRN1: // HE Grenades
-        if(!P_GiveAmmo(player, am_hegrenades, 1))
-            return false;
-        break;
-
-    case SPR_GRN2: // WP Grenades
-        if(!P_GiveAmmo(player, am_wpgrenades, 1))
-            return false;
-        break;
-
-    case SPR_BKPK: // Backpack (aka Ammo Satchel)
-        if(!player->backpack)
-        {
-            for(i = 0; i < NUMAMMO; i++)
-                player->maxammo[i] *= 2;
-
-            player->backpack = true;
-        }
-        for(i = 0; i < NUMAMMO; i++)
-            P_GiveAmmo(player, i, 1);
-        break;
-
-    case SPR_RIFL: // Assault Rifle
-        if(player->weaponowned[wp_rifle])
-            return false;
-
-        if(!P_GiveWeapon(player, wp_rifle, false))
-            return false;
-        
-        sound = sfx_wpnup; // SHK-CHK!
-        break;
-
-    case SPR_FLAM: // Flamethrower
-        if(player->weaponowned[wp_flame])
-            return false;
-
-        if(!P_GiveWeapon(player, wp_flame, false))
-            return false;
-
-        sound = sfx_wpnup; // SHK-CHK!
-        break;
-
-    case SPR_MMSL: // Mini-missile Launcher
-        if(player->weaponowned[wp_missile])
-            return false;
-
-        if(!P_GiveWeapon(player, wp_missile, false))
-            return false;
-
-        sound = sfx_wpnup; // SHK-CHK!
-        break;
-
-    case SPR_TRPD: // Mauler
-        if(player->weaponowned[wp_mauler])
-            return false;
-
-        if(!P_GiveWeapon(player, wp_mauler, false))
-            return false;
-
-        sound = sfx_wpnup; // SHK-CHK!
-        break;
-
-    case SPR_CBOW: // Here's a crossbow. Just aim straight, and *SPLAT!*
-        if(player->weaponowned[wp_elecbow])
-            return false;
-
-        if(!P_GiveWeapon(player, wp_elecbow, false))
-            return false;
-
-        sound = sfx_wpnup; // SHK-CHK!
-        break;
-
-    case SPR_TOKN: // Miscellaneous items - These are determined by thingtype.
-        switch(type)
-        {
-        case MT_KEY_HAND: // Severed hand
-            P_GiveCard(player, key_SeveredHand);
-            break;
-
-        case MT_MONY_300: // 300 Gold (this is the only way to get it, in fact)
-            for(i = 0; i < 300; i++)
-                P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
-            break;
-
-        case MT_TOKEN_AMMO: // Ammo token - you get this from the Weapons Trainer
-            if(player->ammo[am_bullets] >= 50)
-                return false;
-
-            player->ammo[am_bullets] = 50;
-            break;
-
-        case MT_TOKEN_HEALTH: // Health token - from the Front's doctor
-            if(!P_GiveBody(player, healthamounts[gameskill]))
-                return false;
-            break;
-
-        case MT_TOKEN_ALARM: // Alarm token - particularly from the Oracle.
-            P_NoiseAlert(player->mo, player->mo);
-            A_AlertSpectreC(dialogtalker); // BUG: assumes in a dialog o_O
-            break;
-
-        case MT_TOKEN_DOOR1: // Door special 1
-            junk.tag = 222;
-            EV_DoDoor(&junk, vld_open);
-            break;
-
-        case MT_TOKEN_PRISON_PASS: // Door special 1 - Prison pass
-            junk.tag = 223;
-            EV_DoDoor(&junk, vld_open);
-            if(gamemap == 2) // If on Tarnhill, give Prison pass object
-                P_GiveInventoryItem(player, sprnum, type);
-            break;
-
-        case MT_TOKEN_SHOPCLOSE: // Door special 3 - "Shop close" - unused?
-            junk.tag = 222;
-            EV_DoDoor(&junk, vld_close);
-            break;
-
-        case MT_TOKEN_DOOR3: // Door special 4 (or 3? :P ) 
-            junk.tag = 224;
-            EV_DoDoor(&junk, vld_close);
-            break;
-
-        case MT_TOKEN_STAMINA: // Stamina upgrade
-            if(player->stamina >= 100)
-                return false;
-
-            player->stamina += 10;
-            P_GiveBody(player, 200); // full healing
-            break;
-
-        case MT_TOKEN_NEW_ACCURACY: // Accuracy upgrade
-            if(player->accuracy >= 100)
-                return false;
-
-            player->accuracy += 10;
-            break;
-
-        case MT_SLIDESHOW: // Slideshow (start a finale)
-            gameaction = ga_victory;
-            if(gamemap == 10)
-                P_GiveItemToPlayer(player, SPR_TOKN, MT_TOKEN_QUEST17);
-            break;
-        
-        default: // The default is to just give it as an inventory item.
-            P_GiveInventoryItem(player, sprnum, type);
-            break;
-        }
-        break;
-
-    default: // The ultimate default: Give it as an inventory item.
-        if(!P_GiveInventoryItem(player, sprnum, type))
-            return false;
-        break;
-    }
-
-    // Play sound.
-    if(player == &players[consoleplayer])
-        S_StartSound(NULL, sound);
-
-    return true;
-}
-
-//
-// P_TakeDialogItem
-//
-// [STRIFE] New function
-// haleyjd 09/03/10: Removes needed items from the player's inventory.
-//
-static void P_TakeDialogItem(player_t *player, int type, int amount)
-{
-    int i;
-
-    if(amount <= 0)
-        return;
-
-    for(i = 0; i < player->numinventory; i++)
-    {
-        // find a matching item
-        if(type != player->inventory[i].type)
-            continue;
-
-        // if there is none left...
-        if((player->inventory[i].amount -= amount) < 1)
-        {
-            // ...shift everything above it down
-            int j;
-
-            // BUG: They should have stopped at j < numinventory. This
-            // seems to implicitly assume that numinventory is always at
-            // least one less than the max # of slots, otherwise it 
-            // pulls in data from the following player_t fields:
-            // st_update, numinventory, inventorycursor, accuracy, stamina
-            for(j = i + 1; j <= player->numinventory; j++)
-            {
-                inventory_t *item1 = &(player->inventory[j - 1]);
-                inventory_t *item2 = &(player->inventory[j]);
-
-                *item1 = *item2;
-            }
-
-            // blank the topmost slot
-            // BUG: This will overwrite the aforementioned fields if
-            // numinventory is equal to the number of slots!
-            // STRIFE-TODO: Overflow emulation?
-            player->inventory[player->numinventory].type = NUMMOBJTYPES;
-            player->inventory[player->numinventory].sprite = -1;
-            player->numinventory--;
-
-            // update cursor position
-            if(player->inventorycursor >= player->numinventory)
-            {
-                if(player->inventorycursor)
-                    player->inventorycursor--;
-            }
-        } // end if
-        
-        return; // done!
-
-    } // end for
-}
-
-//
-// P_DialogDrawer
-//
-// This function is set as the drawer callback for the dialog menu.
-//
-static void P_DialogDrawer(void)
-{
-    angle_t angle;
-    int y;
-    int i;
-    int height;
-    int finaly;
-    char choicetext[64];
-    char choicetext2[64];
-
-    // Run down bonuscount faster than usual so that flashes from being given
-    // items are less obvious.
-    if(dialogplayer->bonuscount)
-    {
-        dialogplayer->bonuscount -= 3;
-        if(dialogplayer->bonuscount < 0)
-            dialogplayer->bonuscount = 0;
-    }
-
-    angle = R_PointToAngle2(dialogplayer->mo->x,
-                            dialogplayer->mo->y,
-                            dialogtalker->x,
-                            dialogtalker->y);
-    angle -= dialogplayer->mo->angle;
-
-    // Dismiss the dialog if the player is out of alignment, or the thing he was
-    // talking to is now engaged in battle.
-    if ((angle > ANG45 && angle < (ANG270+ANG45))
-     || (dialogtalker->flags & MF_NODIALOG) != 0)
-    {
-        P_DialogDoChoice(dialogmenu.numitems - 1);
-    }
-
-    dialogtalker->reactiontime = 2;
-
-    // draw background
-    if(dialogbgpiclumpnum != -1)
-    {
-        patch_t *patch = W_CacheLumpNum(dialogbgpiclumpnum, PU_CACHE);
-        V_DrawPatchDirect(0, 0, patch);
-    }
-
-    // if there's a valid background pic, delay drawing the rest of the menu 
-    // for a while; otherwise, it will appear immediately
-    if(dialogbgpiclumpnum == -1 || menupausetime <= gametic)
-    {
-        if(menuindialog)
-        {
-            // time to pause the game?
-            if(menupausetime + 3 < gametic)
-                menupause = true;
-        }
-
-        // draw character name
-        M_WriteText(12, 18, dialogname);
-        y = 28;
-
-        // show text (optional for dialogs with voices)
-        if(dialogshowtext || currentdialog->voice[0] == '\0')
-            y = M_WriteText(20, 28, dialogtext);
-
-        height = 20 * dialogmenu.numitems;
-
-        finaly = 175 - height;     // preferred height
-        if(y > finaly)
-            finaly = 199 - height; // height it will bump down to if necessary.
-
-        // draw divider
-        M_WriteText(42, finaly - 6, DEH_String("______________________________"));
-
-        dialogmenu.y = finaly + 6;
-        y = 0;
-
-        // draw the menu items
-        for(i = 0; i < dialogmenu.numitems - 1; i++)
-        {
-            DEH_snprintf(choicetext, sizeof(choicetext),
-                         "%d) %s", i + 1, currentdialog->choices[i].text);
-            
-            // alternate text for items that need money
-            if(currentdialog->choices[i].needamounts[0] > 0)
-            {
-                // haleyjd 20120401: necessary to avoid undefined behavior:
-                M_StringCopy(choicetext2, choicetext, sizeof(choicetext2));
-                DEH_snprintf(choicetext, sizeof(choicetext),
-                             "%s for %d", choicetext2,
-                             currentdialog->choices[i].needamounts[0]);
-            }
-
-            M_WriteText(dialogmenu.x, dialogmenu.y + 3 + y, choicetext);
-            y += 19;
-        }
-
-        // draw the final item for dismissing the dialog
-        M_WriteText(dialogmenu.x, 19 * i + dialogmenu.y + 3, dialoglastmsgbuffer);
-    }
-}
-
-//
-// P_DialogDoChoice
-//
-// [STRIFE] New function
-// haleyjd 09/05/10: Handles making a choice in a dialog. Installed as the
-// callback for all items in the dialogmenu structure.
-//
-void P_DialogDoChoice(int choice)
-{
-    int i = 0, nextdialog = 0;
-    boolean candochoice = true;
-    char *message = NULL;
-    mapdlgchoice_t *currentchoice;
-
-    if(choice == -1)
-        choice = dialogmenu.numitems - 1;
-
-    currentchoice = &(currentdialog->choices[choice]);
-
-    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++)
-    {
-        if(P_PlayerHasItem(dialogplayer, currentchoice->needitems[i]) <
-                                         currentchoice->needamounts[i])
-        {
-            candochoice = false; // nope, missing something
-        }
-    }
-
-    if(choice != dialogmenu.numitems - 1 && candochoice)
-    {
-        int item;
-
-        message = currentchoice->textok;
-        if(dialogtalkerstates->yes)
-            P_SetMobjState(dialogtalker, dialogtalkerstates->yes);
-
-        item = currentchoice->giveitem;
-        if(item < 0 || 
-           P_GiveItemToPlayer(dialogplayer, 
-                              states[mobjinfo[item].spawnstate].sprite, 
-                              item))
-        {
-            // if successful, take needed items
-            int count = 0;
-            // villsa 09/08/10: converted into for loop
-            for(count = 0; count < MDLG_MAXITEMS; count++)
-            {
-                P_TakeDialogItem(dialogplayer, 
-                                 currentchoice->needitems[count],
-                                 currentchoice->needamounts[count]);
-            }
-        }
-        else
-            message = DEH_String("You seem to have enough!");
-
-        // store next dialog into the talking actor
-        nextdialog = currentchoice->next;
-        if(nextdialog != 0)
-            dialogtalker->miscdata = (byte)(abs(nextdialog));
-    }
-    else
-    {
-        // not successful
-        message = currentchoice->textno;
-        if(dialogtalkerstates->no)
-            P_SetMobjState(dialogtalker, dialogtalkerstates->no);
-    }
-    
-    if(choice != dialogmenu.numitems - 1)
-    {
-        int objective;
-        char *objlump;
-
-        if((objective = currentchoice->objective))
-        {
-            DEH_snprintf(mission_objective, OBJECTIVE_LEN, "log%i", objective);
-            objlump = W_CacheLumpName(mission_objective, PU_CACHE);
-            M_StringCopy(mission_objective, objlump, OBJECTIVE_LEN);
-        }
-        // haleyjd 20130301: v1.31 hack: if first char of message is a period,
-        // clear the player's message. Is this actually used anywhere?
-        if(gameversion == exe_strife_1_31 && message[0] == '.')
-            message = NULL;
-        dialogplayer->message = message;
-    }
-
-    dialogtalker->angle = dialogtalkerangle;
-    dialogplayer->st_update = true;
-    M_ClearMenus(0);
-
-    if(nextdialog >= 0 || gameaction == ga_victory) // Macil hack
-        menuindialog = false;
-    else
-        P_DialogStart(dialogplayer);
-}
-
-//
-// P_DialogStartP1
-//
-// [STRIFE] New function
-// haleyjd 09/13/10: This is a hack used by the finale system.
-//
-void P_DialogStartP1(void)
-{
-    P_DialogStart(&players[0]);
-}
-
-//
-// P_DialogStart
-//
-// villsa [STRIFE] New function
-//
-void P_DialogStart(player_t *player)
-{
-    int i = 0;
-    int pic;
-    int rnd = 0;
-    char* byetext;
-    int jumptoconv;
-
-    if(menuactive || netgame)
-        return;
-
-    // are we facing towards our NPC?
-    P_AimLineAttack(player->mo, player->mo->angle, (128*FRACUNIT));
-    if(!linetarget)
-    {
-        P_AimLineAttack(player->mo, player->mo->angle + (ANG90/16), (128*FRACUNIT));
-        if(!linetarget)
-            P_AimLineAttack(player->mo, player->mo->angle - (ANG90/16), (128*FRACUNIT));
-    }
-
-    if(!linetarget)
-       return;
-
-    // already in combat, can't talk to it
-    if(linetarget->flags & MF_NODIALOG)
-       return;
-
-    // set pointer to the character talking
-    dialogtalker = linetarget;
-
-    // play a sound
-    if(player == &players[consoleplayer])
-       S_StartSound(0, sfx_radio);
-
-    linetarget->target = player->mo;         // target the player
-    dialogtalker->reactiontime = 2;          // set reactiontime
-    dialogtalkerangle = dialogtalker->angle; // remember original angle
-
-    // face talker towards player
-    A_FaceTarget(dialogtalker);
-
-    // face towards NPC's direction
-    player->mo->angle = R_PointToAngle2(player->mo->x,
-                                        player->mo->y,
-                                        dialogtalker->x,
-                                        dialogtalker->y);
-    // set pointer to player talking
-    dialogplayer = player;
-
-    // haleyjd 09/08/10: get any stored dialog state from this object
-    jumptoconv = linetarget->miscdata;
-
-    // check item requirements
-    while(1)
-    {
-        int i = 0;
-        currentdialog = P_DialogFind(linetarget->type, jumptoconv);
-
-        // dialog's jumptoconv equal to 0? There's nothing to jump to.
-        if(currentdialog->jumptoconv == 0)
-            break;
-
-        // villsa 09/08/10: converted into for loop
-        for(i = 0; i < MDLG_MAXITEMS; i++)
-        {
-            // if the item is non-zero, the player must have at least one in his
-            // or her inventory
-            if(currentdialog->checkitem[i] != 0 &&
-                P_PlayerHasItem(dialogplayer, currentdialog->checkitem[i]) < 1)
-                break;
-        }
-
-        if(i < MDLG_MAXITEMS) // didn't find them all? this is our dialog!
-            break;
-
-        jumptoconv = currentdialog->jumptoconv;
-    }
-
-    M_DialogDimMsg(20, 28, currentdialog->text, false);
-    dialogtext = P_DialogGetMsg(currentdialog->text);
-
-    // get states
-    dialogtalkerstates = P_DialogGetStates(linetarget->type);
-
-    // have talker greet the player
-    if(dialogtalkerstates->greet)
-        P_SetMobjState(dialogtalker, dialogtalkerstates->greet);
-
-    // get talker's name
-    if(currentdialog->name[0])
-        dialogname = currentdialog->name;
-    else
-    {
-        // use a fallback:
-        if(mobjinfo[linetarget->type].name)
-            dialogname = DEH_String(mobjinfo[linetarget->type].name); // mobjtype name
-        else
-            dialogname = DEH_String("Person"); // default name - like Joe in Doom 3 :P
-    }
-
-    // setup number of choices to choose from
-    for(i = 0; i < MDLG_MAXCHOICES; i++)
-    {
-        if(!currentdialog->choices[i].giveitem)
-            break;
-    }
-
-    // set number of choices to menu
-    dialogmenu.numitems = i + 1;
-
-    rnd = M_Random() % 3;
-
-    // setup dialog menu
-    M_StartControlPanel();
-    menupause = false;
-    menuindialog = true;
-    menupausetime = gametic + 17;
-    currentMenu = &dialogmenu;
-
-    if(i >= dialogmenu.lastOn)
-        itemOn = dialogmenu.lastOn;
-    else
-        itemOn = 0;
-
-    // get backdrop
-    pic = W_CheckNumForName(currentdialog->backpic);
-    dialogbgpiclumpnum = pic;
-    if(pic != -1)
-        V_DrawPatchDirect(0, 0, W_CacheLumpNum(pic, PU_CACHE));
-
-    // get voice
-    I_StartVoice(currentdialog->voice);
-
-    // get bye text
-    switch(rnd)
-    {
-    case 2:
-        byetext = DEH_String("BYE!");
-        break;
-    case 1:
-        byetext = DEH_String("Thanks, Bye!");
-        break;
-    default:
-    case 0:
-        byetext = DEH_String("See you later!");
-        break;
-    }
-
-    DEH_snprintf(dialoglastmsgbuffer, sizeof(dialoglastmsgbuffer),
-                 "%d) %s", i + 1, byetext);
-}
-
-// EOF
-
-
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2010 James Haley, Samuel Villarreal
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// DESCRIPTION:
+//
+// [STRIFE] New Module
+//
+// Dialog Engine for Strife
+//
+
+#include <stdlib.h>
+
+#include "z_zone.h"
+#include "w_wad.h"
+#include "deh_str.h"
+#include "d_main.h"
+#include "d_mode.h"
+#include "d_player.h"
+#include "doomstat.h"
+#include "m_random.h"
+#include "m_menu.h"
+#include "m_misc.h"
+#include "r_main.h"
+#include "v_video.h"
+#include "p_local.h"
+#include "sounds.h"
+#include "p_dialog.h"
+#include "s_sound.h"
+#include "p_local.h"
+#include "p_inter.h"
+
+//
+// Defines and Macros
+//
+
+// haleyjd: size of the original Strife mapdialog_t structure.
+#define ORIG_MAPDIALOG_SIZE 0x5EC
+
+#define DIALOG_INT(field, ptr)    \
+    field = ((int)ptr[0]        | \
+            ((int)ptr[1] <<  8) | \
+            ((int)ptr[2] << 16) | \
+            ((int)ptr[3] << 24)); \
+    ptr += 4;
+
+#define DIALOG_STR(field, ptr, len) \
+    memcpy(field, ptr, len);        \
+    ptr += len;
+
+//
+// Globals
+//
+
+// This can be toggled at runtime to determine if the full dialog messages
+// are subtitled on screen or not. Defaults to off.
+int dialogshowtext = false;
+
+// The global mission objective buffer. This gets written to and read from file,
+// and is set by dialogs and line actions.
+char mission_objective[OBJECTIVE_LEN];
+
+//
+// Static Globals
+//
+
+// True if SCRIPT00 is loaded.
+static boolean script0loaded;
+
+// Number of dialogs defined in the current level's script.
+static int numleveldialogs;
+
+// The actual level dialogs. This didn't exist in Strife, but is new to account
+// for structure alignment/packing concerns, given that Chocolate Doom is
+// multiplatform.
+static mapdialog_t *leveldialogs;
+
+// The actual script00 dialogs. As above.
+static mapdialog_t *script0dialogs;
+
+// Number of dialogs defined in the SCRIPT00 lump.
+static int numscript0dialogs;
+
+// The player engaged in dialog. This is always player 1, though, since Rogue
+// never completed the ability to use dialog outside of single-player mode.
+static player_t *dialogplayer;
+
+// The object to which the player is speaking.
+static mobj_t   *dialogtalker;
+
+// The talker's current angle
+static angle_t dialogtalkerangle;
+
+// The currently active mapdialog object.
+static mapdialog_t *currentdialog;
+
+// Text at the end of the choices
+static char dialoglastmsgbuffer[48];
+
+// Item to display to player when picked up or recieved
+static char pickupstring[46];
+
+// Health based on gameskill given by the front's medic
+static const int healthamounts[] = { -100 , -75, -50, -50, -100 };
+
+//=============================================================================
+//
+// Dialog State Sets
+//
+// These are used to animate certain actors in response to what happens in
+// their dialog sequences.
+//
+
+typedef struct dialogstateset_s
+{
+    mobjtype_t type;  // the type of object
+    statenum_t greet; // greeting state, for start of dialog
+    statenum_t yes;   // "yes" state, for an affirmative response
+    statenum_t no;    // "no" state, when you don't have the right items
+} dialogstateset_t;
+
+static dialogstateset_t dialogstatesets[] =
+{
+    { MT_PLAYER,       S_NULL,    S_NULL,    S_NULL    },
+    { MT_SHOPKEEPER_W, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
+    { MT_SHOPKEEPER_B, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
+    { MT_SHOPKEEPER_A, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
+    { MT_SHOPKEEPER_M, S_MRGT_00, S_MRYS_00, S_MRNO_00 }
+};
+
+// Rogue stored this in a static global rather than making it a define...
+static int numdialogstatesets = arrlen(dialogstatesets);
+
+// Current dialog talker state
+static dialogstateset_t *dialogtalkerstates;
+
+//=============================================================================
+//
+// Random Messages
+//
+// Rogue hard-coded these so they wouldn't have to repeat them several times
+// in the SCRIPT00 lump, apparently.
+//
+
+#define MAXRNDMESSAGES 10
+
+typedef struct rndmessage_s
+{
+    const char *type_name;
+    int nummessages;
+    char *messages[MAXRNDMESSAGES];
+} rndmessage_t;
+
+static rndmessage_t rndMessages[] = 
+{
+    // Peasants
+    {
+        "PEASANT",
+        10,
+        {
+            "PLEASE DON'T HURT ME.",
+            
+            "IF YOU'RE LOOKING TO HURT ME, I'M \n"
+            "NOT REALLY WORTH THE EFFORT.",
+            
+            "I DON'T KNOW ANYTHING.",
+            
+            "GO AWAY OR I'LL CALL THE GUARDS!",
+            
+            "I WISH SOMETIMES THAT ALL THESE \n"
+            "REBELS WOULD JUST LEARN THEIR \n"
+            "PLACE AND STOP THIS NONSENSE.",
+
+            "JUST LEAVE ME ALONE, OK?",
+
+            "I'M NOT SURE, BUT SOMETIMES I THINK \n"
+            "THAT I KNOW SOME OF THE ACOLYTES.",
+
+            "THE ORDER'S GOT EVERYTHING AROUND HERE PRETTY WELL LOCKED UP TIGHT.",
+
+            "THERE'S NO WAY THAT THIS IS JUST A \n"
+            "SECURITY FORCE.",
+
+            "I'VE HEARD THAT THE ORDER IS REALLY \n"
+            "NERVOUS ABOUT THE FRONT'S \n"
+            "ACTIONS AROUND HERE."
+        }
+    },
+    // Rebel
+    {
+        "REBEL",
+        10,
+        {
+            "THERE'S NO WAY THE ORDER WILL \n"
+            "STAND AGAINST US.",
+
+            "WE'RE ALMOST READY TO STRIKE. \n"
+            "MACIL'S PLANS ARE FALLING IN PLACE.",
+
+            "WE'RE ALL BEHIND YOU, DON'T WORRY.",
+
+            "DON'T GET TOO CLOSE TO ANY OF THOSE BIG ROBOTS. THEY'LL MELT YOU DOWN \n"
+            "FOR SCRAP!",
+
+            "THE DAY OF OUR GLORY WILL SOON \n"
+            "COME, AND THOSE WHO OPPOSE US WILL \n"
+            "BE CRUSHED!",
+
+            "DON'T GET TOO COMFORTABLE. WE'VE \n"
+            "STILL GOT OUR WORK CUT OUT FOR US.",
+
+            "MACIL SAYS THAT YOU'RE THE NEW \n"
+            "HOPE. BEAR THAT IN MIND.",
+
+            "ONCE WE'VE TAKEN THESE CHARLATANS DOWN, WE'LL BE ABLE TO REBUILD THIS "
+            "WORLD AS IT SHOULD BE.",
+
+            "REMEMBER THAT YOU AREN'T FIGHTING \n"
+            "JUST FOR YOURSELF, BUT FOR \n"
+            "EVERYONE HERE AND OUTSIDE.",
+
+            "AS LONG AS ONE OF US STILL STANDS, \n"
+            "WE WILL WIN."
+        }
+    },
+    // Acolyte
+    {
+        "AGUARD",
+        10,
+        {
+            "MOVE ALONG,  PEASANT.",
+
+            "FOLLOW THE TRUE FAITH, ONLY THEN \n"
+            "WILL YOU BEGIN TO UNDERSTAND.",
+
+            "ONLY THROUGH DEATH CAN ONE BE \n"
+            "TRULY REBORN.",
+
+            "I'M NOT INTERESTED IN YOUR USELESS \n"
+            "DRIVEL.",
+
+            "IF I HAD WANTED TO TALK TO YOU I \n"
+            "WOULD HAVE TOLD YOU SO.",
+
+            "GO AND ANNOY SOMEONE ELSE!",
+
+            "KEEP MOVING!",
+
+            "IF THE ALARM GOES OFF, JUST STAY OUT OF OUR WAY!",
+
+            "THE ORDER WILL CLEANSE THE WORLD \n"
+            "AND USHER IT INTO THE NEW ERA.",
+
+            "PROBLEM?  NO, I THOUGHT NOT.",
+        }
+    },
+    // Beggar
+    {
+        "BEGGAR",
+        10,
+        {
+            "ALMS FOR THE POOR?",
+
+            "WHAT ARE YOU LOOKING AT, SURFACER?",
+
+            "YOU WOULDN'T HAVE ANY EXTRA FOOD, WOULD YOU?",
+
+            "YOU  SURFACE PEOPLE WILL NEVER \n"
+            "                                                                 "
+            "                                      UNDERSTAND US.",
+
+            "HA, THE GUARDS CAN'T FIND US.  THOSE \n"
+            "IDIOTS DON'T EVEN KNOW WE EXIST.",
+
+            "ONE DAY EVERYONE BUT THOSE WHO SERVE THE ORDER WILL BE FORCED TO "
+            "  JOIN US.",
+
+            "STARE NOW,  BUT YOU KNOW THAT THIS WILL BE YOUR OWN FACE ONE DAY.",
+
+            // Note: "NOTHING THING" is an authentic typo
+            "THERE'S NOTHING THING MORE \n"
+            "ANNOYING THAN A SURFACER WITH AN ATTITUDE!",
+
+            "THE ORDER WILL MAKE SHORT WORK OF YOUR PATHETIC FRONT.",
+
+            "WATCH YOURSELF SURFACER. WE KNOW OUR ENEMIES!"
+        }
+    },
+    // Templar
+    {
+        "PGUARD",
+        10,
+        {
+            "WE ARE THE HANDS OF FATE. TO EARN \n"
+            "OUR WRATH IS TO FIND OBLIVION!",
+
+            "THE ORDER WILL CLEANSE THE WORLD \n"
+            "OF THE WEAK AND CORRUPT!",
+
+            "OBEY THE WILL OF THE MASTERS!",
+
+            "LONG LIFE TO THE BROTHERS OF THE \n"
+            "ORDER!",
+
+            "FREE WILL IS AN ILLUSION THAT BINDS \n"
+            "THE WEAK MINDED.",
+
+            "POWER IS THE PATH TO GLORY. TO \n"
+            "FOLLOW THE ORDER IS TO WALK THAT \n"
+            "PATH!",
+
+            "TAKE YOUR PLACE AMONG THE \n"
+            "RIGHTEOUS, JOIN US!",
+
+            "THE ORDER PROTECTS ITS OWN.",
+
+            "ACOLYTES?  THEY HAVE YET TO SEE THE FULL GLORY OF THE ORDER.",
+
+            "IF THERE IS ANY HONOR INSIDE THAT \n"
+            "PATHETIC SHELL OF A BODY, \n"
+            "YOU'LL ENTER INTO THE ARMS OF THE \n"
+            "ORDER."
+        }
+    }
+};
+
+// And again, this could have been a define, but was a variable.
+static int numrndmessages = arrlen(rndMessages);
+
+//=============================================================================
+//
+// Dialog Menu Structure
+//
+// The Strife dialog system is actually just a serious abuse of the DOOM menu
+// engine. Hence why it doesn't work in multiplayer games or during demo
+// recording.
+//
+
+#define NUMDIALOGMENUITEMS 6
+
+static void P_DialogDrawer(void);
+
+static menuitem_t dialogmenuitems[] =
+{
+    { 1, "", P_DialogDoChoice, '1' }, // These items are loaded dynamically
+    { 1, "", P_DialogDoChoice, '2' },
+    { 1, "", P_DialogDoChoice, '3' },
+    { 1, "", P_DialogDoChoice, '4' },
+    { 1, "", P_DialogDoChoice, '5' },
+    { 1, "", P_DialogDoChoice, '6' }  // Item 6 is always the dismissal item
+};
+
+static menu_t dialogmenu =
+{
+    NUMDIALOGMENUITEMS, 
+    NULL, 
+    dialogmenuitems, 
+    P_DialogDrawer, 
+    42, 
+    75, 
+    0
+};
+
+// Lump number of the dialog background picture, if any.
+static int dialogbgpiclumpnum;
+
+// Name of current speaking character.
+static char *dialogname;
+
+// Current dialog text.
+static const char *dialogtext;
+
+//=============================================================================
+//
+// Routines
+//
+
+//
+// P_ParseDialogLump
+//
+// haleyjd 09/02/10: This is an original function added to parse out the 
+// dialogs from the dialog lump rather than reading them raw from the lump 
+// pointer. This avoids problems with structure packing.
+//
+static void P_ParseDialogLump(byte *lump, mapdialog_t **dialogs, 
+                              int numdialogs, int tag)
+{
+    int i;
+    byte *rover = lump;
+
+    *dialogs = Z_Malloc(numdialogs * sizeof(mapdialog_t), tag, NULL);
+
+    for(i = 0; i < numdialogs; i++)
+    {
+        int j;
+        mapdialog_t *curdialog = &((*dialogs)[i]);
+
+        DIALOG_INT(curdialog->speakerid,    rover);
+        DIALOG_INT(curdialog->dropitem,     rover);
+        DIALOG_INT(curdialog->checkitem[0], rover);
+        DIALOG_INT(curdialog->checkitem[1], rover);
+        DIALOG_INT(curdialog->checkitem[2], rover);
+        DIALOG_INT(curdialog->jumptoconv,   rover);
+        DIALOG_STR(curdialog->name,         rover, MDLG_NAMELEN);
+        DIALOG_STR(curdialog->voice,        rover, MDLG_LUMPLEN);
+        DIALOG_STR(curdialog->backpic,      rover, MDLG_LUMPLEN);
+        DIALOG_STR(curdialog->text,         rover, MDLG_TEXTLEN);
+
+        // copy choices
+        for(j = 0; j < 5; j++)
+        {
+            mapdlgchoice_t *curchoice = &(curdialog->choices[j]);
+            DIALOG_INT(curchoice->giveitem,         rover);
+            DIALOG_INT(curchoice->needitems[0],     rover);
+            DIALOG_INT(curchoice->needitems[1],     rover);
+            DIALOG_INT(curchoice->needitems[2],     rover);
+            DIALOG_INT(curchoice->needamounts[0],   rover);
+            DIALOG_INT(curchoice->needamounts[1],   rover);
+            DIALOG_INT(curchoice->needamounts[2],   rover);
+            DIALOG_STR(curchoice->text,             rover, MDLG_CHOICELEN);
+            DIALOG_STR(curchoice->textok,           rover, MDLG_MSGLEN);
+            DIALOG_INT(curchoice->next,             rover);
+            DIALOG_INT(curchoice->objective,        rover);
+            DIALOG_STR(curchoice->textno,           rover, MDLG_MSGLEN);
+        }
+    }
+}
+
+//
+// P_DialogLoad
+//
+// [STRIFE] New function
+// haleyjd 09/02/10: Loads the dialog script for the current map. Also loads 
+// SCRIPT00 if it has not yet been loaded.
+//
+void P_DialogLoad(void)
+{
+    char lumpname[9];
+    int  lumpnum;
+
+    // load the SCRIPTxy lump corresponding to MAPxy, if it exists.
+    DEH_snprintf(lumpname, sizeof(lumpname), "script%02d", gamemap);
+    if((lumpnum = W_CheckNumForName(lumpname)) == -1)
+        numleveldialogs = 0;
+    else
+    {
+        byte *leveldialogptr = W_CacheLumpNum(lumpnum, PU_STATIC);
+        numleveldialogs = W_LumpLength(lumpnum) / ORIG_MAPDIALOG_SIZE;
+        P_ParseDialogLump(leveldialogptr, &leveldialogs, numleveldialogs, 
+                          PU_LEVEL);
+        Z_Free(leveldialogptr); // haleyjd: free the original lump
+    }
+
+    // also load SCRIPT00 if it has not been loaded yet
+    if(!script0loaded)
+    {
+        byte *script0ptr;
+
+        script0loaded = true; 
+        // BUG: Rogue should have used W_GetNumForName here...
+        lumpnum = W_CheckNumForName(DEH_String("script00")); 
+        script0ptr = W_CacheLumpNum(lumpnum, PU_STATIC);
+        numscript0dialogs = W_LumpLength(lumpnum) / ORIG_MAPDIALOG_SIZE;
+        P_ParseDialogLump(script0ptr, &script0dialogs, numscript0dialogs,
+                          PU_STATIC);
+        Z_Free(script0ptr); // haleyjd: free the original lump
+    }
+}
+
+//
+// P_PlayerHasItem
+//
+// [STRIFE] New function
+// haleyjd 09/02/10: Checks for inventory items, quest flags, etc. for dialogs.
+// Returns the amount possessed, or 0 if none.
+//
+int P_PlayerHasItem(player_t *player, mobjtype_t type)
+{
+    int i;
+
+    if(type > 0)
+    {
+        // check keys
+        if(type >= MT_KEY_BASE && type < MT_INV_SHADOWARMOR)
+            return (player->cards[type - MT_KEY_BASE]);
+
+        // check sigil pieces
+        if(type >= MT_SIGIL_A && type <= MT_SIGIL_E)
+            return (type - MT_SIGIL_A <= player->sigiltype);
+
+        // check quest tokens
+        if(type >= MT_TOKEN_QUEST1 && type <= MT_TOKEN_QUEST31)
+            return (player->questflags & (1 << (type - MT_TOKEN_QUEST1)));
+
+        // check inventory
+        for(i = 0; i < 32; i++)
+        {
+            if(type == player->inventory[i].type)
+                return player->inventory[i].amount;
+        }
+    }
+    return 0;
+}
+
+//
+// P_DialogFind
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Looks for a dialog definition matching the given 
+// Script ID # for an mobj.
+//
+mapdialog_t *P_DialogFind(mobjtype_t type, int jumptoconv)
+{
+    int i;
+
+    // check the map-specific dialogs first
+    for(i = 0; i < numleveldialogs; i++)
+    {
+        if(type == leveldialogs[i].speakerid)
+        {
+            if(jumptoconv <= 1)
+                return &leveldialogs[i];
+            else
+                --jumptoconv;
+        }
+    }
+
+    // check SCRIPT00 dialogs next
+    for(i = 0; i < numscript0dialogs; i++)
+    {
+        if(type == script0dialogs[i].speakerid)
+            return &script0dialogs[i];
+    }
+
+    // the default dialog is script 0 in the SCRIPT00 lump.
+    return &script0dialogs[0];
+}
+
+//
+// P_DialogGetStates
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Find the set of special dialog states (greetings, yes, no)
+// for a particular thing type.
+//
+static dialogstateset_t *P_DialogGetStates(mobjtype_t type)
+{
+    int i;
+
+    // look for a match by type
+    for(i = 0; i < numdialogstatesets; i++)
+    {
+        if(type == dialogstatesets[i].type)
+            return &dialogstatesets[i];
+    }
+
+    // return the default 0 record if no match.
+    return &dialogstatesets[0];
+}
+
+//
+// P_DialogGetMsg
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Redirects dialog messages when the script indicates that
+// the actor should use a random message stored in the executable instead.
+//
+static const char *P_DialogGetMsg(const char *message)
+{
+    // if the message starts with "RANDOM"...
+    if(!strncasecmp(message, DEH_String("RANDOM"), 6))
+    {
+        int i;
+        const char *nameloc = message + 7;
+
+        // look for a match in rndMessages for the string starting 
+        // 7 chars after "RANDOM_"
+        for(i = 0; i < numrndmessages; i++)
+        {
+            if(!strncasecmp(nameloc, rndMessages[i].type_name, 4))
+            {
+                // found a match, so return a random message
+                int rnd = M_Random();
+                int nummessages = rndMessages[i].nummessages;
+                return DEH_String(rndMessages[i].messages[rnd % nummessages]);
+            }
+        }
+    }
+
+    // otherwise, just return the message passed in.
+    return message;
+}
+
+//
+// P_GiveInventoryItem
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Give an inventory item to the player, if possible.
+// villsa 09/09/10: Fleshed out routine
+//
+boolean P_GiveInventoryItem(player_t *player, int sprnum, mobjtype_t type)
+{
+    int curinv = 0;
+    int i;
+    boolean ok = false;
+    mobjtype_t item = 0;
+    inventory_t* invtail;
+
+    // repaint the status bar due to inventory changing
+    player->st_update = true;
+
+    while(1)
+    {
+        // inventory is full
+        if(curinv > player->numinventory)
+            return true;
+
+        item = player->inventory[curinv].type;
+        if(type < item)
+        {
+            if(curinv != MAXINVENTORYSLOTS)
+            {
+                // villsa - sort inventory item if needed
+                invtail = &player->inventory[player->numinventory - 1];
+                if(player->numinventory >= (curinv + 1))
+                {
+                    for(i = player->numinventory; i >= (curinv + 1); --i)    
+                    {
+                        invtail[1].sprite   = invtail[0].sprite;
+                        invtail[1].type     = invtail[0].type;
+                        invtail[1].amount   = invtail[0].amount;
+
+                        invtail--;
+                    }
+                }
+
+                // villsa - add inventory item
+                player->inventory[curinv].amount = 1;
+                player->inventory[curinv].sprite = sprnum;
+                player->inventory[curinv].type = type;
+
+                // sort cursor if needed
+                if(player->numinventory)
+                {
+                    if(curinv <= player->inventorycursor)
+                        player->inventorycursor++;
+                }
+
+                player->numinventory++;
+
+                return true;
+            }
+
+            return false;
+        }
+
+        if(type == item)
+            break;
+
+        curinv++;
+    }
+
+    // check amount of inventory item by using the mass from mobjinfo
+    if(player->inventory[curinv].amount < mobjinfo[item].mass)
+    {
+        player->inventory[curinv].amount++;
+        ok = true;
+    }
+    else
+        ok = false;
+
+    return ok;
+}
+
+//
+// P_GiveItemToPlayer
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Sorts out how to give something to the player.
+// Not strictly just for inventory items.
+// villsa 09/09/10: Fleshed out function
+//
+boolean P_GiveItemToPlayer(player_t *player, int sprnum, mobjtype_t type)
+{
+    int i = 0;
+    line_t junk;
+    int sound = sfx_itemup; // haleyjd 09/21/10: different sounds for items
+
+    // set quest if mf_givequest flag is set
+    if(mobjinfo[type].flags & MF_GIVEQUEST)
+        player->questflags |= 1 << (mobjinfo[type].speed - 1);
+
+    // check for keys
+    if(type >= MT_KEY_BASE && type <= MT_NEWKEY5)
+    {
+        P_GiveCard(player, type - MT_KEY_BASE);
+        return true;
+    }
+
+    // check for quest tokens
+    if(type >= MT_TOKEN_QUEST1 && type <= MT_TOKEN_QUEST31)
+    {
+        if(mobjinfo[type].name)
+        {
+            M_StringCopy(pickupstring, DEH_String(mobjinfo[type].name), 39);
+            player->message = pickupstring;
+        }
+        player->questflags |= 1 << (type - MT_TOKEN_QUEST1);
+
+        if(player == &players[consoleplayer])
+            S_StartSound(NULL, sound);
+        return true;
+    }
+
+    // haleyjd 09/22/10: Refactored to give sprites higher priority than
+    // mobjtypes and to implement missing logic.
+    switch(sprnum)
+    {
+    case SPR_HELT: // This is given only by the "DONNYTRUMP" cheat (aka Midas)
+        P_GiveInventoryItem(player, SPR_HELT, MT_TOKEN_TOUGHNESS);
+        P_GiveInventoryItem(player, SPR_GUNT, MT_TOKEN_ACCURACY);
+
+        // [STRIFE] Bizarre...
+        for(i = 0; i < 5 * player->accuracy + 300; i++)
+            P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+        break;
+
+    case SPR_ARM1: // Armor 1
+        if(!P_GiveArmor(player, -2))
+            P_GiveInventoryItem(player, sprnum, type);
+        break;
+
+    case SPR_ARM2: // Armor 2
+        if(!P_GiveArmor(player, -1))
+            P_GiveInventoryItem(player, sprnum, type);
+        break;
+
+    case SPR_COIN: // 1 Gold
+        P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+        break;
+
+    case SPR_CRED: // 10 Gold
+        for(i = 0; i < 10; i++)
+            P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+        break;
+
+    case SPR_SACK: // 25 gold
+        for(i = 0; i < 25; i++)
+            P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+        break;
+
+    case SPR_CHST: // 50 gold
+        for(i = 0; i < 50; i++)
+            P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+        break; // haleyjd 20141215: missing break, caused Rowan to not take ring from you.
+
+    case SPR_BBOX: // Box of Bullets
+        if(!P_GiveAmmo(player, am_bullets, 5))
+            return false;
+        break;
+
+    case SPR_BLIT: // Bullet Clip
+        if(!P_GiveAmmo(player, am_bullets, 1))
+            return false;
+        break;
+
+    case SPR_PMAP: // Map powerup
+        if(!P_GivePower(player, pw_allmap))
+            return false;
+        sound = sfx_yeah; // bluh-doop!
+        break;
+
+    case SPR_COMM: // Communicator
+        if(!P_GivePower(player, pw_communicator))
+            return false;
+        sound = sfx_yeah; // bluh-doop!
+        break;
+
+    case SPR_MSSL: // Mini-missile
+        if(!P_GiveAmmo(player, am_missiles, 1))
+            return false;
+        break;
+
+    case SPR_ROKT: // Crate of missiles
+        if(!P_GiveAmmo(player, am_missiles, 5))
+            return false;
+        break;
+
+    case SPR_BRY1: // Battery cell
+        if(!P_GiveAmmo(player, am_cell, 1))
+            return false;
+        break;
+
+    case SPR_CPAC: // Cell pack
+        if(!P_GiveAmmo(player, am_cell, 5))
+            return false;
+        break;
+
+    case SPR_PQRL: // Poison bolts
+        if(!P_GiveAmmo(player, am_poisonbolts, 5))
+            return false;
+        break;
+
+    case SPR_XQRL: // Electric bolts
+        if(!P_GiveAmmo(player, am_elecbolts, 5))
+            return false;
+        break;
+
+    case SPR_GRN1: // HE Grenades
+        if(!P_GiveAmmo(player, am_hegrenades, 1))
+            return false;
+        break;
+
+    case SPR_GRN2: // WP Grenades
+        if(!P_GiveAmmo(player, am_wpgrenades, 1))
+            return false;
+        break;
+
+    case SPR_BKPK: // Backpack (aka Ammo Satchel)
+        if(!player->backpack)
+        {
+            for(i = 0; i < NUMAMMO; i++)
+                player->maxammo[i] *= 2;
+
+            player->backpack = true;
+        }
+        for(i = 0; i < NUMAMMO; i++)
+            P_GiveAmmo(player, i, 1);
+        break;
+
+    case SPR_RIFL: // Assault Rifle
+        if(player->weaponowned[wp_rifle])
+            return false;
+
+        if(!P_GiveWeapon(player, wp_rifle, false))
+            return false;
+        
+        sound = sfx_wpnup; // SHK-CHK!
+        break;
+
+    case SPR_FLAM: // Flamethrower
+        if(player->weaponowned[wp_flame])
+            return false;
+
+        if(!P_GiveWeapon(player, wp_flame, false))
+            return false;
+
+        sound = sfx_wpnup; // SHK-CHK!
+        break;
+
+    case SPR_MMSL: // Mini-missile Launcher
+        if(player->weaponowned[wp_missile])
+            return false;
+
+        if(!P_GiveWeapon(player, wp_missile, false))
+            return false;
+
+        sound = sfx_wpnup; // SHK-CHK!
+        break;
+
+    case SPR_TRPD: // Mauler
+        if(player->weaponowned[wp_mauler])
+            return false;
+
+        if(!P_GiveWeapon(player, wp_mauler, false))
+            return false;
+
+        sound = sfx_wpnup; // SHK-CHK!
+        break;
+
+    case SPR_CBOW: // Here's a crossbow. Just aim straight, and *SPLAT!*
+        if(player->weaponowned[wp_elecbow])
+            return false;
+
+        if(!P_GiveWeapon(player, wp_elecbow, false))
+            return false;
+
+        sound = sfx_wpnup; // SHK-CHK!
+        break;
+
+    case SPR_TOKN: // Miscellaneous items - These are determined by thingtype.
+        switch(type)
+        {
+        case MT_KEY_HAND: // Severed hand
+            P_GiveCard(player, key_SeveredHand);
+            break;
+
+        case MT_MONY_300: // 300 Gold (this is the only way to get it, in fact)
+            for(i = 0; i < 300; i++)
+                P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+            break;
+
+        case MT_TOKEN_AMMO: // Ammo token - you get this from the Weapons Trainer
+            if(player->ammo[am_bullets] >= 50)
+                return false;
+
+            player->ammo[am_bullets] = 50;
+            break;
+
+        case MT_TOKEN_HEALTH: // Health token - from the Front's doctor
+            if(!P_GiveBody(player, healthamounts[gameskill]))
+                return false;
+            break;
+
+        case MT_TOKEN_ALARM: // Alarm token - particularly from the Oracle.
+            P_NoiseAlert(player->mo, player->mo);
+            A_AlertSpectreC(dialogtalker); // BUG: assumes in a dialog o_O
+            break;
+
+        case MT_TOKEN_DOOR1: // Door special 1
+            junk.tag = 222;
+            EV_DoDoor(&junk, vld_open);
+            break;
+
+        case MT_TOKEN_PRISON_PASS: // Door special 1 - Prison pass
+            junk.tag = 223;
+            EV_DoDoor(&junk, vld_open);
+            if(gamemap == 2) // If on Tarnhill, give Prison pass object
+                P_GiveInventoryItem(player, sprnum, type);
+            break;
+
+        case MT_TOKEN_SHOPCLOSE: // Door special 3 - "Shop close" - unused?
+            junk.tag = 222;
+            EV_DoDoor(&junk, vld_close);
+            break;
+
+        case MT_TOKEN_DOOR3: // Door special 4 (or 3? :P ) 
+            junk.tag = 224;
+            EV_DoDoor(&junk, vld_close);
+            break;
+
+        case MT_TOKEN_STAMINA: // Stamina upgrade
+            if(player->stamina >= 100)
+                return false;
+
+            player->stamina += 10;
+            P_GiveBody(player, 200); // full healing
+            break;
+
+        case MT_TOKEN_NEW_ACCURACY: // Accuracy upgrade
+            if(player->accuracy >= 100)
+                return false;
+
+            player->accuracy += 10;
+            break;
+
+        case MT_SLIDESHOW: // Slideshow (start a finale)
+            gameaction = ga_victory;
+            if(gamemap == 10)
+                P_GiveItemToPlayer(player, SPR_TOKN, MT_TOKEN_QUEST17);
+            break;
+        
+        default: // The default is to just give it as an inventory item.
+            P_GiveInventoryItem(player, sprnum, type);
+            break;
+        }
+        break;
+
+    default: // The ultimate default: Give it as an inventory item.
+        if(!P_GiveInventoryItem(player, sprnum, type))
+            return false;
+        break;
+    }
+
+    // Play sound.
+    if(player == &players[consoleplayer])
+        S_StartSound(NULL, sound);
+
+    return true;
+}
+
+//
+// P_TakeDialogItem
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Removes needed items from the player's inventory.
+//
+static void P_TakeDialogItem(player_t *player, int type, int amount)
+{
+    int i;
+
+    if(amount <= 0)
+        return;
+
+    for(i = 0; i < player->numinventory; i++)
+    {
+        // find a matching item
+        if(type != player->inventory[i].type)
+            continue;
+
+        // if there is none left...
+        if((player->inventory[i].amount -= amount) < 1)
+        {
+            // ...shift everything above it down
+            int j;
+
+            // BUG: They should have stopped at j < numinventory. This
+            // seems to implicitly assume that numinventory is always at
+            // least one less than the max # of slots, otherwise it 
+            // pulls in data from the following player_t fields:
+            // st_update, numinventory, inventorycursor, accuracy, stamina
+            for(j = i + 1; j <= player->numinventory; j++)
+            {
+                inventory_t *item1 = &(player->inventory[j - 1]);
+                inventory_t *item2 = &(player->inventory[j]);
+
+                *item1 = *item2;
+            }
+
+            // blank the topmost slot
+            // BUG: This will overwrite the aforementioned fields if
+            // numinventory is equal to the number of slots!
+            // STRIFE-TODO: Overflow emulation?
+            player->inventory[player->numinventory].type = NUMMOBJTYPES;
+            player->inventory[player->numinventory].sprite = -1;
+            player->numinventory--;
+
+            // update cursor position
+            if(player->inventorycursor >= player->numinventory)
+            {
+                if(player->inventorycursor)
+                    player->inventorycursor--;
+            }
+        } // end if
+        
+        return; // done!
+
+    } // end for
+}
+
+//
+// P_DialogDrawer
+//
+// This function is set as the drawer callback for the dialog menu.
+//
+static void P_DialogDrawer(void)
+{
+    angle_t angle;
+    int y;
+    int i;
+    int height;
+    int finaly;
+    char choicetext[64];
+    char choicetext2[64];
+
+    // Run down bonuscount faster than usual so that flashes from being given
+    // items are less obvious.
+    if(dialogplayer->bonuscount)
+    {
+        dialogplayer->bonuscount -= 3;
+        if(dialogplayer->bonuscount < 0)
+            dialogplayer->bonuscount = 0;
+    }
+
+    angle = R_PointToAngle2(dialogplayer->mo->x,
+                            dialogplayer->mo->y,
+                            dialogtalker->x,
+                            dialogtalker->y);
+    angle -= dialogplayer->mo->angle;
+
+    // Dismiss the dialog if the player is out of alignment, or the thing he was
+    // talking to is now engaged in battle.
+    if ((angle > ANG45 && angle < (ANG270+ANG45))
+     || (dialogtalker->flags & MF_NODIALOG) != 0)
+    {
+        P_DialogDoChoice(dialogmenu.numitems - 1);
+    }
+
+    dialogtalker->reactiontime = 2;
+
+    // draw background
+    if(dialogbgpiclumpnum != -1)
+    {
+        patch_t *patch = W_CacheLumpNum(dialogbgpiclumpnum, PU_CACHE);
+        V_DrawPatchDirect(0, 0, patch);
+    }
+
+    // if there's a valid background pic, delay drawing the rest of the menu 
+    // for a while; otherwise, it will appear immediately
+    if(dialogbgpiclumpnum == -1 || menupausetime <= gametic)
+    {
+        if(menuindialog)
+        {
+            // time to pause the game?
+            if(menupausetime + 3 < gametic)
+                menupause = true;
+        }
+
+        // draw character name
+        M_WriteText(12, 18, dialogname);
+        y = 28;
+
+        // show text (optional for dialogs with voices)
+        if(dialogshowtext || currentdialog->voice[0] == '\0')
+            y = M_WriteText(20, 28, dialogtext);
+
+        height = 20 * dialogmenu.numitems;
+
+        finaly = 175 - height;     // preferred height
+        if(y > finaly)
+            finaly = 199 - height; // height it will bump down to if necessary.
+
+        // draw divider
+        M_WriteText(42, finaly - 6, DEH_String("______________________________"));
+
+        dialogmenu.y = finaly + 6;
+        y = 0;
+
+        // draw the menu items
+        for(i = 0; i < dialogmenu.numitems - 1; i++)
+        {
+            DEH_snprintf(choicetext, sizeof(choicetext),
+                         "%d) %s", i + 1, currentdialog->choices[i].text);
+            
+            // alternate text for items that need money
+            if(currentdialog->choices[i].needamounts[0] > 0)
+            {
+                // haleyjd 20120401: necessary to avoid undefined behavior:
+                M_StringCopy(choicetext2, choicetext, sizeof(choicetext2));
+                DEH_snprintf(choicetext, sizeof(choicetext),
+                             "%s for %d", choicetext2,
+                             currentdialog->choices[i].needamounts[0]);
+            }
+
+            M_WriteText(dialogmenu.x, dialogmenu.y + 3 + y, choicetext);
+            y += 19;
+        }
+
+        // draw the final item for dismissing the dialog
+        M_WriteText(dialogmenu.x, 19 * i + dialogmenu.y + 3, dialoglastmsgbuffer);
+    }
+}
+
+//
+// P_DialogDoChoice
+//
+// [STRIFE] New function
+// haleyjd 09/05/10: Handles making a choice in a dialog. Installed as the
+// callback for all items in the dialogmenu structure.
+//
+void P_DialogDoChoice(int choice)
+{
+    int i = 0, nextdialog = 0;
+    boolean candochoice = true;
+    char *message = NULL;
+    mapdlgchoice_t *currentchoice;
+
+    if(choice == -1)
+        choice = dialogmenu.numitems - 1;
+
+    currentchoice = &(currentdialog->choices[choice]);
+
+    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++)
+    {
+        if(P_PlayerHasItem(dialogplayer, currentchoice->needitems[i]) <
+                                         currentchoice->needamounts[i])
+        {
+            candochoice = false; // nope, missing something
+        }
+    }
+
+    if(choice != dialogmenu.numitems - 1 && candochoice)
+    {
+        int item;
+
+        message = currentchoice->textok;
+        if(dialogtalkerstates->yes)
+            P_SetMobjState(dialogtalker, dialogtalkerstates->yes);
+
+        item = currentchoice->giveitem;
+        if(item < 0 || 
+           P_GiveItemToPlayer(dialogplayer, 
+                              states[mobjinfo[item].spawnstate].sprite, 
+                              item))
+        {
+            // if successful, take needed items
+            int count = 0;
+            // villsa 09/08/10: converted into for loop
+            for(count = 0; count < MDLG_MAXITEMS; count++)
+            {
+                P_TakeDialogItem(dialogplayer, 
+                                 currentchoice->needitems[count],
+                                 currentchoice->needamounts[count]);
+            }
+        }
+        else
+            message = DEH_String("You seem to have enough!");
+
+        // store next dialog into the talking actor
+        nextdialog = currentchoice->next;
+        if(nextdialog != 0)
+            dialogtalker->miscdata = (byte)(abs(nextdialog));
+    }
+    else
+    {
+        // not successful
+        message = currentchoice->textno;
+        if(dialogtalkerstates->no)
+            P_SetMobjState(dialogtalker, dialogtalkerstates->no);
+    }
+    
+    if(choice != dialogmenu.numitems - 1)
+    {
+        int objective;
+        char *objlump;
+
+        if((objective = currentchoice->objective))
+        {
+            DEH_snprintf(mission_objective, OBJECTIVE_LEN, "log%i", objective);
+            objlump = W_CacheLumpName(mission_objective, PU_CACHE);
+            M_StringCopy(mission_objective, objlump, OBJECTIVE_LEN);
+        }
+        // haleyjd 20130301: v1.31 hack: if first char of message is a period,
+        // clear the player's message. Is this actually used anywhere?
+        if(gameversion == exe_strife_1_31 && message[0] == '.')
+            message = NULL;
+        dialogplayer->message = message;
+    }
+
+    dialogtalker->angle = dialogtalkerangle;
+    dialogplayer->st_update = true;
+    M_ClearMenus(0);
+
+    if(nextdialog >= 0 || gameaction == ga_victory) // Macil hack
+        menuindialog = false;
+    else
+        P_DialogStart(dialogplayer);
+}
+
+//
+// P_DialogStartP1
+//
+// [STRIFE] New function
+// haleyjd 09/13/10: This is a hack used by the finale system.
+//
+void P_DialogStartP1(void)
+{
+    P_DialogStart(&players[0]);
+}
+
+//
+// P_DialogStart
+//
+// villsa [STRIFE] New function
+//
+void P_DialogStart(player_t *player)
+{
+    int i = 0;
+    int pic;
+    int rnd = 0;
+    char* byetext;
+    int jumptoconv;
+
+    if(menuactive || netgame)
+        return;
+
+    // are we facing towards our NPC?
+    P_AimLineAttack(player->mo, player->mo->angle, (128*FRACUNIT));
+    if(!linetarget)
+    {
+        P_AimLineAttack(player->mo, player->mo->angle + (ANG90/16), (128*FRACUNIT));
+        if(!linetarget)
+            P_AimLineAttack(player->mo, player->mo->angle - (ANG90/16), (128*FRACUNIT));
+    }
+
+    if(!linetarget)
+       return;
+
+    // already in combat, can't talk to it
+    if(linetarget->flags & MF_NODIALOG)
+       return;
+
+    // set pointer to the character talking
+    dialogtalker = linetarget;
+
+    // play a sound
+    if(player == &players[consoleplayer])
+       S_StartSound(0, sfx_radio);
+
+    linetarget->target = player->mo;         // target the player
+    dialogtalker->reactiontime = 2;          // set reactiontime
+    dialogtalkerangle = dialogtalker->angle; // remember original angle
+
+    // face talker towards player
+    A_FaceTarget(dialogtalker);
+
+    // face towards NPC's direction
+    player->mo->angle = R_PointToAngle2(player->mo->x,
+                                        player->mo->y,
+                                        dialogtalker->x,
+                                        dialogtalker->y);
+    // set pointer to player talking
+    dialogplayer = player;
+
+    // haleyjd 09/08/10: get any stored dialog state from this object
+    jumptoconv = linetarget->miscdata;
+
+    // check item requirements
+    while(1)
+    {
+        int i = 0;
+        currentdialog = P_DialogFind(linetarget->type, jumptoconv);
+
+        // dialog's jumptoconv equal to 0? There's nothing to jump to.
+        if(currentdialog->jumptoconv == 0)
+            break;
+
+        // villsa 09/08/10: converted into for loop
+        for(i = 0; i < MDLG_MAXITEMS; i++)
+        {
+            // if the item is non-zero, the player must have at least one in his
+            // or her inventory
+            if(currentdialog->checkitem[i] != 0 &&
+                P_PlayerHasItem(dialogplayer, currentdialog->checkitem[i]) < 1)
+                break;
+        }
+
+        if(i < MDLG_MAXITEMS) // didn't find them all? this is our dialog!
+            break;
+
+        jumptoconv = currentdialog->jumptoconv;
+    }
+
+    M_DialogDimMsg(20, 28, currentdialog->text, false);
+    dialogtext = P_DialogGetMsg(currentdialog->text);
+
+    // get states
+    dialogtalkerstates = P_DialogGetStates(linetarget->type);
+
+    // have talker greet the player
+    if(dialogtalkerstates->greet)
+        P_SetMobjState(dialogtalker, dialogtalkerstates->greet);
+
+    // get talker's name
+    if(currentdialog->name[0])
+        dialogname = currentdialog->name;
+    else
+    {
+        // use a fallback:
+        if(mobjinfo[linetarget->type].name)
+            dialogname = DEH_String(mobjinfo[linetarget->type].name); // mobjtype name
+        else
+            dialogname = DEH_String("Person"); // default name - like Joe in Doom 3 :P
+    }
+
+    // setup number of choices to choose from
+    for(i = 0; i < MDLG_MAXCHOICES; i++)
+    {
+        if(!currentdialog->choices[i].giveitem)
+            break;
+    }
+
+    // set number of choices to menu
+    dialogmenu.numitems = i + 1;
+
+    rnd = M_Random() % 3;
+
+    // setup dialog menu
+    M_StartControlPanel();
+    menupause = false;
+    menuindialog = true;
+    menupausetime = gametic + 17;
+    currentMenu = &dialogmenu;
+
+    if(i >= dialogmenu.lastOn)
+        itemOn = dialogmenu.lastOn;
+    else
+        itemOn = 0;
+
+    // get backdrop
+    pic = W_CheckNumForName(currentdialog->backpic);
+    dialogbgpiclumpnum = pic;
+    if(pic != -1)
+        V_DrawPatchDirect(0, 0, W_CacheLumpNum(pic, PU_CACHE));
+
+    // get voice
+    I_StartVoice(currentdialog->voice);
+
+    // get bye text
+    switch(rnd)
+    {
+    case 2:
+        byetext = DEH_String("BYE!");
+        break;
+    case 1:
+        byetext = DEH_String("Thanks, Bye!");
+        break;
+    default:
+    case 0:
+        byetext = DEH_String("See you later!");
+        break;
+    }
+
+    DEH_snprintf(dialoglastmsgbuffer, sizeof(dialoglastmsgbuffer),
+                 "%d) %s", i + 1, byetext);
+}
+
+// EOF
+
+
--- a/src/strife/p_dialog.h
+++ b/src/strife/p_dialog.h
@@ -1,102 +1,102 @@
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 1996 Rogue Entertainment / Velocity, Inc.
-// Copyright(C) 2010 James Haley, Samuel Villareal
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// DESCRIPTION:
-//
-// [STRIFE] New Module
-//
-// Dialog Engine for Strife
-//
-
-#ifndef P_DIALOG_H__
-#define P_DIALOG_H__
-
-#define OBJECTIVE_LEN       300
-
-#define MAXINVENTORYSLOTS   30
-
-#define MDLG_CHOICELEN      32
-#define MDLG_MSGLEN         80
-#define MDLG_NAMELEN        16
-#define MDLG_LUMPLEN        8
-#define MDLG_TEXTLEN        320
-#define MDLG_MAXCHOICES     5
-#define MDLG_MAXITEMS       3
-
-extern char mission_objective[OBJECTIVE_LEN];
-
-extern int dialogshowtext;
-
-// villsa - convenient macro for giving objective logs to player
-#define GiveObjective(x, minlumpnum) \
-do { \
-  int obj_ln  = W_CheckNumForName(DEH_String(x)); \
-  if(obj_ln > minlumpnum) \
-    M_StringCopy(mission_objective, W_CacheLumpNum(obj_ln, PU_CACHE), \
-                 OBJECTIVE_LEN);\
-} while(0)
-
-// haleyjd - voice and objective in one
-#define GiveVoiceObjective(voice, log, minlumpnum) \
-do { \
-  int obj_ln = W_CheckNumForName(DEH_String(log)); \
-  I_StartVoice(DEH_String(voice)); \
-  if(obj_ln > minlumpnum) \
-    M_StringCopy(mission_objective, W_CacheLumpNum(obj_ln, PU_CACHE), \
-                 OBJECTIVE_LEN);\
-} while(0)
-
-typedef struct mapdlgchoice_s
-{
-    int  giveitem;                      // item given when successful
-    int  needitems[MDLG_MAXITEMS];      // item needed for success
-    int  needamounts[MDLG_MAXITEMS];    // amount of items needed
-    char text[MDLG_CHOICELEN];          // normal text
-    char textok[MDLG_MSGLEN];           // message given on success
-    int next;                           // next dialog?
-    int objective;                      // ???
-    char textno[MDLG_MSGLEN];           // message given on failure
-} mapdlgchoice_t;
-
-typedef struct mapdialog_s
-{
-    int speakerid;                      // script ID# for mobjtype that will use this dialog
-    int dropitem;                       // item to drop if that thingtype is killed
-    int checkitem[MDLG_MAXITEMS];       // item(s) needed to see this dialog
-    int jumptoconv;                     // conversation to jump to when... ?
-    char name[MDLG_NAMELEN];            // name of speaker
-    char voice[MDLG_LUMPLEN];           // voice file to play
-    char backpic[MDLG_LUMPLEN];         // backdrop pic for character, if any
-    char text[MDLG_TEXTLEN];            // main message text
-    
-    // options that this dialog gives the player
-    mapdlgchoice_t choices[MDLG_MAXCHOICES];
-} mapdialog_t;
-
-void         P_DialogLoad(void);
-void         P_DialogStart(player_t *player);
-void         P_DialogDoChoice(int choice);
-boolean      P_GiveItemToPlayer(player_t *player, int sprnum, mobjtype_t type);
-boolean      P_GiveInventoryItem(player_t *player, int sprnum, mobjtype_t type);
-boolean      P_UseInventoryItem(player_t* player, int item);
-void         P_DialogStartP1(void);
-mapdialog_t* P_DialogFind(mobjtype_t type, int jumptoconv);
-int          P_PlayerHasItem(player_t *player, mobjtype_t type);
-
-#endif
-
-// EOF
-
-
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1996 Rogue Entertainment / Velocity, Inc.
+// Copyright(C) 2010 James Haley, Samuel Villareal
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// DESCRIPTION:
+//
+// [STRIFE] New Module
+//
+// Dialog Engine for Strife
+//
+
+#ifndef P_DIALOG_H__
+#define P_DIALOG_H__
+
+#define OBJECTIVE_LEN       300
+
+#define MAXINVENTORYSLOTS   30
+
+#define MDLG_CHOICELEN      32
+#define MDLG_MSGLEN         80
+#define MDLG_NAMELEN        16
+#define MDLG_LUMPLEN        8
+#define MDLG_TEXTLEN        320
+#define MDLG_MAXCHOICES     5
+#define MDLG_MAXITEMS       3
+
+extern char mission_objective[OBJECTIVE_LEN];
+
+extern int dialogshowtext;
+
+// villsa - convenient macro for giving objective logs to player
+#define GiveObjective(x, minlumpnum) \
+do { \
+  int obj_ln  = W_CheckNumForName(DEH_String(x)); \
+  if(obj_ln > minlumpnum) \
+    M_StringCopy(mission_objective, W_CacheLumpNum(obj_ln, PU_CACHE), \
+                 OBJECTIVE_LEN);\
+} while(0)
+
+// haleyjd - voice and objective in one
+#define GiveVoiceObjective(voice, log, minlumpnum) \
+do { \
+  int obj_ln = W_CheckNumForName(DEH_String(log)); \
+  I_StartVoice(DEH_String(voice)); \
+  if(obj_ln > minlumpnum) \
+    M_StringCopy(mission_objective, W_CacheLumpNum(obj_ln, PU_CACHE), \
+                 OBJECTIVE_LEN);\
+} while(0)
+
+typedef struct mapdlgchoice_s
+{
+    int  giveitem;                      // item given when successful
+    int  needitems[MDLG_MAXITEMS];      // item needed for success
+    int  needamounts[MDLG_MAXITEMS];    // amount of items needed
+    char text[MDLG_CHOICELEN];          // normal text
+    char textok[MDLG_MSGLEN];           // message given on success
+    int next;                           // next dialog?
+    int objective;                      // ???
+    char textno[MDLG_MSGLEN];           // message given on failure
+} mapdlgchoice_t;
+
+typedef struct mapdialog_s
+{
+    int speakerid;                      // script ID# for mobjtype that will use this dialog
+    int dropitem;                       // item to drop if that thingtype is killed
+    int checkitem[MDLG_MAXITEMS];       // item(s) needed to see this dialog
+    int jumptoconv;                     // conversation to jump to when... ?
+    char name[MDLG_NAMELEN];            // name of speaker
+    char voice[MDLG_LUMPLEN];           // voice file to play
+    char backpic[MDLG_LUMPLEN];         // backdrop pic for character, if any
+    char text[MDLG_TEXTLEN];            // main message text
+    
+    // options that this dialog gives the player
+    mapdlgchoice_t choices[MDLG_MAXCHOICES];
+} mapdialog_t;
+
+void         P_DialogLoad(void);
+void         P_DialogStart(player_t *player);
+void         P_DialogDoChoice(int choice);
+boolean      P_GiveItemToPlayer(player_t *player, int sprnum, mobjtype_t type);
+boolean      P_GiveInventoryItem(player_t *player, int sprnum, mobjtype_t type);
+boolean      P_UseInventoryItem(player_t* player, int item);
+void         P_DialogStartP1(void);
+mapdialog_t* P_DialogFind(mobjtype_t type, int jumptoconv);
+int          P_PlayerHasItem(player_t *player, mobjtype_t type);
+
+#endif
+
+// EOF
+
+