ref: fbc9b30c1033e63e0af5b31cef5a7eab95e428dc
parent: 0083adaa40f4af7d44a3744ca315edb8d87c6bd8
parent: 37d108a5abb9e81fde6f1f47169d1130294d08e0
author: Thomas A. Birkel <[email protected]>
date: Wed Nov 30 20:12:13 EST 2016
Merge branch 'master' of https://github.com/chocolate-doom/chocolate-doom into commandline-savedir
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,79 +1,91 @@
## HEAD
### General
- * Bash completion scripts are included. (thanks Fabian)
- * Support the *.lmp file format in the OS X launcher (thanks Jon)
- * Added emulation for pitch-shifting as in early versions of Doom,
- Heretic, and Hexen. (thanks Jon)
- * Write out aspect-correct 1600×1200 PNGs. (thanks Jon)
- * OPL emulation is more accurate. (thanks Nuke.YKT)
- * Futher emulation of DMX bugs with GUS cards. (thanks Nuke.YKT)
- * Emulation of the disk icon has returned. (thanks Fabian, Jon)
- * Checksum calculations were fixed on big endian systems, allowing
+ * Bash completion scripts are included (thanks Fabian)
+ * The OS X launcher now supports the .lmp file format (thanks Jon)
+ * Pitch-shifting from early versions of Doom, Heretic, and Hexen.
+ is now supported (thanks Jon)
+ * Aspect ratio-corrected 1600×1200 PNGs are now written (thanks Jon)
+ * OPL emulation is more accurate (thanks Nuke.YKT)
+ * DMX bugs with GUS cards are now better emulated (thanks Nuke.YKT)
+ * The disk activity floppy disk icon is now shown (thanks Fabian, Jon)
+ * Checksum calculations are fixed on big endian systems, allowing
multiplayer games to be played in mixed little/big-endian
- environments. (thanks GhostlyDeath, njankowski)
+ environments (thanks GhostlyDeath, njankowski)
* The NES30, SNES30, and SFC30 gamepads are detected and configured
- automatically by the Setup tool. The automap can also be
- configured to a joystick button. (thanks Jon)
- * The vanilla limit of 4046 lumps per WAD is now enforced. (thanks
+ automatically by the Setup tool. The automap can also be configured
+ to a joystick button (thanks Jon)
+ * The vanilla limit of 4046 lumps per WAD is now enforced (thanks
Jon, Quasar, Edward-san)
- * Solidsegs overflow is emulated like in vanilla. (thanks Quasar)
- * Heretic/Hexen demo support has expanded. "-demoextend" allows
- demos to last longer than a single level; "-shortticfix" adjusts
- low-resolution turning to match Doom's handling; "-maxdemo" and
- "-longtics" support. (thanks CapnClever)
+ * Solidsegs overflow is emulated like in vanilla (thanks Quasar)
+ * Multiple capitalizations are now tried when searching for WAD files,
+ for convenience when running on case sensitive filesystems (thanks
+ Fabian).
### Build systems
- * Improved compatibility with BSD Make. (thanks R.Rebello)
+ * There is better compatibility with BSD Make (thanks R.Rebello)
* “./configure --with-PACKAGE” checks were repaired to behave
- logically, rather than disabling the feature. (thanks R.Rebello)
- * Default to installing the games to ${bindir}, such as
- /usr/local/bin, rather than /usr/local/games. (thanks chungy)
- * Support Visual Studio 2015. (thanks Azarien)
- * Allow SDL headers and libraries to exist in the Microsoft Visual
- Studio project directory. (thanks Quasar)
- * Repaired the CodeBlocks projects by removing non-existent files
+ logically, rather than disabling the feature (thanks R.Rebello)
+ * Games are now installed to ${bindir} by default, eg.
+ /usr/local/bin, rather than /usr/local/games (thanks chungy)
+ * Visual Studio 2015 is now supported (thanks Azarien)
+ * SDL headers and libraries can now exist in the Microsoft Visual
+ Studio project directory (thanks Quasar)
+ * CodeBlocks projects were repaired by removing non-existent files
from the project files (thanks krystalgamer)
### Doom
- * Chex Quest’s level warp cheat (LEESNYDER##) was changed to behave
- like the original EXE. (thanks Nuke.YKT)
- * Allow starting multiplayer Chex Quest games.
- * Allow Freedoom: Phase 1 ≤ 0.10.1 to be loaded with mods, with
- -gameversion older than ultimate. (thanks Fabian, chungy)
+ * Chex Quest’s level warp cheat (LEESNYDER##) now behaves more like
+ like the original EXE (thanks Nuke.YKT)
+ * It's now possible to start multiplayer Chex Quest games.
+ * Freedoom: Phase 1 <= 0.10.1 can now be loaded with mods, with
+ -gameversion older than ultimate (thanks Fabian, chungy)
* The IWAD order preference for GOG.com installs matches vanilla
- Final Doom: doom2, plutonia, tnt, doom. (thanks chungy)
- * Added safety checks against write failures when saving a game,
- such as when the directory is read-only. Try falling back to a
- temporary directory and reporting an error instead. (thanks
+ Final Doom: doom2, plutonia, tnt, doom (thanks chungy)
+ * There are better safety checks against write failures when saving
+ a game, such as when the directory is read-only (thanks
terrorcide)
- * Versions 1.666, 1.7, and 1.8 are emulated. (thanks Nuke.YKT)
+ * Versions 1.666, 1.7, and 1.8 are emulated (thanks Nuke.YKT)
+ * Crashes are now handled more gracefully when a linedef references
+ nonexistent sidedefs (thanks Fabian)
### Heretic
- * Added map names for Episode 6, fixing a crash after completing a
- level in this episode. (thanks J.Benaim)
- * Added unlimited demo/savegame support. (thanks CapnClever)
+ * Map names were added for Episode 6, fixing a crash after completing
+ a level in this episode (thanks J.Benaim)
+ * Support for unlimited demo/savegames was added (thanks CapnClever)
+ * Demo support is expanded: "-demoextend" allows demos to last longer
+ than a single level; "-shortticfix" adjusts low-resolution turning
+ to match Doom's handling, and there is now "-maxdemo" and "-longtics"
+ support (thanks CapnClever)
### Hexen
- * The MRJONES cheat code returns an identical string as vanilla, and
- enables fully reproducable builds. (thanks Fabian)
- * Fixed an issue where the game crashed while killing the
- Wraithverge in 64-bit builds. (thanks J.Benaim)
- * Added unlimited demo/savegame support. (thanks CapnClever)
+ * The MRJONES cheat code returns an identical string to vanilla, and
+ enables fully reproducible builds (thanks Fabian)
+ * An issue was fixed where the game crashed while killing the
+ Wraithverge in 64-bit builds (thanks J.Benaim)
+ * Support for unlimited demo/savegames was added (thanks CapnClever)
+ * Mouse buttons for strafe left/right and move backward were added,
+ as well as a "Double click acts as use" mouse option (thanks
+ CapnClever)
+ * Demo support is expanded: "-demoextend" allows demos to last longer
+ than a single level; "-shortticfix" adjusts low-resolution turning
+ to match Doom's handling, and there is now "-maxdemo" and "-longtics"
+ support (thanks CapnClever)
### Strife
- * Support added for automatic loading of the IWAD from the GOG.com
- release of Strife: Veteran Edition on Windows. (thanks chungy)
- * Jumping can be bound to a mouse button. (thanks Gez)
- * Gibbing logic was changed to match vanilla behavior. (thanks Quasar)
- * Several constants differences from vanilla were fixed. (thanks
+ * Support was added for automatic loading of the IWAD from the GOG.com
+ release of Strife: Veteran Edition on Windows (thanks chungy)
+ * Jumping can now be bound to a mouse button (thanks Gez)
+ * Gibbing logic was changed to match vanilla behavior (thanks Quasar)
+ * Several constants differences from vanilla were fixed (thanks
Nuke.YKT, Quasar)
* When using -iwad, voices.wad from the IWAD’s directory is prefered
- over auto-detected DOS/Steam/GOG.com installs. (thanks Quasar)
+ over auto-detected DOS/Steam/GOG.com installs (thanks Quasar)
### libtextscreen
- * Simplified the API for creating and managing tables and columns.
- * Allow cycling through tables with tab key.
+ * The API for creating and managing tables and columns was simplified.
+ * It's now possible to cycle through tables with the tab key.
+ * Windows can now have multiple columns.
## 2.2.1 (2015-09-10)
--- a/PHILOSOPHY.md
+++ b/PHILOSOPHY.md
@@ -28,9 +28,12 @@
* DOS Heretic 1.3.
* DOS Hexen 1.1.
* DOS Strife 1.31.
+ * DOS Chex Quest.
-“Vanilla” does not include ports (either official or unofficial), such
-as console ports, Doom 95 or Doom 3: BFG Edition.
+Compatibility with older versions of the DOS binaries is also a
+secondary goal (though not pre-release versions). Other ports (either
+official or unofficial) are out of scope: this includes console ports,
+non-DOS ports, Doom 95 and Doom 3: BFG Edition.
# Compatibility
@@ -46,7 +49,7 @@
Chocolate Doom as a faithful substitute.
* Demo compatibility: Doom was one of the first games to develop a
‘speedrunning’ community, and thousands of recordings of Doom
- gameplay (.lmp demo files) exist in the Compet-N archive. Chocolate
+ gameplay (`.lmp` demo files) exist in the Compet-N archive. Chocolate
Doom aims for the highest standard of demo compatibility with
Vanilla Doom, a goal that is often complicated by obscure behavior
that can be difficult to reproduce.
@@ -67,8 +70,8 @@
treated as such. Some examples are:
* The novert setting, which reproduces the functionality of
- novert.exe.
- * The -deh parameter, which loads Dehacked patches like dehacked.exe
+ `novert.exe`.
+ * The `-deh` parameter, which loads Dehacked patches like dehacked.exe
does under DOS. Chocolate Doom imposes the same limitations that
Vanilla Dehacked does.
@@ -97,8 +100,8 @@
3. Supporting obsolete technology is not a goal: it’s considered
acceptable that Chocolate Doom does not support every type of
hardware from 1993. However, Chocolate Doom should aim to recreate
- the functionality in a modern way. Examples of technology that
- isn’t supported are:
+ the functionality in a modern way. Examples of technologies that
+ aren’t supported are:
- No support for IPX networks, but TCP/IP is supported instead.
- No support for dial-up/serial connections; modern operating
@@ -111,9 +114,9 @@
- There are new key bindings for actions that can’t be rebound with
Vanilla Doom, because it’s useful for portability to machines
that don’t have a full keyboard.
- - There are additional mouse and joystick key bindings that let you
- perform actions with them that can only be done with the keyboard
- in Vanilla Doom.
+ - There are additional mouse and joystick button bindings that let
+ you perform actions with them that can only be done with the
+ keyboard in Vanilla Doom.
- Chocolate Doom includes some hacks to support the Doom 3: BFG
Edition IWAD files. The assumption is that being able to at least
play is better than nothing, even if it’s not Vanilla behavior.
@@ -145,9 +148,20 @@
- The startup messages in Chocolate Doom are not identical to
Vanilla Doom and are not necessarily in the same order.
- - Vanilla Doom has command line options named -comdev, -shdev and
- -regdev used by id internally for development; these have been
- removed.
+ - Vanilla Doom has command line options named `-comdev`, `-shdev`
+ and `-regdev` used by id internally for development; these have
+ been removed.
+
+ 8. Expansions to the vanilla demo formats are allowed, to make
+ recording and playback of vanilla gameplay more convenient, with
+ the following restrictions:
+
+ - Such expansions are not supported in WAD files (they are not
+ an editing feature for WAD authors to use).
+ - Support for these features can be completely disabled using the
+ `-strictdemos` command line argument.
+ - A warning is shown to the user on the console (stdout) when a
+ demo using one of these features is recorded or played back.
A good litmus test of when it’s acceptable to break from Vanilla
behavior is to ask the question: “Although this is Vanilla behavior,
--- a/README.md
+++ b/README.md
@@ -101,4 +101,4 @@
file for more information.
* Please send any feedback, questions or suggestions to
- [email protected]. Thanks!
+ [email protected]. Thanks!
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,5 @@
-AC_INIT(Chocolate Doom, 2.2.1, [email protected], chocolate-doom)
+AC_INIT(Chocolate Doom, 2.2.1, [email protected],
+ chocolate-doom)
PACKAGE_SHORTNAME=${PACKAGE_NAME% Doom}
PACKAGE_SHORTDESC="Conservative source port"
--- a/src/d_iwad.c
+++ b/src/d_iwad.c
@@ -459,13 +459,15 @@
static char *CheckDirectoryHasIWAD(char *dir, char *iwadname)
{
char *filename;
+ char *probe;
// As a special case, the "directory" may refer directly to an
// IWAD file if the path comes from DOOMWADDIR or DOOMWADPATH.
- if (DirIsFile(dir, iwadname) && M_FileExists(dir))
+ probe = M_FileCaseExists(dir);
+ if (DirIsFile(dir, iwadname) && probe != NULL)
{
- return M_StringDuplicate(dir);
+ return probe;
}
// Construct the full path to the IWAD if it is located in
@@ -480,9 +482,10 @@
filename = M_StringJoin(dir, DIR_SEPARATOR_S, iwadname, NULL);
}
- if (M_FileExists(filename))
+ probe = M_FileCaseExists(filename);
+ if (probe != NULL)
{
- return filename;
+ return probe;
}
free(filename);
@@ -709,13 +712,15 @@
char *D_FindWADByName(char *name)
{
char *path;
+ char *probe;
int i;
// Absolute path?
- if (M_FileExists(name))
+ probe = M_FileCaseExists(name);
+ if (probe != NULL)
{
- return name;
+ return probe;
}
BuildIWADDirList();
@@ -728,9 +733,10 @@
// the "directory" may actually refer directly to an IWAD
// file.
- if (DirIsFile(iwad_dirs[i], name) && M_FileExists(iwad_dirs[i]))
+ probe = M_FileCaseExists(iwad_dirs[i]);
+ if (DirIsFile(iwad_dirs[i], name) && probe != NULL)
{
- return M_StringDuplicate(iwad_dirs[i]);
+ return probe;
}
// Construct a string for the full path
@@ -737,9 +743,10 @@
path = M_StringJoin(iwad_dirs[i], DIR_SEPARATOR_S, name, NULL);
- if (M_FileExists(path))
+ probe = M_FileCaseExists(path);
+ if (probe != NULL)
{
- return path;
+ return probe;
}
free(path);
--- a/src/d_loop.c
+++ b/src/d_loop.c
@@ -816,3 +816,85 @@
{
loop_interface = i;
}
+
+// TODO: Move nonvanilla demo functions into a dedicated file.
+#include "m_misc.h"
+#include "w_wad.h"
+
+static boolean StrictDemos(void)
+{
+ //!
+ // @category demo
+ //
+ // When recording or playing back demos, disable any extensions
+ // of the vanilla demo format - record demos as vanilla would do,
+ // and play back demos as vanilla would do.
+ //
+ return M_ParmExists("-strictdemos");
+}
+
+// If the provided conditional value is true, we're trying to record
+// a demo file that will include a non-vanilla extension. The function
+// will return true if the conditional is true and it's allowed to use
+// this extension (no extensions are allowed if -strictdemos is given
+// on the command line). A warning is shown on the console using the
+// provided string describing the non-vanilla expansion.
+boolean D_NonVanillaRecord(boolean conditional, char *feature)
+{
+ if (!conditional || StrictDemos())
+ {
+ return false;
+ }
+
+ printf("Warning: Recording a demo file with a non-vanilla extension "
+ "(%s). Use -strictdemos to disable this extension.\n",
+ feature);
+
+ return true;
+}
+
+// Returns true if the given lump number corresponds to data from a .lmp
+// file, as opposed to a WAD.
+static boolean IsDemoFile(int lumpnum)
+{
+ char *lower;
+ boolean result;
+
+ lower = M_StringDuplicate(lumpinfo[lumpnum]->wad_file->path);
+ M_ForceLowercase(lower);
+ result = M_StringEndsWith(lower, ".lmp");
+ free(lower);
+
+ return result;
+}
+
+// If the provided conditional value is true, we're trying to play back
+// a demo that includes a non-vanilla extension. We return true if the
+// conditional is true and it's allowed to use this extension, checking
+// that:
+// - The -strictdemos command line argument is not provided.
+// - The given lumpnum identifying the demo to play back identifies a
+// demo that comes from a .lmp file, not a .wad file.
+// - Before proceeding, a warning is shown to the user on the console.
+boolean D_NonVanillaPlayback(boolean conditional, int lumpnum,
+ char *feature)
+{
+ if (!conditional || StrictDemos())
+ {
+ return false;
+ }
+
+ if (!IsDemoFile(lumpnum))
+ {
+ printf("Warning: WAD contains demo with a non-vanilla extension "
+ "(%s)\n", feature);
+ return false;
+ }
+
+ printf("Warning: Playing back a demo file with a non-vanilla extension "
+ "(%s). Use -strictdemos to disable this extension.\n",
+ feature);
+
+ return true;
+}
+
--- a/src/d_loop.h
+++ b/src/d_loop.h
@@ -77,5 +77,12 @@
extern boolean singletics;
extern int gametic, ticdup;
+// Check if it is permitted to record a demo with a non-vanilla feature.
+boolean D_NonVanillaRecord(boolean conditional, char *feature);
+
+// Check if it is permitted to play back a demo with a non-vanilla feature.
+boolean D_NonVanillaPlayback(boolean conditional, int lumpnum,
+ char *feature);
+
#endif
--- a/src/doom/d_main.c
+++ b/src/doom/d_main.c
@@ -1438,19 +1438,6 @@
D_IdentifyVersion();
InitGameVersion();
- //!
- // @category mod
- //
- // Disable automatic loading of Dehacked patches for certain
- // IWAD files.
- //
- if (!M_ParmExists("-nodeh"))
- {
- // Some IWADs have dehacked patches that need to be loaded for
- // them to be played properly.
- LoadIwadDeh();
- }
-
// Check which IWAD variant we are using.
if (W_CheckNumForName("FREEDOOM") >= 0)
@@ -1467,6 +1454,19 @@
else if (W_CheckNumForName("DMENUPIC") >= 0)
{
gamevariant = bfgedition;
+ }
+
+ //!
+ // @category mod
+ //
+ // Disable automatic loading of Dehacked patches for certain
+ // IWAD files.
+ //
+ if (!M_ParmExists("-nodeh"))
+ {
+ // Some IWADs have dehacked patches that need to be loaded for
+ // them to be played properly.
+ LoadIwadDeh();
}
// Doom 3: BFG Edition includes modified versions of the classic
--- a/src/doom/g_game.c
+++ b/src/doom/g_game.c
@@ -2056,6 +2056,8 @@
{
int i;
+ demo_p = demobuffer;
+
//!
// @category demo
//
@@ -2062,16 +2064,12 @@
// Record a high resolution "Doom 1.91" demo.
//
- longtics = M_CheckParm("-longtics") != 0;
+ longtics = D_NonVanillaRecord(M_ParmExists("-longtics"),
+ "Doom 1.91 demo format");
// If not recording a longtics demo, record in low res
-
lowres_turn = !longtics;
-
- demo_p = demobuffer;
-
- // Save the right version code for this demo
-
+
if (longtics)
{
*demo_p++ = DOOM_191_VERSION;
@@ -2127,6 +2125,8 @@
return "v1.8";
case 109:
return "v1.9";
+ case 111:
+ return "v1.91 hack demo?";
default:
break;
}
@@ -2146,27 +2146,29 @@
}
}
-void G_DoPlayDemo (void)
-{
- skill_t skill;
- int i, episode, map;
+void G_DoPlayDemo (void)
+{
+ skill_t skill;
+ int i, lumpnum, episode, map;
int demoversion;
-
- gameaction = ga_nothing;
- demobuffer = demo_p = W_CacheLumpName (defdemoname, PU_STATIC);
+ lumpnum = W_GetNumForName(defdemoname);
+ gameaction = ga_nothing;
+ demobuffer = W_CacheLumpNum(lumpnum, PU_STATIC);
+ demo_p = demobuffer;
+
demoversion = *demo_p++;
- if (demoversion == G_VanillaVersionCode())
+ longtics = false;
+
+ // Longtics demos use the modified format that is generated by cph's
+ // hacked "v1.91" doom exe. This is a non-vanilla extension.
+ if (D_NonVanillaPlayback(demoversion == DOOM_191_VERSION, lumpnum,
+ "Doom 1.91 demo format"))
{
- longtics = false;
- }
- else if (demoversion == DOOM_191_VERSION)
- {
- // demo recorded with cph's modified "v1.91" doom exe
longtics = true;
}
- else
+ else if (demoversion != G_VanillaVersionCode())
{
char *message = "Demo is from a different game version!\n"
"(read %i, should be %i)\n"
@@ -2180,7 +2182,7 @@
I_Error(message, demoversion, G_VanillaVersionCode(),
DemoVersionDescription(demoversion));
}
-
+
skill = *demo_p++;
episode = *demo_p++;
map = *demo_p++;
--- a/src/heretic/g_game.c
+++ b/src/heretic/g_game.c
@@ -1790,7 +1790,8 @@
// Record or playback a demo with high resolution turning.
//
- longtics = M_ParmExists("-longtics");
+ longtics = D_NonVanillaRecord(M_ParmExists("-longtics"),
+ "vvHeretic longtics demo");
// If not recording a longtics demo, record in low res
@@ -1836,7 +1837,7 @@
// 0x02 = -nomonsters
*demo_p = 1; // assume player one exists
- if (respawnparm)
+ if (D_NonVanillaRecord(respawnparm, "vvHeretic -respawn header flag"))
{
*demo_p |= DEMOHEADER_RESPAWN;
}
@@ -1844,7 +1845,7 @@
{
*demo_p |= DEMOHEADER_LONGTICS;
}
- if (nomonsters)
+ if (D_NonVanillaRecord(nomonsters, "vvHeretic -nomonsters header flag"))
{
*demo_p |= DEMOHEADER_NOMONSTERS;
}
@@ -1876,21 +1877,34 @@
void G_DoPlayDemo(void)
{
skill_t skill;
- int i, episode, map;
+ int i, lumpnum, episode, map;
gameaction = ga_nothing;
- demobuffer = demo_p = W_CacheLumpName(defdemoname, PU_STATIC);
+ lumpnum = W_GetNumForName(defdemoname);
+ demobuffer = W_CacheLumpNum(lumpnum, PU_STATIC);
+ demo_p = demobuffer;
skill = *demo_p++;
episode = *demo_p++;
map = *demo_p++;
- // Read special parameter bits: see G_RecordDemo() for details.
- longtics = (*demo_p & DEMOHEADER_LONGTICS) != 0;
+ // vvHeretic allows extra options to be stored in the upper bits of
+ // the player 1 present byte. However, this is a non-vanilla extension.
+ if (D_NonVanillaPlayback((*demo_p & DEMOHEADER_LONGTICS) != 0,
+ lumpnum, "vvHeretic longtics demo"))
+ {
+ longtics = true;
+ }
+ if (D_NonVanillaPlayback((*demo_p & DEMOHEADER_RESPAWN) != 0,
+ lumpnum, "vvHeretic -respawn header flag"))
+ {
+ respawnparm = true;
+ }
+ if (D_NonVanillaPlayback((*demo_p & DEMOHEADER_NOMONSTERS) != 0,
+ lumpnum, "vvHeretic -nomonsters header flag"))
+ {
+ nomonsters = true;
+ }
- // don't overwrite arguments from the command line
- respawnparm |= (*demo_p & DEMOHEADER_RESPAWN) != 0;
- nomonsters |= (*demo_p & DEMOHEADER_NOMONSTERS) != 0;
-
for (i = 0; i < MAXPLAYERS; i++)
playeringame[i] = (*demo_p++) != 0;
@@ -1921,9 +1935,11 @@
map = *demo_p++;
// Read special parameter bits: see G_RecordDemo() for details.
- respawnparm = (*demo_p & DEMOHEADER_RESPAWN) != 0;
- longtics = (*demo_p & DEMOHEADER_LONGTICS) != 0;
- nomonsters = (*demo_p & DEMOHEADER_NOMONSTERS) != 0;
+ longtics = (*demo_p & DEMOHEADER_LONGTICS) != 0;
+
+ // don't overwrite arguments from the command line
+ respawnparm |= (*demo_p & DEMOHEADER_RESPAWN) != 0;
+ nomonsters |= (*demo_p & DEMOHEADER_NOMONSTERS) != 0;
for (i = 0; i < MAXPLAYERS; i++)
{
--- a/src/hexen/g_game.c
+++ b/src/hexen/g_game.c
@@ -312,13 +312,13 @@
{
forward -= forwardmove[pClass][speed];
}
- if (gamekeydown[key_straferight] || joystrafemove > 0
- || joybuttons[joybstraferight])
+ if (gamekeydown[key_straferight] || mousebuttons[mousebstraferight]
+ || joystrafemove > 0 || joybuttons[joybstraferight])
{
side += sidemove[pClass][speed];
}
- if (gamekeydown[key_strafeleft] || joystrafemove < 0
- || joybuttons[joybstrafeleft])
+ if (gamekeydown[key_strafeleft] || mousebuttons[mousebstrafeleft]
+ || joystrafemove < 0 || joybuttons[joybstrafeleft])
{
side -= sidemove[pClass][speed];
}
@@ -504,57 +504,66 @@
{
forward += forwardmove[pClass][speed];
}
+ if (mousebuttons[mousebbackward])
+ {
+ forward -= forwardmove[pClass][speed];
+ }
-//
-// forward double click
-//
- if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1)
+ // Double click to use can be disabled
+
+ if (dclick_use)
{
- dclickstate = mousebuttons[mousebforward];
- if (dclickstate)
- dclicks++;
- if (dclicks == 2)
+ //
+ // forward double click
+ //
+ if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1)
{
- cmd->buttons |= BT_USE;
- dclicks = 0;
+ dclickstate = mousebuttons[mousebforward];
+ if (dclickstate)
+ dclicks++;
+ if (dclicks == 2)
+ {
+ cmd->buttons |= BT_USE;
+ dclicks = 0;
+ }
+ else
+ dclicktime = 0;
}
else
- dclicktime = 0;
- }
- else
- {
- dclicktime += ticdup;
- if (dclicktime > 20)
{
- dclicks = 0;
- dclickstate = 0;
+ dclicktime += ticdup;
+ if (dclicktime > 20)
+ {
+ dclicks = 0;
+ dclickstate = 0;
+ }
}
- }
-//
-// strafe double click
-//
- bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe];
- if (bstrafe != dclickstate2 && dclicktime2 > 1)
- {
- dclickstate2 = bstrafe;
- if (dclickstate2)
- dclicks2++;
- if (dclicks2 == 2)
+ //
+ // strafe double click
+ //
+ bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe];
+ if (bstrafe != dclickstate2 && dclicktime2 > 1)
{
- cmd->buttons |= BT_USE;
- dclicks2 = 0;
+ dclickstate2 = bstrafe;
+ if (dclickstate2)
+ dclicks2++;
+ if (dclicks2 == 2)
+ {
+ cmd->buttons |= BT_USE;
+ dclicks2 = 0;
+ }
+ else
+ dclicktime2 = 0;
}
else
- dclicktime2 = 0;
- }
- else
- {
- dclicktime2 += ticdup;
- if (dclicktime2 > 20)
{
- dclicks2 = 0;
- dclickstate2 = 0;
+ dclicktime2 += ticdup;
+ if (dclicktime2 > 20)
+ {
+ dclicks2 = 0;
+ dclickstate2 = 0;
+ }
}
}
@@ -1949,7 +1958,8 @@
// Record or playback a demo with high resolution turning.
//
- longtics = M_ParmExists("-longtics");
+ longtics = D_NonVanillaRecord(M_ParmExists("-longtics"),
+ "vvHeretic longtics demo");
// If not recording a longtics demo, record in low res
@@ -1996,7 +2006,7 @@
// 0x02 = -nomonsters
*demo_p = 1; // assume player one exists
- if (respawnparm)
+ if (D_NonVanillaRecord(respawnparm, "vvHeretic -respawn header flag"))
{
*demo_p |= DEMOHEADER_RESPAWN;
}
@@ -2004,7 +2014,7 @@
{
*demo_p |= DEMOHEADER_LONGTICS;
}
- if (nomonsters)
+ if (D_NonVanillaRecord(nomonsters, "vvHeretic -nomonsters header flag"))
{
*demo_p |= DEMOHEADER_NOMONSTERS;
}
@@ -2040,21 +2050,37 @@
void G_DoPlayDemo(void)
{
skill_t skill;
- int i, episode, map;
+ int i, lumpnum, episode, map;
gameaction = ga_nothing;
- demobuffer = demo_p = W_CacheLumpName(defdemoname, PU_STATIC);
+ lumpnum = W_GetNumForName(defdemoname);
+ demobuffer = W_CacheLumpNum(lumpnum, PU_STATIC);
+ demo_p = demobuffer;
skill = *demo_p++;
episode = *demo_p++;
map = *demo_p++;
- // Read special parameter bits: see G_RecordDemo() for details.
- longtics = (*demo_p & DEMOHEADER_LONGTICS) != 0;
+ // When recording we store some extra options inside the upper bits
+ // of the player 1 present byte. However, this is a non-vanilla extension.
+ // Note references to vvHeretic here; these are the extensions used by
+ // vvHeretic, which we're just reusing for Hexen demos too. There is no
+ // vvHexen.
+ if (D_NonVanillaPlayback((*demo_p & DEMOHEADER_LONGTICS) != 0,
+ lumpnum, "vvHeretic longtics demo"))
+ {
+ longtics = true;
+ }
+ if (D_NonVanillaPlayback((*demo_p & DEMOHEADER_RESPAWN) != 0,
+ lumpnum, "vvHeretic -respawn header flag"))
+ {
+ respawnparm = true;
+ }
+ if (D_NonVanillaPlayback((*demo_p & DEMOHEADER_NOMONSTERS) != 0,
+ lumpnum, "vvHeretic -nomonsters header flag"))
+ {
+ nomonsters = true;
+ }
- // don't overwrite arguments from the command line
- respawnparm |= (*demo_p & DEMOHEADER_RESPAWN) != 0;
- nomonsters |= (*demo_p & DEMOHEADER_NOMONSTERS) != 0;
-
for (i = 0; i < maxplayers; i++)
{
playeringame[i] = (*demo_p++) != 0;
@@ -2091,9 +2117,11 @@
map = *demo_p++;
// Read special parameter bits: see G_RecordDemo() for details.
- respawnparm = (*demo_p & DEMOHEADER_RESPAWN) != 0;
- longtics = (*demo_p & DEMOHEADER_LONGTICS) != 0;
- nomonsters = (*demo_p & DEMOHEADER_NOMONSTERS) != 0;
+ longtics = (*demo_p & DEMOHEADER_LONGTICS) != 0;
+
+ // don't overwrite arguments from the command line
+ respawnparm |= (*demo_p & DEMOHEADER_RESPAWN) != 0;
+ nomonsters |= (*demo_p & DEMOHEADER_NOMONSTERS) != 0;
for (i = 0; i < maxplayers; i++)
{
--- a/src/hexen/p_acs.c
+++ b/src/hexen/p_acs.c
@@ -56,8 +56,6 @@
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
-void CheckACSPresent(int number);
-
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void StartOpenACS(int number, int infoIndex, int *address);
--- a/src/hexen/sv_save.c
+++ b/src/hexen/sv_save.c
@@ -3299,10 +3299,11 @@
{
I_Error ("Couldn't read file %s", source_name);
}
+
write_count = fwrite(buffer, 1, buf_count, write_handle);
- if (read_count < buf_count)
+ if (write_count < buf_count)
{
- I_Error ("Couldn't read file %s", dest_name);
+ I_Error ("Couldn't write to file %s", dest_name);
}
file_remaining -= buf_count;
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -83,6 +83,75 @@
}
}
+// Check if a file exists by probing for common case variation of its filename.
+// Returns a newly allocated string that the caller is responsible for freeing.
+
+char *M_FileCaseExists(char *path)
+{
+ char *path_dup, *filename, *ext;
+
+ path_dup = M_StringDuplicate(path);
+
+ // 0: actual path
+ if (M_FileExists(path_dup))
+ {
+ return path_dup;
+ }
+
+ filename = strrchr(path_dup, DIR_SEPARATOR);
+ if (filename != NULL)
+ {
+ filename++;
+ }
+ else
+ {
+ filename = path_dup;
+ }
+
+ // 1: lowercase filename, e.g. doom2.wad
+ M_ForceLowercase(filename);
+
+ if (M_FileExists(path_dup))
+ {
+ return path_dup;
+ }
+
+ // 2: uppercase filename, e.g. DOOM2.WAD
+ M_ForceUppercase(filename);
+
+ if (M_FileExists(path_dup))
+ {
+ return path_dup;
+ }
+
+ // 3. uppercase basename with lowercase extension, e.g. DOOM2.wad
+ ext = strrchr(path_dup, '.');
+ if (ext != NULL && ext > filename)
+ {
+ M_ForceLowercase(ext + 1);
+
+ if (M_FileExists(path_dup))
+ {
+ return path_dup;
+ }
+ }
+
+ // 4. lowercase filename with uppercase first letter, e.g. Doom2.wad
+ if (strlen(filename) > 1)
+ {
+ M_ForceLowercase(filename + 1);
+
+ if (M_FileExists(path_dup))
+ {
+ return path_dup;
+ }
+ }
+
+ // 5. no luck
+ free(path_dup);
+ return NULL;
+}
+
//
// Determine the length of an open file.
//
@@ -247,6 +316,24 @@
for (p = text; *p != '\0'; ++p)
{
*p = toupper(*p);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC M_ForceLowercase
+//
+// Change string to lowercase.
+//
+//---------------------------------------------------------------------------
+
+void M_ForceLowercase(char *text)
+{
+ char *p;
+
+ for (p = text; *p != '\0'; ++p)
+ {
+ *p = tolower(*p);
}
}
--- a/src/m_misc.h
+++ b/src/m_misc.h
@@ -30,10 +30,12 @@
void M_MakeDirectory(char *dir);
char *M_TempFile(char *s);
boolean M_FileExists(char *file);
+char *M_FileCaseExists(char *file);
long M_FileLength(FILE *handle);
boolean M_StrToInt(const char *str, int *result);
void M_ExtractFileBase(char *path, char *dest);
void M_ForceUppercase(char *text);
+void M_ForceLowercase(char *text);
char *M_StrCaseStr(char *haystack, char *needle);
char *M_StringDuplicate(const char *orig);
boolean M_StringCopy(char *dest, const char *src, size_t dest_size);
--- a/src/w_file.h
+++ b/src/w_file.h
@@ -28,35 +28,31 @@
typedef struct
{
// Open a file for reading.
-
wad_file_t *(*OpenFile)(char *path);
// Close the specified file.
-
void (*CloseFile)(wad_file_t *file);
// Read data from the specified position in the file into the
// provided buffer. Returns the number of bytes read.
-
size_t (*Read)(wad_file_t *file, unsigned int offset,
void *buffer, size_t buffer_len);
-
} wad_file_class_t;
struct _wad_file_s
{
// Class of this file.
-
wad_file_class_t *file_class;
// If this is NULL, the file cannot be mapped into memory. If this
// is non-NULL, it is a pointer to the mapped file.
-
byte *mapped;
// Length of the file, in bytes.
-
unsigned int length;
+
+ // File's location on disk.
+ const char *path;
};
// Open the specified file. Returns a pointer to a new wad_file_t
--- a/src/w_file_posix.c
+++ b/src/w_file_posix.c
@@ -26,6 +26,7 @@
#include <sys/mman.h>
#include <string.h>
+#include "m_misc.h"
#include "w_file.h"
#include "z_zone.h"
@@ -90,6 +91,7 @@
result = Z_Malloc(sizeof(posix_wad_file_t), PU_STATIC, 0);
result->wad.file_class = &posix_wad_file;
result->wad.length = GetFileLength(handle);
+ result->wad.path = M_StringDuplicate(path);
result->handle = handle;
// Try to map the file into memory with mmap:
--- a/src/w_file_stdc.c
+++ b/src/w_file_stdc.c
@@ -48,6 +48,7 @@
result->wad.file_class = &stdc_wad_file;
result->wad.mapped = NULL;
result->wad.length = M_FileLength(fstream);
+ result->wad.path = M_StringDuplicate(path);
result->fstream = fstream;
return &result->wad;
--- a/src/w_file_win32.c
+++ b/src/w_file_win32.c
@@ -26,6 +26,7 @@
#include <windows.h>
#include "i_system.h"
+#include "m_misc.h"
#include "w_file.h"
#include "z_zone.h"
@@ -115,6 +116,7 @@
result = Z_Malloc(sizeof(win32_wad_file_t), PU_STATIC, 0);
result->wad.file_class = &win32_wad_file;
result->wad.length = GetFileLength(handle);
+ result->wad.path = M_StringDuplicate(path);
result->handle = handle;
// Try to map the file into memory with mmap: