]> git.0x19.co - doomgeneric-snom360/commitdiff
Upgraded to chocolate-doom port instead
authorMaxime Vincent <maxime.vince@gmail.com>
Mon, 23 May 2016 13:26:13 +0000 (15:26 +0200)
committerMaxime Vincent <maxime.vince@gmail.com>
Mon, 23 May 2016 13:26:13 +0000 (15:26 +0200)
205 files changed:
frosted-doom/CVS/Entries [deleted file]
frosted-doom/CVS/Repository [deleted file]
frosted-doom/CVS/Root [deleted file]
frosted-doom/ChangeLog [deleted file]
frosted-doom/DOOMLIC.TXT [deleted file]
frosted-doom/FILES [deleted file]
frosted-doom/FILES2 [deleted file]
frosted-doom/Makefile
frosted-doom/README.asm [deleted file]
frosted-doom/README.b [deleted file]
frosted-doom/README.book [deleted file]
frosted-doom/README.gl [deleted file]
frosted-doom/README.sound [deleted file]
frosted-doom/TODO [deleted file]
frosted-doom/am_map.c
frosted-doom/am_map.h
frosted-doom/compat/values.h [deleted file]
frosted-doom/config.h [new file with mode: 0644]
frosted-doom/d_englsh.h
frosted-doom/d_event.c [new file with mode: 0644]
frosted-doom/d_event.h
frosted-doom/d_french.h [deleted file]
frosted-doom/d_items.c
frosted-doom/d_items.h
frosted-doom/d_iwad.c [new file with mode: 0644]
frosted-doom/d_iwad.h [new file with mode: 0644]
frosted-doom/d_loop.c [new file with mode: 0644]
frosted-doom/d_loop.h [new file with mode: 0644]
frosted-doom/d_main.c
frosted-doom/d_main.h
frosted-doom/d_mode.c [new file with mode: 0644]
frosted-doom/d_mode.h [new file with mode: 0644]
frosted-doom/d_net.c
frosted-doom/d_net.h [deleted file]
frosted-doom/d_player.h
frosted-doom/d_textur.h
frosted-doom/d_think.h
frosted-doom/d_ticcmd.h
frosted-doom/deh_main.h [new file with mode: 0644]
frosted-doom/deh_misc.h [new file with mode: 0644]
frosted-doom/deh_str.h [new file with mode: 0644]
frosted-doom/doom.h [new file with mode: 0644]
frosted-doom/doomdata.h
frosted-doom/doomdef.c
frosted-doom/doomdef.h
frosted-doom/doomfeatures.h [new file with mode: 0644]
frosted-doom/doomkeys.h [new file with mode: 0644]
frosted-doom/doomstat.c
frosted-doom/doomstat.h
frosted-doom/doomtype.h
frosted-doom/dstrings.c
frosted-doom/dstrings.h
frosted-doom/dummy.c [new file with mode: 0644]
frosted-doom/f_finale.c
frosted-doom/f_finale.h
frosted-doom/f_wipe.c
frosted-doom/f_wipe.h
frosted-doom/g_game.c
frosted-doom/g_game.h
frosted-doom/gusconf.c [new file with mode: 0644]
frosted-doom/gusconf.h [new file with mode: 0644]
frosted-doom/hu_lib.c
frosted-doom/hu_lib.h
frosted-doom/hu_stuff.c
frosted-doom/hu_stuff.h
frosted-doom/i_cdmus.c [new file with mode: 0644]
frosted-doom/i_cdmus.h [new file with mode: 0644]
frosted-doom/i_endoom.c [new file with mode: 0644]
frosted-doom/i_endoom.h [new file with mode: 0644]
frosted-doom/i_joystick.c [new file with mode: 0644]
frosted-doom/i_joystick.h [new file with mode: 0644]
frosted-doom/i_main.c
frosted-doom/i_net.c [deleted file]
frosted-doom/i_net.h [deleted file]
frosted-doom/i_oplmusic.c [new file with mode: 0644]
frosted-doom/i_pcsound.c [new file with mode: 0644]
frosted-doom/i_scale.c [new file with mode: 0644]
frosted-doom/i_scale.h [new file with mode: 0644]
frosted-doom/i_sdlmusic.c [new file with mode: 0644]
frosted-doom/i_sdlsound.c [new file with mode: 0644]
frosted-doom/i_sound.c
frosted-doom/i_sound.h
frosted-doom/i_swap.h [new file with mode: 0644]
frosted-doom/i_system.c
frosted-doom/i_system.h
frosted-doom/i_timer.c [new file with mode: 0644]
frosted-doom/i_timer.h [new file with mode: 0644]
frosted-doom/i_video.c
frosted-doom/i_video.h
frosted-doom/i_video_SDL.c [deleted file]
frosted-doom/i_video_dummy.c [deleted file]
frosted-doom/i_video_fbdev.c
frosted-doom/icon.c [new file with mode: 0644]
frosted-doom/info.c
frosted-doom/info.h
frosted-doom/m_argv.c
frosted-doom/m_argv.h
frosted-doom/m_bbox.c
frosted-doom/m_bbox.h
frosted-doom/m_cheat.c
frosted-doom/m_cheat.h
frosted-doom/m_config.c [new file with mode: 0644]
frosted-doom/m_config.h [new file with mode: 0644]
frosted-doom/m_controls.c [new file with mode: 0644]
frosted-doom/m_controls.h [new file with mode: 0644]
frosted-doom/m_fixed.c
frosted-doom/m_fixed.h
frosted-doom/m_menu.c
frosted-doom/m_menu.h
frosted-doom/m_misc.c
frosted-doom/m_misc.h
frosted-doom/m_random.c
frosted-doom/m_random.h
frosted-doom/m_swap.c [deleted file]
frosted-doom/m_swap.h [deleted file]
frosted-doom/memio.c [new file with mode: 0644]
frosted-doom/memio.h [new file with mode: 0644]
frosted-doom/net_client.h [new file with mode: 0644]
frosted-doom/net_dedicated.h [new file with mode: 0644]
frosted-doom/net_defs.h [new file with mode: 0644]
frosted-doom/net_gui.h [new file with mode: 0644]
frosted-doom/net_io.h [new file with mode: 0644]
frosted-doom/net_loop.h [new file with mode: 0644]
frosted-doom/net_packet.h [new file with mode: 0644]
frosted-doom/net_query.h [new file with mode: 0644]
frosted-doom/net_sdl.h [new file with mode: 0644]
frosted-doom/net_server.h [new file with mode: 0644]
frosted-doom/p_ceilng.c
frosted-doom/p_doors.c
frosted-doom/p_enemy.c
frosted-doom/p_floor.c
frosted-doom/p_inter.c
frosted-doom/p_inter.h
frosted-doom/p_lights.c
frosted-doom/p_local.h
frosted-doom/p_map.c
frosted-doom/p_maputl.c
frosted-doom/p_mobj.c
frosted-doom/p_mobj.h
frosted-doom/p_plats.c
frosted-doom/p_pspr.c
frosted-doom/p_pspr.h
frosted-doom/p_saveg.c
frosted-doom/p_saveg.h
frosted-doom/p_setup.c
frosted-doom/p_setup.h
frosted-doom/p_sight.c
frosted-doom/p_spec.c
frosted-doom/p_spec.h
frosted-doom/p_switch.c
frosted-doom/p_telept.c
frosted-doom/p_tick.c
frosted-doom/p_tick.h
frosted-doom/p_user.c
frosted-doom/r_bsp.c
frosted-doom/r_bsp.h
frosted-doom/r_data.c
frosted-doom/r_data.h
frosted-doom/r_defs.h
frosted-doom/r_draw.c
frosted-doom/r_draw.h
frosted-doom/r_local.h
frosted-doom/r_main.c
frosted-doom/r_main.h
frosted-doom/r_plane.c
frosted-doom/r_plane.h
frosted-doom/r_segs.c
frosted-doom/r_segs.h
frosted-doom/r_sky.c
frosted-doom/r_sky.h
frosted-doom/r_state.h
frosted-doom/r_things.c
frosted-doom/r_things.h
frosted-doom/s_sound.c
frosted-doom/s_sound.h
frosted-doom/sha1.c [new file with mode: 0644]
frosted-doom/sha1.h [new file with mode: 0644]
frosted-doom/sounds.c
frosted-doom/sounds.h
frosted-doom/st_lib.c
frosted-doom/st_lib.h
frosted-doom/st_stuff.c
frosted-doom/st_stuff.h
frosted-doom/statdump.c [new file with mode: 0644]
frosted-doom/statdump.h [new file with mode: 0644]
frosted-doom/tables.c
frosted-doom/tables.h
frosted-doom/v_patch.h [new file with mode: 0644]
frosted-doom/v_video.c
frosted-doom/v_video.h
frosted-doom/w_checksum.c [new file with mode: 0644]
frosted-doom/w_checksum.h [new file with mode: 0644]
frosted-doom/w_file.c [new file with mode: 0644]
frosted-doom/w_file.h [new file with mode: 0644]
frosted-doom/w_file_stdc.c [new file with mode: 0644]
frosted-doom/w_file_stdc_unbuffered.c [new file with mode: 0644]
frosted-doom/w_main.c [new file with mode: 0644]
frosted-doom/w_main.h [new file with mode: 0644]
frosted-doom/w_merge.h [new file with mode: 0644]
frosted-doom/w_wad.c
frosted-doom/w_wad.h
frosted-doom/wi_stuff.c
frosted-doom/wi_stuff.h
frosted-doom/z_zone.c
frosted-doom/z_zone.h

diff --git a/frosted-doom/CVS/Entries b/frosted-doom/CVS/Entries
deleted file mode 100644 (file)
index f1f4112..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/ChangeLog/1.14/Mon Feb  3 22:45:08 1997//
-/DOOMLIC.TXT/1.3/Sun Jan 26 07:44:56 1997//
-/FILES/1.1/Sun Jan 19 17:22:41 1997//
-/FILES2/1.1/Sun Jan 19 17:22:42 1997//
-/Makefile/1.6/Mon Feb  3 22:45:08 1997//
-/am_data.h/1.2/Tue Jan 21 18:59:56 1997//
-/am_map.c/1.4/Mon Feb  3 21:24:33 1997//
-/am_map.h/1.2/Tue Jan 21 18:59:56 1997//
-/d_englsh.h/1.1/Mon Feb  3 21:48:03 1997//
-/d_event.h/1.2/Mon Feb  3 22:01:47 1997//
-/d_french.h/1.3/Mon Feb  3 21:48:03 1997//
-/d_main.c/1.8/Mon Feb  3 22:45:09 1997//
-/d_net.c/1.3/Mon Feb  3 22:01:47 1997//
-/d_textur.h/1.1/Mon Feb  3 16:47:51 1997//
-/doomdata.h/1.5/Mon Feb  3 22:45:09 1997//
-/doomdef.h/1.9/Mon Feb  3 22:45:09 1997//
-/doomtype.h/1.2/Mon Feb  3 22:45:09 1997//
-/dstrings.h/1.4/Mon Feb  3 21:48:03 1997//
-/dutils.c/1.5/Mon Feb  3 17:11:23 1997//
-/dutils.h/1.4/Mon Feb  3 17:11:23 1997//
-/f_finale.c/1.5/Mon Feb  3 21:26:34 1997//
-/f_finale.h/1.1/Mon Feb  3 21:26:34 1997//
-/f_wipe.c/1.2/Mon Feb  3 22:45:09 1997//
-/f_wipe.h/1.1/Mon Feb  3 17:11:23 1997//
-/fpfunc.S/1.1/Sun Jan 19 17:22:43 1997//
-/g_game.c/1.8/Mon Feb  3 22:45:09 1997//
-/g_game.h/1.1/Mon Feb  3 21:34:47 1997//
-/hu_lib.c/1.3/Sun Jan 26 07:44:58 1997//
-/hu_lib.h/1.4/Mon Feb  3 16:47:52 1997//
-/hu_stuff.c/1.4/Mon Feb  3 16:47:52 1997//
-/hu_stuff.h/1.3/Sun Jan 26 07:44:58 1997//
-/i_dga.c/1.3/Sun Jan 26 07:44:58 1997//
-/i_ibm.c/1.3/Sun Jan 26 07:44:58 1997//
-/i_main.c/1.4/Mon Feb  3 22:45:10 1997//
-/i_pcnet.c/1.3/Sun Jan 26 07:44:59 1997//
-/i_sound.c/1.3/Sun Jan 26 07:44:59 1997//
-/i_sound.h/1.3/Sun Jan 26 07:44:59 1997//
-/i_svga.c/1.3/Sun Jan 26 07:44:59 1997//
-/i_unix.c/1.5/Mon Feb  3 22:45:10 1997//
-/i_x.c/1.6/Mon Feb  3 22:45:10 1997//
-/info.c/1.3/Sun Jan 26 07:45:00 1997//
-/info.h/1.3/Sun Jan 26 07:45:00 1997//
-/irix.c/1.3/Sun Jan 26 07:45:00 1997//
-/irix.h/1.3/Sun Jan 26 07:45:01 1997//
-/linux.c/1.3/Sun Jan 26 07:45:01 1997//
-/m_argv.c/1.1/Mon Feb  3 22:45:10 1997//
-/m_argv.h/1.1/Mon Feb  3 22:45:10 1997//
-/m_bbox.c/1.1/Mon Feb  3 22:45:10 1997//
-/m_bbox.h/1.1/Mon Feb  3 22:45:10 1997//
-/m_cheat.c/1.1/Mon Feb  3 21:24:34 1997//
-/m_cheat.h/1.1/Mon Feb  3 21:24:34 1997//
-/m_menu.c/1.7/Mon Feb  3 22:45:10 1997//
-/m_menu.h/1.1/Mon Feb  3 22:01:49 1997//
-/m_misc.c/1.6/Mon Feb  3 22:45:10 1997//
-/m_misc.h/1.1/Mon Feb  3 22:45:11 1997//
-/m_random.c/1.1/Mon Feb  3 22:45:11 1997//
-/m_random.h/1.1/Mon Feb  3 22:45:11 1997//
-/p_ceilng.c/1.4/Mon Feb  3 16:47:53 1997//
-/p_doors.c/1.4/Mon Feb  3 16:47:53 1997//
-/p_enemy.c/1.5/Mon Feb  3 22:45:11 1997//
-/p_floor.c/1.4/Mon Feb  3 16:47:54 1997//
-/p_inter.c/1.4/Mon Feb  3 22:45:11 1997//
-/p_lights.c/1.5/Mon Feb  3 22:45:11 1997//
-/p_local.h/1.3/Tue Jan 28 22:08:27 1997//
-/p_map.c/1.5/Mon Feb  3 22:45:11 1997//
-/p_maputl.c/1.5/Mon Feb  3 22:45:11 1997//
-/p_mobj.c/1.5/Mon Feb  3 22:45:12 1997//
-/p_plats.c/1.5/Mon Feb  3 22:45:12 1997//
-/p_pspr.c/1.5/Mon Feb  3 22:45:12 1997//
-/p_setup.c/1.5/Mon Feb  3 22:45:12 1997//
-/p_sight.c/1.3/Tue Jan 28 22:08:28 1997//
-/p_spec.c/1.6/Mon Feb  3 22:45:12 1997//
-/p_spec.h/1.3/Tue Jan 28 22:08:29 1997//
-/p_switch.c/1.3/Tue Jan 28 22:08:29 1997//
-/p_telept.c/1.3/Tue Jan 28 22:08:29 1997//
-/p_tick.c/1.4/Mon Feb  3 16:47:55 1997//
-/p_user.c/1.3/Tue Jan 28 22:08:29 1997//
-/r_bsp.c/1.4/Mon Feb  3 22:45:12 1997//
-/r_data.c/1.4/Mon Feb  3 16:47:55 1997//
-/r_draw.c/1.4/Mon Feb  3 16:47:55 1997//
-/r_local.h/1.4/Mon Feb  3 21:26:34 1997//
-/r_main.c/1.5/Mon Feb  3 22:45:12 1997//
-/r_plane.c/1.4/Mon Feb  3 16:47:55 1997//
-/r_segs.c/1.3/Wed Jan 29 20:10:19 1997//
-/r_things.c/1.5/Mon Feb  3 16:47:56 1997//
-/s_sound.c/1.6/Mon Feb  3 22:45:12 1997//
-/sounds.c/1.3/Wed Jan 29 22:40:44 1997//
-/sounds.h/1.3/Wed Jan 29 22:40:44 1997//
-/soundsrv.c/1.3/Wed Jan 29 22:40:44 1997//
-/soundsrv.h/1.3/Wed Jan 29 22:40:44 1997//
-/soundst.h/1.3/Wed Jan 29 22:40:45 1997//
-/st_lib.c/1.4/Mon Feb  3 16:47:56 1997//
-/st_lib.h/1.4/Mon Feb  3 16:47:56 1997//
-/st_stuff.c/1.6/Mon Feb  3 22:45:13 1997//
-/st_stuff.h/1.3/Thu Jan 30 19:54:22 1997//
-/sun.c/1.3/Thu Jan 30 19:54:22 1997//
-/tables.c/1.4/Mon Feb  3 16:47:57 1997//
-/tables.h/1.1/Mon Feb  3 16:47:57 1997//
-/tmap.S/1.1/Sun Jan 19 17:22:51 1997//
-/v_video.c/1.5/Mon Feb  3 22:45:13 1997//
-/v_video.h/1.2/Mon Feb  3 17:11:59 1997//
-/w_wad.c/1.5/Mon Feb  3 16:47:57 1997//
-/wadread.c/1.3/Thu Jan 30 19:54:23 1997//
-/wadread.h/1.3/Thu Jan 30 19:54:23 1997//
-/wi_data.h/1.3/Thu Jan 30 19:54:23 1997//
-/wi_stuff.c/1.7/Mon Feb  3 22:45:13 1997//
-/wi_stuff.h/1.4/Mon Feb  3 16:47:58 1997//
-/z_zone.c/1.4/Mon Feb  3 16:47:58 1997//
-/z_zone.h/1.1/Mon Feb  3 16:47:58 1997//
diff --git a/frosted-doom/CVS/Repository b/frosted-doom/CVS/Repository
deleted file mode 100644 (file)
index fa03d7f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/info/cvsroot/id/id_doom
diff --git a/frosted-doom/CVS/Root b/frosted-doom/CVS/Root
deleted file mode 100644 (file)
index 41613f0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/info/cvsroot/
diff --git a/frosted-doom/ChangeLog b/frosted-doom/ChangeLog
deleted file mode 100644 (file)
index 717db2e..0000000
+++ /dev/null
@@ -1,922 +0,0 @@
-
-
-
-       * TODO: see below, and in the "TODO" file. Enjoy!
-
-Mon Dec 22 20:29:16 1997    <bk@gamers.org>
-
-       * CVS logs and other obsolete stuff removed. Anybody
-         who wants to keep some revision control now has a
-         clean slate to start with.
-
-Mon Dec 22 19:53:34 1997    <bk@gamers.org>
-
-       
-       * i_sound.c: enabled SNDSERV, as SNDINTR for
-         some reason just gives ghastly results e.g.
-         on E4M2. Frankly, I am at a loss. SNDSERV is
-         now default, until the internal sound driver
-         is a bit more reliable.
-         Note that the current redundancy means that
-         changes like the one below will have to 
-         be propagated manually to the soundserver
-         sources.
-
-       * m_menu.c: the 4th episode is now removed with
-         the original doom.wad. You need to rename the
-         Ultimate DOOM/Special Edition retail IWAD to
-         doomu.wad now, or you won't see the 4th episode
-         in the menu. The compile time SPECIAL define
-         is thus gone.
-
-Mon Dec 22 17:08:33 1997    <bk@gamers.org>
-
-       * v_video.c (V_DrawPatch): another last minute hack.
-         While shareware, retail, commercial, and plutonia
-         (being a full DOOM2 IWAD) seem to work okay now,
-         TNT gives an error on finishing the first mission:
-          "Patch at -35, -5 exceeds LFB".
-         I changed the error abort into a simple return,
-         thus the patch is ignored. The intermission screen
-         seems to come up okay.
-       * TODO: check which patch, and whether it is an IWAD
-         problem.
-
-       * i_sound.c: the sound table is hardwired in
-         sounds.h/sounds.c. As our current crude
-         sound handling simply loads *all* sounds at
-         startup, we are going to miss some with DOOM1
-         WAD files. I could skip them, but decided to
-         load a placeholder instead (dspistol). It might
-         be good to use a distinct default sound for
-         WAD debug purposes. A zero length sound lump
-         would work, but would not be noticeable.
-         Anyway, shareware and retail work now.
-       * TODO: implement proper handling for missing
-         lumps, sound and otherwise.
-         Perhaps move sound table into WAD?
-
-       * g_game.c (G_DoPlayDemo): finally removed the
-         annoying "Demo is from a different game version"
-         abort. It now simply declines to playback the
-         demo, and waits for user input on some
-         do_nothing screen.
-
-       * doomdef.h&Cie.: Lesson of the day - do not
-         replace a bunch of booleans with an enum and
-         use the same identifiers. Point in case:
-          "if ( commercial )" will not give an error,
-         and will always be true as long as the enum
-         value is greater than zero.
-         I found that the DOOM2 vs. DOOM differences
-         are everywhere (weapons, monsters, doors).
-         Number of episodes varies from shareware/commercial
-         to registered to retail, while commercial has
-         a unique set (two of them, counting the german
-         edition) of maps in one episode. Plus, TNT and
-         Plutonia add some TITLE strings to the mixture.
-         
-         Well, Plutonia and TNT are treated as DOOM2 for
-         now, so you will miss the startup message.
-
-       * wi_stuff.h (NUMEPISODES): removed SPECIAL switch.
-         It is no 4 times 9 for wi_stuff.c internal
-         static arrays - doesn't matter.
-       * TODO: unified handling with DOOM 2 - dynamic
-         allocation of arrays.
-
-       * i_sound.c (I_UpdateSound): okay, I separated
-         the mixing, now done synchonously, along with
-         a flag signalling the timer that the mixing buffer
-         has been updated. The handler is now very short,
-         and I tried several intervals down to 50usecs,
-         w/o complaints. Now the man page says:
-          "system timer resolution currently 10ms". Odd.
-         Anyway, while the double shotgun/plasma rapid
-         fire problem seems to be a bit less disturbing
-         at higher refresh, it's still there. I set the
-         interval to 500usec, which is sufficient for
-         avoiding any buffer update misses.
-         Conclusion after just two days of experimentation:
-         yep, sound driver code isn't fun at all.
-
-         As for the bug - well, Dave Taylor suggested
-         close distance getting into a divide-by-near-zero
-         situation, screwing up the volume. I can't figure
-         why latency of an external sound driver or screen
-         size affect this, but I am running out of ideas.
-       
-       * i_sound.c: 
-         Some more experimentation with the timer driven
-         sound. It doesn't work well using an intervall
-         of less then 30 msecs - there will be artifacts
-         with say 50 msecs. This is pretty obvious with
-         a target frame rate of at least 30fps, methinks.
-         Using the REAL/SIGALRM timer with 30msec gets
-         rid of the artifacts, it seems - at the expense
-         of slowing down things on a P133 to a noticeable
-         jerkiness. Bah.
-
-Mon Dec 22 00:36:54 1997    <bk@gamers.org>
-
-       * info.c: and i_video.c and i_sound.c - don't ask
-         me why some Linux header files are different with
-         gcc vs. g++, or what the complaint about the g++
-         complaint info.c state table is all about:
-         "initializer element for `states[..].action.acp1' 
-          is not constant"
-         Undid some changes, compiled with gcc, playtested,
-         seems okay. Done for today... yesterday.
-
-       * i_net.c (ntohl): okay, htons/htonl, ntohs,ntohl 
-         are back to haunt me. Copied the macros that
-         on my box aren't used for whatever reason directly
-         into the source. Got rid of all other multiple and
-         undefined references. CC=g++ now compiles (still
-         many warnings) and links, but the binary dumps a
-         core after Init PlayLoop. So be it.
-
-Sun Dec 21 12:38:08 1997    <bk@gamers.org>
-
-       * p_enemy.c (P_NewChaseDir): changed tdir to int,
-         removed the LUTs - spurious locks were due to
-         endless loops created by boneheaded predecessor
-         map. Has to be a better way to do enum dirtype_t
-         anyway. Problem seems to be fixed.
-
-       * CC=gcc again, this time loads of #includes to
-         fix "implicit declarations, and one or two
-         unused variables. DOOM now compiles without
-         any -Wall warnings left, as C.
-
-       * Bug: compiled the reworked code with gcc. Within a
-         solid while of testing and blasting away, it
-         locked once. Got a core, which gdb doesn't grok.
-         Bah.
-
-       * TODO: okay, linkage of g++ build modules give loads
-         of errors, because we have many implicits, plus
-         missing #pragma implementation causing multiple
-         definitions. Yet, this is the very first time DOOM
-         was compiled as C++ without a parsing error. So there.
-       
-       * sounds.c: included doomtype.h and removed yet another
-                   enum { false, true } definition.
-
-       * p_saveg.c  (misc): several. 
-       * p_mobj.c   (P_SpawnMobj): (actionf_p1)P_MobjThinker
-       * p_spec.c   (EV_DoDonut): (action_p1) T_MoveFloor (twice).
-       * p_plats.c  (EV_DoPlat): (actionf_p1) T_PlatRaise.
-       * p_plats.c  (EV_StopPlat): (actionf_v)NULL.
-       * p_plats.c  (P_ActivateInStasis): same
-       * p_lights.c (P_SpawnGlowingLight): (actionf_p1) T_Glow.
-       * p_lights.c (P_SpawnStrobeFlash): (actionf_p1) T_StrobeFlash.
-       * p_lights.c (P_SpawnLightFlash): (actionf_p1) T_LightFlash.
-       * p_lights.c (P_SpawnFireFlicker): (actionf_p1) T_FireFlicker.
-       * p_floor.c  (EV_DoFloor): (actionf_p1) T_MoveFloor.
-       * p_floor.c  (EV_BuildStairs): same (twice).
-       * p_doors.c  (EV_VerticalDoor): (actionf_p1)T_VerticalDoor.
-       * p_doors.c  (P_SpawnDoorCloseIn30): same
-       * p_doors.c  (P_SpawnDoorRaiseIn5Mins): same
-       * p_doors.c  (EV_DoDoor): same
-       * p_ceilng.c (EV_CeilingCrushStop): (actionf_v)NULL.
-       * p_ceilng.c (EV_DoCeiling): (actionf_p1)T_MoveCeiling.
-       * p_ceilng.c (P_ActivateInStasisCeiling): same.
-         These gave g++ errors, but  have been ignored by gcc.
-
-       * r_data.c (R_PrecacheLevel): (actionf_p1)P_MobjThinker.
-
-       * p_saveg.c:  conversions (actionf_p1)T_Whatever.
-
-       * p_tick.c: cast (actionf_v)(-1).
-
-       * p_telept.c: yet another (actionf_p1)P_MobjThinker.
-       
-       * p_mobj.c (P_MobjThinker): cast (actionf_v)(-1).
-       * TODO:  decent NOP/NULL/Nil function pointer.
-         I'd introduce a global A_NOP() function that
-         chokes up an error message. 
-         Why -1 instead of NULL?
-
-       * p_enemy.c: conversions (actionf_p1)P_MobjThinker.
-
-       * d_think.h/info.h:  think_t is essentially
-         the same action function pointer stuff.
-         I moved the definitions from info.h to
-         d_think.h, and aliased them with a typedef.
-         Now more changes needed.
-
-       * p_enemy.c (successor, predecessor): new LUT,
-         to provide increments/decrements for enum
-         dirtype_t, as g++ complaints:
-         "no post-increment/decrement operator for type"
-
-       * Makefile (CC): okay, tried "g++" once more.
-         A few errors (above). Plus shitloads of warnings
-         (obviously, better "unused" checking with C++,
-          lots of the usual int2enum suspects, implicit
-          declarations, the works).
-        
-
-       * p_mobj.c: action.acp1 used accordingly.
-       * p_pspr.c: action.acp2 used accordingly.
-       * TODO: info.c:144 warning
-         "missing braces around initializer for `states[0].action'"
-       
-       * info.h/info.c: some experimental stuff on
-         action function pointers.
-         
-       * TODO: still some sound glitches at startup.
-       * i_sound.c: few more cleanups. Made mixing use
-         channel loop instead of unroll, set mixbuffer
-         to zero ot start.
-         Removed some more DOS leftovers (8bit),
-         kept some as comment.
-
-       * hu_stuff.c (HU_Start):
-         More gamemode changes. As in d_main.c, I
-         decided to use DOOM2 as default whenever
-         one needed - it was sold most, and had the
-         superset of items, enemies and monsters.
-
-       * TODO: the handling of WAD specific messages
-         like HU_TITLE, HU_TITLE2, HU_TITLEP etc.
-         should definitely be removed.
-
-       * d_main.c (CheckBetaTest): 
-         Removed outdated, DOS specific BETATEST stuff.
-         d_main.c (IdentifyVersion):
-         Numerous changes to gamemode handling. 
-
-       * TODO: currently, french language is enabled by
-         detecting an doom2f.wad - yet it needs FRENCH
-         define at compile time. I removed most language
-         stuff, and propose handling that at runtime,
-         using a switch in the config file. Well,
-         mission specific texts won't work outside the
-         WAD anyway.
-
-       * TODO: along the same lines: I suggest removing
-         the misc. devparm switches as well - lots of
-         redundancy not needed anymore.
-
-       * Makefile: finally added a doomstat.c for all
-         the global state variables listing internal
-         engine configuration. Right now, these are
-         scattered everywhere. Declaration to be found
-         in doomstat.h header.
-
-       * f_finale.c (F_StartFinale): 
-         Reworked the entire finale handling based on
-         game mode enum.
-
-       * doomstat.h:
-         Global variables for game mode and language.
-         Removed old booleans.
-
-       * doomdef.h: GameMode_t and Language_t enum added.
-          Boolean for language was kinda limiting to 2
-         alternatives (french, english), and five boolean
-         plus #define SPECIAL for game version is just ugly.
-       
-       * wi_stuff.h: SPECIAL switch compiles two
-         different EXE's, one for 3 episodes of 9 maps
-         each (DOOM 1 registered), one for 4 episodes
-         of 9 maps each (DOOM 1 retail/FinalDOOM).
-         Implicitely, the DOOM2 config (one episode,
-         34 missions) is handled. How is the german
-         edition (32 missions only) done?
-         Frankly, this is a mess. The problem is that
-         intermission (animated as in DOOM 1, simple
-         backdrop as in DOOM2) as well as certain
-         items (double shotgun) as well as certain
-         rendering stuff (sky texture) depend on this.
-
-         Plus, it ties into runtime flags as "commercial"
-         as well. Yuck.
-       
-         Each change will change the game. Postponed.
-
-       * d_net.c,m_misc.c: removed last two NeXT remains.
-
-       * d_englsh.h,d_french.h,d_main.c,m_misc.c,r_draw.c,v_video.c:
-         more WATCOM remains removed. Kept some stuff that
-         handeld the blocky mode/detailshift in DOS, which
-         is n.a. in Linux - but probably not worth fixing.
-
-Sat Dec 20 15:16:51 1997    <bk@gamers.org>
-
-       * Bug: core dump when using doom.wad or doom1.wad
-         without a "-file UNUSED/doom2.wad". Version
-         dependend handling of stuff (double shotgun)
-         comes to mind.
-
-       * doomdef.h: 
-         SNDSERV enables external sound server
-         support. SNDINTR enables internal sound
-         output with timer (asynchronous). Default
-         is internal, synchronous.
-
-       * i_sound.c (I_HandleSoundTimer): 
-         Okay, the plasma/double shotgun sound bug
-         (crapyy sund when firing nose-to-wall) is
-         obviously a problem with blocking at
-         refresh - smaller screen size makes it go
-         away.
-         I won't do threads w/o a proper gdb, and
-         I can't do whatever Dave Taylor did with
-         LinuxQuake w/o the sources, thus I broke
-         down and implemented a timer based solution.
-         Seems to work fine, given the fact that
-         this is the first time ever I implemented
-         sound handling.
-
-Fri Dec 19 10:02:48 1997    <bk@gamers.org>
-
-       * m_menu.c/i_sound.c/s_sound.c:
-         Removed a few more inconsistencies due to
-         old internal sound handling (DOS),
-         external (Linux sndserver), and
-         new internal (the unfinished merge of
-         both the former).
-         The Options/Sound/Music volume menu is
-         accessible now. It was due to an internal
-         scaling of the menu (effective range 0-15),
-         up to 0..120, by multiply with 8 scattered
-         all over the place, that we got a
-          v_video.c: I_Error ("Bad V_DrawPatch")
-         Now I am using the menu resolution
-         everywhere, and scaling should only be done
-         in the actual mixing/output.
-       
-       * OK, obviously this hasn't been updated in months.
-         This is because: a) most of the time nothing
-         happened, and b) when something got done, it was
-         too much to keep track of it by CVS and/or ChangeLog.
-
-         Basically, what happened in the meantime is that
-         I did not find a publisher who believed that the book
-         sales would be worth doing it. Within the limited
-         amount of time that I could dedicate to a project
-         that will not generate any revenue whatsoever,
-         I spent some time on cleaning up the Linux code
-         base which works, essentially. I might or might not
-         be able to participate in a Mesa+Voodoo+Glide based
-         GLDOOM port for Linux. I won't waste a minute on
-         Win32 without getting paid for it.
-  
-         Because of the legal issues involved with the
-         DMX sound library id licensed for DOS DOOM, Linuxdoom
-         is the only code base that has sound support at all.
-         Other UNIX ports (SGI, Sun) could probably be revived
-         and integrated w/o too many problems. There is no
-         Win32 port - I never had access to WinDOOM or
-         Jim Dose's GLDOOM sources. There is no Linux
-         OpenGL (read: Mesa) support yet - that'd involve
-         internal changes which will best be done after a
-         public source release.
-
-         John Carmack opted for a release of the Linux code.
-         I have removed all DMX references I could get a
-         hold of, but preserved some of the original
-         sound handling within DOOM that interfaced
-         with DMX. Linuxdoom (like previous UNIX ports)
-         used a separate sound server binary. I did some
-         work on putting the sound server module back into
-         the engine. It works, but shutdown (pending sounds),
-         and sound output parallel to refresh (blocking)
-         is crappy, and there is a problem with double
-         shotgun and plasma at close distance (as well as
-         with lots of other noises going on). As the
-         mixing code is identical to the separate
-         soundserver, and as it doesn't seem to be a
-         blocking issue, I am currently at a loss - I
-         wonder whether the IPC communication with the
-         soundserver process introduced a delay that
-         changed behaviour, or whether I simply overlooked
-         a bug. I am currently lacking the time to track
-         this down, so I am keeping both internal and
-         soundserver source.
-
-         I did remove DOS and Watcom specifics. I did also
-         remove the texture mapping and fixed point assembly.
-         From my experience, it isn't worth the trouble
-         to ue GCC inline assembler, as performance of 
-         the same loop written in C is perfectly sufficient.
-         On demand I will put both assembly modules into some
-         documentation, as they are probably of historic
-         interest.
-
-         There is no Sun DGA, Irix, or other non-Linux stuff
-         in this code base (at least, not intentionally). 
-         They will be back when ports to other UNIX 
-         environments will be merged back (I can't do 
-         testing, and the modules were separate and not
-         consistent, so I refrained from wasting time on
-         this prior to a public release).
-
-         While I made only minor changes to the actual code
-         (some fixes, some cleaning up of SHM and audio),
-         I did a huge amount of shuffling around. I
-         introduced many more header files and modules,
-         some of them laughably small (doing these changes
-         is bound to screw up CVS, so no CVS record anymore
-         for the time being). I would introduce even more
-         separation if I had the time. Splitting the
-         animation/AI/behaviour code that defines 
-         "DOOM - The Game" into a separate game.so (like
-          Quake2 does) should definitely be done. Separating
-         a ref_soft.so aka "DOOM - The Engine", and defining
-         a clean interface prior to introducing a ref_gl.so
-         is recommended as well.
-
-         I am going to purge some more leftovers, remove 
-         the obsolete CVS history except for comments,
-         and try to clean up the last "implicit declaration"
-         and "unused variable" warnings. Except for enabling
-         cheats in nightmare (to have more fun while testing),
-         I did not change the game mechanics at all. I would
-         strongly advise against doing so w/o the proper
-         separations suggested above. I will not waste time
-         on fixing detail and blocky mode, lack of resize,
-         or other stuff that it better addressed by a proper
-         GLDOOM port.
-
-       
-Sat Aug 16 08:07:16 1997    <bk@hal.gamers.org>
-
-       * p_pspr.c:
-         Moved the sprite animation stuff from doomdef.h here.
-
-       * info.h:
-         Added #ifndef __INFO__ for multiple inclusion. I am
-         not going to deal with multigen, or changing the
-         original DOOM monster animation anyway.
-
-       * p_spec.h/c:
-         Moved anim_t etc., locally used only. There is
-         another anim_t in wi_stuff.h/c, now local as well,
-         so collisions on header inclusion should not occur.
-          #include "doomdef.h"
-          #include "doomstat.h"
-         these should now be topmost includes.
-       
-       * doomstat.h, doomdef.h, wi_stuff.h, d_player.h:
-         I moved wbstartstruct_t to d_player.h, and wminfo
-         to doomstat.h. Basically, I will try to move all
-         global state related stuff into doomstat.h, and
-         all data structures defined for state variables
-         into doomdef.h - this will be kinda greek tragedy,
-         and never finished, but a body can try.
-
-       * wi_stuff.h/c, wi_data.h: 
-          Removed wi_data.h, put all local stuff blah... see
-         below.
-          I have found several unused global variables,
-         started outcommenting them with //U, will remove
-         them later. It might be Watcom/PC stuff, or
-         somebody put the actual numbers into the implementation
-         instead of using STARDIST, ANIMPERIOD & Cie.
-       
-       * st_stuff.h/c: from doomdef.h, local stuff moved
-         into st_stuff.c, etc.
-         In the current revisions, I am tolerating warnings
-         of the "implicit declaration" kind - the linker
-         resolves the stuff, and it will be handy in 
-         unmangling the modules once the headers contain
-         only the globally visible stuff.
-
-       * am_map.h/c, am_data.h:
-         Removed am_data.h, put all local stuff into
-         am_map.c, moved globally needed headers from
-         doomdef.h into am_map.h.
-
-       * p_saveg.h, p_setup.h, p_tick.h:
-         created, stuff from doomde.h moved there
-
-       * d_main.c, d_net.c, doomdef.h: 
-         Decided to dump mprintf, as only needed for
-         Watcom support which is not going to happen.
-
-       * doomdef.h: 
-         Moved function prototypes to appropriate headers:
-         d_main.h, d_net.h.
-
-Fri Aug 15 16:38:53 1997    <bk@hal.gamers.org>
-
-       * doomstat.h:
-         added a few more comments, regrouped some of the
-         state variables.
-
-       * doomdata.h: added a few more comments.
-
-Thu Aug 14 10:38:37 1997    <bk@hal.gamers.org>
-
-       * g_game.c (G_DoLoadLevel): 
-         copied the skyflatnum determination here, from
-         the R_InitSkyMap - once should be sufficient.
-
-       * Makefile, r_sky.h/c: 
-         added r_sky module. The sky handling was scattered
-         over r_bsp, r_main, r_plane, doomstat.h...
-
-       * r_bsp.c, r_main.c, r_segs.c:
-         Removed RD_* calls from R_debug.m, NeXT switches.
-
-       * r_local.h:
-         Removed the R_debug.m NeXT specific debugging
-         code headers. Removed "drawbsp" flag from
-         here, and r_main.c, too.
-
-       * r_data.c: 
-         Started to remove NORMALUNIX switches, using
-         LINUX instead. Basically, different UNIX
-         platforms using the same code should simply
-         be ANDed in the #ifdef switches.
-
-       * r_draw.c:
-         Removed some more, but not all WATCOMC support.
-         There is an unresolved problem with the fuzzy
-         blitting in the lowres (blocky) modes - either
-         the "detailshift" flag triggered lowres mode
-         will be removed, or the bug has to be fixed.
-
-       * r_bsp.h, r_draw.h, r_things.h, r_data.h,
-         r_segs.h, r_main.h, r_plane.h: 
-          Created from r_local.h. 
-       
-       * Back to work.
-         Till March 22nd, a lot of source shuffling and addition
-         of new header files, separating stuff, and creating
-         new, smaller modules. Some Watcom/PC/DMX/NeXT etc.
-         related stuff got removed, but not all (yet). None of
-         this ended up in the Log (sorry) or the revision control
-         (CVS is not well suited while number of files and
-         respective names change a lot, especially if stuff gets
-         deleted and/or re-introduced).
-         Major change: part of the sound code got copied from the
-         separate Linux sndserver sources to the linuxdoom source.
-         Re-integration and removal of sndserver pending.
-         Nothing of importance happend since then (priorities).
-
-Mon Feb  3 16:41:05 1997    <bk@gamers.org ()>
-
-        * m_misc.c:
-          Created m_argv, m_random and m_bbox, kept remains in m_misc
-          for the time being. Misc. files changed to include only
-          necessary modules. Moved bbox definitions from doomdata.h. 
-
-        * m_menu.h:
-          Created from doomdef.h. Misc. changes in dependend modules.
-          I am not going to list every affected file from now on.
-          See Log entries within each file. 
-
-        * dstrings.h:
-          Now handles multi-language support and switches.
-          So far, only english (default) and french are available. 
-
-        * d_englsh.h: 
-          Created from dstrings.h. 
-
-        * g_game.h:
-          Created, from doomdef.h. 
-
-        * am_map.c, st_stuff.c, wi_stuff.c: 
-        * Makefile: 
-          Added m_cheat, removed dutils. Doubly linked list stuff unused.
-
-        * m_cheat.h, m_cheat.c:
-          Created, basci cheat string scrambling and check, from dutils.h
-          and dutils.c. 
-
-        * doomdef.h
-          Moved screen declaration to v_video.h.
-
-        * dutils.h, dutils.c
-          Remode code for f_wipe.h and f_wipe.c.
-
-        * Makefile
-        * d_main.c,
-          Added f_wipe files.
-
-        * f_wipe.h, f_wipe.c: 
-          Created, screen wipe/melt at mission begin, from dutils.h
-          and dutils.c.
-
-        * d_textur.h:
-          Created from doomdata.h. Separates all the patch/texture
-          defintions. Needed for v_video module. 
-
-        * r_local.h, wi_stuff.h, st_lib.h, hu_lib.h: 
-        * i_x.c, d_main.c, m_menu.c, m_misc.c: 
-          Added v_video.h.
-
-        * v_video.h:
-          Created. Using headers from doomdef.h. Forward of patch_t.
-          Moved bool and byte to doomtype.h.
-
-Thu Jan 30 20:50:16 1997    <bk@gamers.org ()>
-
-        * doomtype.h:
-          Created, for fixed_t. Should add angle_t here, too.
-
-        * tables.c: 
-          Added SlopeDiv from r_main.c, added all defines and typedefs
-          related to basic trig table use here, removed it.
-          Currently "tables.h" is included in doomdef.h and
-          r_local.h, too. This is not too cleanly separated, but
-          we have to start somewhere, right?
-
-        * tables.h:
-          Created from doomdef.h.
-          Note that tables.c had fixed size tables, while doomdef.h
-          calculated from the value of FINEANGLES. In addition,
-         entries were given as either "int" or "fixed_t". Bad boys.  
-
-        * z_zone.c: 
-        * s_sound.c: 
-        * hu_stuff.c: 
-        * st_lib.c, st_stuff.c: 
-        * wi_stuff.c: 
-        * w_wad.c: 
-        * r_things.c, r_plane.c, r_draw.c, r_data.c: 
-        * p_tick.c, p_mobj.c, p_spec.c, p_setup.c, p_lights.c, 
-          p_plats.c, p_floor.c, p_doors.c, p_ceilng.c: 
-        * am_map.c: 
-        * m_misc.c, m_menu.c: 
-        * g_game.c: 
-        * d_main.c: 
-        * f_finale.c:
-          Added #include "z_zone.h". 
-
-        * z_zone.h: 
-          Created, from stuff in doomdef.h
-
-        * CVS checkin. Reformatting run, last one.
-          Took a week to go through all the sources, w/o even
-          looking to closely.
-
-        * st_stuff.c (ST_Responder): 
-          Removed a first tiny bit of redundancy (NO_CLIP checks).
-         Should remove idspispod completely, later.
-
-Wed Jan 29 19:53:43 1997    <bk@gamers.org ()>
-
-        * Another one, while we are on it. All S (Sound) files.
-
-        * CVS checkin. Reformatting run, all R (Refresh) files.
-
-        * r_draw.c (R_DrawSpanLow): 
-          The non-Watcom, non-asm lowres mode was just a copy
-         of the default mode. As detailshift was used to scale
-         the image down, lowres mode just filled the left half
-         of the buffer.
-        * r_draw.c (R_DrawColumnLow): 
-          Tried the same hack for walls, horribly broken.
-         Postponed. 
-
-Tue Jan 28 19:32:48 1997    <bk@gamers.org ()>
-
-        * CVS checkin. Another reformatting run. Did all P files.
-
-        * p_spec.c: P_FindNextHighestFloor
-          The number of adjoining sectors is limited to 20, because
-         of a temporary LUT needed for determining lowest height
-         in adjacent sectors. No overflow checking is done.
-
-Sun Jan 26 08:41:21 1997    <bk@gamers.org ()>
-
-        * Another CVS checkin of a formatting run.
-          D,F,G,HU,I,M have been changed.
-
-        * Note: in initial and current release,
-           linuxxdoom -3 -file plutonia.wad, idclev 12
-          produces a Segmentation fault.
-
-Wed Jan 22 14:03:00 1997    <bk@gamers.org ()>
-
-        * m_menu.c:
-           initializer-string for array of chars is too long (skullName)
-           warning: unused parameter `int choice' (a couple of times)
-
-        * Attempt to compile as C++. Loads of warnings, a couple of errors.
-          p_enemy.c (P_Move):
-          r_things.c (R_ProjectSprite)
-           `catch', `throw', and `try' are all C++ reserved words,
-           thus changed "try" to "try_ok". Fixed.
-          p_pspr.c: In function `void P_SetPsprite(struct player_s *, ... )':
-           too many arguments to function
-           No convenient fix - state->action is declared void action(),
-           but called w/o, with one, or with two parameters.
-           There are more like this. Going to be a tough one.
-          Union of pointers?
-          Postponed.
-
-       r_plane.c: In function `void R_DrawPlanes()':
-          s_sound.c: In function `int S_AdjustSoundParams(struct mobj_s *, .. )':
-          p_map.c: In function `bool PIT_StompThing(struct mobj_s *)':
-          p_maputl.c: In function `int P_AproxDistance(int, int)':
-          r_main.c: In function `int R_PointToDist(int, int)':
-          p_enemy.c: In function `void P_NewChaseDir(struct mobj_s *)':
-           warning: implicit declaration of function `int abs(...)'  <stdlib.h>
-
-Wed Jan 22 12:15:00 1997    <bk@gamers.org ()>
-
-        * CVS checkin of purification run. Sources now compile
-          without any "-Wall" warnings.
-
-        * Note: with -file "tnt.wad", we get an "Error: Bad V_DrawPatch"
-          abort each time we enter an exit. Invalid or missing
-          intermission screen?
-
-        * Makefile (CFLAGS): added -Wall, first purification run.
-
-          d_main.c: In function `D_DoomMain':
-           warning: implicit declaration of function `mkdir'   <fcntl.h>
-
-          i_unix.c: In function `I_StartSound':
-           warning: control reaches end of non-void function
-          i_unix.c: In function `I_InitNetwork':
-           warning: implicit declaration of function `inet_addr' <arpa/inet.h>
-          i_unix.c: At top level:
-           warning: `endianness' defined but not used
-
-          i_x.c: In function `I_Error':
-           warning: unused variable `string'
-          i_x.c: In function `I_GetEvent':
-           warning: suggest parentheses around arithmetic in operand of |
-          i_x.c: In function `I_FinishUpdate':
-           warning: unused variable `bigscreen'
-          i_x.c: In function `grabsharedmemory':
-           warning: implicit declaration of function `getuid'  <unistd.h>
-           warning: unused variable `done'
-          i_x.c: In function `I_InitGraphics':
-           warning: suggest parentheses around assignment used as truth value
-           warning: char format, different type arg (arg 3)
-           warning: char format, different type arg (arg 5)
-           warning: implicit declaration of function `XShmGetEventBase'
-          i_x.c: In function `InitExpand2':
-           warning: unused variable `jexp'
-           warning: unused variable `iexp'
-
-          m_menu.c: In function `M_ReadSaveStrings':
-           warning: implicit declaration of function `read'    <sys/types.h>
-           warning: implicit declaration of function `close'   <unistd.h>
-
-       m_misc.c: In function `M_WriteFile':
-           warning: implicit declaration of function `write'
-           warning: implicit declaration of function `close'
-          m_misc.c: In function `M_ReadFile':
-           warning: implicit declaration of function `read'
-          m_misc.c: In function `M_ScreenShot':
-           warning: implicit declaration of function `access'  <unistd.h>
-
-       p_pspr.c: In function `P_MovePsprites': 
-        suggest parentheses around assignment used as truth value
-
-          p_spec.c: In function `P_SpawnSpecials':
-           warning: implicit declaration of function `atoi'    <stdlib.h>
-
-       w_wad.c: In function `strupr':
-           warning: implicit declaration of function `toupper' <ctype.h>
-          w_wad.c: In function `W_AddFile':
-           warning: implicit declaration of function `read'    <sys/types.h>
-           warning: implicit declaration of function `lseek'
-           warning: implicit declaration of function `close'   <unistd.h>
-
-          wi_stuff.c: In function `WI_loadData':
-           warning: unused variable `pic'
-          wi_stuff.c: At top level:
-           warning: `background' defined but not used
-
-Tue Jan 21 22:00:00 1997    <bk@gamers.org ()>
-
-        * doomdata.h (__BYTEBOOL__):
-          Use builtin ANSI C++ bool.
-
-        * d_main.c (IdentifyVersion): 
-          Bug fix: insufficient malloc created errors in malloc/realloc
-         calls later on. Welcome to the risks of Copy'n'paste. 
-
-Tue Jan 21 13:20:05 1997    <bk@gamers.org ()>
-
-        * First formatting checkin.
-          A word of explanation: prior to making any changes to the
-         source, a couple of formatting runs will be made, followed
-         by some purification runs.
-         For this run, the Emacs mode selection line has been changed
-         to use C++ style indenting (cc-mode.el).  Each file has
-         been automatically reformatted using Emacs indent-region.
-         A few files have been changed manually already (i.e.,
-         comments, use of tabs).
-         Warning: using "diff" to compare files of different states
-         during the reformatting will not give useful results.
-
-        * hu_stuff.c: 
-          fixed "assignment discard const", the last remaining error
-          message with default compilation.
-                      
-
-Sun Jan 19 14:27:06 1997    <bk@gamers.org ()>
-
-        * Makefile:
-          Minor fix for sndserver target, removed linuxsdoom target
-          for the time being, added CVS header (kind of).
-
-        * Initial CVS checkin. 
-
-        * soundsrv/irix/linux/sun.c: 
-          Changed includes (irix.h removed, soundsrv.h included).
-
-        * i_svga.c: 
-          Changed to DOS 8+3.
-
-        * soundsrv.h/c:
-          Changed to DOS 8+3, included irix.h in soundsrv.h.
-
-        * r_local.h:
-          Same for PI, include math.h with Linux.
-
-        * doomdef.h: 
-          Got rid of multiply defined warnings for Linux, 
-          included values.h.
-
-        * FILES2:
-          created a commented list of all files, removed a few
-          more files (sndserver test, NeXT leftovers, DMX header).
-          Identified the following main modules (see FILES2):
-          AM, HU, M, P, R, S, ST, W, WI. Some stuff is separate
-          (Z, F), some not clearly separable (G, D). System specific
-          interfaces are in I. Some of the latter replace i_main.c
-          (i.e. the void/int main(argc,argv) call), e.g. SVGA,
-          others (X11, SHM, DGA) don't. There is a certain amount
-          of overlap, and the largest module (with possibly most
-          overlap) is P - playing, i.e. all the games state and
-          animation handling.
-          Dithering is currently not used.
-
-Sat Jan 18 15:14:41 1997    <bk@gamers.org ()>
-
-        * r_draw.c: 
-          fixed !defined(USEASM) lines for R_DrawColumn/Span.
-          Removed fpfunc.o/S from Makefile, now compiling
-          X11 w/o any assembler.
-          Got a running linuxxdoom again. We are in business.
-          This source is going to be used for the initial CVS
-          check in.
-
-        * Tried a quick hack compiling it as COFF a.out instead
-          of ELF, with "gcc -b i486-linuxaout". Same linker
-          errors. 
-          Tried removing -DUSE_ASM. Still using fpfunc.S.
-
-
-        * Tried linuxxdoom.
-          Compile run: some warnings (redefinition of MAX/MIN
-           SHORT/INT/LONG) in doomdef.h and (PI redefined)
-           r_local.h.
-          Link run: crashed, undefined references in 
-            d_main.c: undefined reference to  `FixedDiv2'
-            am_map.c:  undefined reference to `FixedMul'
-            r_main.c:  undefined reference to `R_DrawColumn'
-            r_main.c:  undefined reference to `R_DrawSpan'
-            r_plane.c: undefined reference to `FixedMul'
-            
-          This stuff is defined in fpfunc.S (Fixed point) and
-          in r_draw.c (assembler in tmap.S not used).
-          However, "nm," shows that r_draw.o does not include
-          the drawing functions (see below - USE_ASM).
-          Furthermore, the global symbols in fpfunc.S begin
-          with an underscore, "_FixedMul" and "_FixedDiv2".
-          More problems within fpfunc.o: undefined references to 
-
-             `_dc_yl'      `_dc_yh'
-             `_ylookup'
-             `_centery'
-             `_dc_x'
-             `_columnofs'
-             `_dc_iscale'
-             `_dc_texturemid'
-             `_dc_source'
-             `_dc_colormap'
-
-             `_ds_y'       `_ds_x1'      `_ds_x2'
-             `_ds_xfrac'   `_ds_yfrac'
-             `_ds_xstep'   `_ds_ystep'
-             `_ds_colormap'
-             `_ds_source'
-
-          Again, underscore problem.
-          Note: tmap.S currently obsolete, as somebody pasted all
-          the texture mapping assembly into fpfunc.S. Gotta clean
-          that up.
-
-        * Created initial release from CD sources, created ChangeLog.
-          Let the games begin.
-
-
-        **************************************************************
-       DOOM source code ChangeLog file
-       **************************************************************
-
diff --git a/frosted-doom/DOOMLIC.TXT b/frosted-doom/DOOMLIC.TXT
deleted file mode 100644 (file)
index 2b2252e..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-
-
-      LIMITED USE SOFTWARE LICENSE AGREEMENT
-
-        This Limited Use Software License Agreement (the "Agreement")
-is a legal agreement between you, the end-user, and Id Software, Inc.
-("ID").  By downloading or purchasing the software material, which
-includes source code (the "Source Code"), artwork data, music and
-software tools (collectively, the "Software"), you are agreeing to
-be bound by the terms of this Agreement.  If you do not agree to the
-terms of this Agreement, promptly destroy the Software you may have
-downloaded or copied.
-
-ID SOFTWARE LICENSE
-
-1.      Grant of License.  ID grants to you the right to use the
-Software.  You have no ownership or proprietary rights in or to the 
-Software, or the Trademark. For purposes of this section, "use" means 
-loading the Software into RAM, as well as installation on a hard disk
-or other storage device. The Software, together with any archive copy
-thereof, shall be destroyed when no longer used in accordance with 
-this Agreement, or when the right to use the Software is terminated.  
-You agree that the Software will not be shipped, transferred or 
-exported into any country in violation of the U.S. Export 
-Administration Act (or any other law governing such matters) and that 
-you will not utilize, in any other manner, the Software in violation 
-of any applicable law.
-
-2.      Permitted Uses.  For educational purposes only, you, the
-end-user, may use portions of the Source Code, such as particular
-routines, to develop your own software, but may not duplicate the
-Source Code, except as noted in paragraph 4.  The limited right
-referenced in the preceding sentence is hereinafter referred to as
-"Educational Use."  By so exercising the Educational Use right you
-shall not obtain any ownership, copyright, proprietary or other
-interest in or to the Source Code, or any portion of the Source
-Code.  You may dispose of your own software in your sole discretion.
-With the exception of the Educational Use right, you may not
-otherwise use the Software, or an portion of the Software, which
-includes the Source Code, for commercial gain.
-
-3.      Prohibited Uses:  Under no circumstances shall you, the
-end-user, be permitted, allowed or authorized to commercially exploit
-the Software. Neither you nor anyone at your direction shall do any
-of the following acts with regard to the Software, or any portion
-thereof:
-
-        Rent;
-
-        Sell;
-
-        Lease;
-
-        Offer on a pay-per-play basis;
-
-        Distribute for money or any other consideration; or
-
-        In any other manner and through any medium whatsoever
-commercially exploit or use for any commercial purpose.
-
-Notwithstanding the foregoing prohibitions, you may commercially
-exploit the software you develop by exercising the Educational Use 
-right, referenced in paragraph 2. hereinabove.
-
-4.      Copyright.  The Software and all copyrights related thereto 
-(including all characters and other images generated by the Software
-or depicted in the Software) are owned by ID and is protected by
-United States  copyright laws and international treaty provisions.  
-Id shall retain exclusive ownership and copyright in and to the
-Software and all portions of the Software and you shall have no 
-ownership or other proprietary interest in such materials. You must
-treat the Software like any other copyrighted material. You may not
-otherwise reproduce, copy or disclose to others, in whole or in any
-part, the Software.  You may not copy the written materials
-accompanying the Software.  You agree to use your best efforts to
-see that any user of the Software licensed hereunder complies with
-this Agreement.
-
-5.      NO WARRANTIES.  ID DISCLAIMS ALL WARRANTIES, BOTH EXPRESS
-IMPLIED, INCLUDING BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE WITH RESPECT
-TO THE SOFTWARE.  THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL
-RIGHTS.  YOU MAY HAVE OTHER RIGHTS WHICH VARY FROM JURISDICTION TO
-JURISDICTION.  ID DOES NOT WARRANT THAT THE OPERATION OF THE SOFTWARE
-WILL BE UNINTERRUPTED, ERROR FREE OR MEET YOUR SPECIFIC REQUIREMENTS.
-THE WARRANTY SET FORTH ABOVE IS IN LIEU OF ALL OTHER EXPRESS
-WARRANTIES WHETHER ORAL OR WRITTEN.  THE AGENTS, EMPLOYEES, 
-DISTRIBUTORS, AND DEALERS OF ID ARE NOT AUTHORIZED TO MAKE 
-MODIFICATIONS TO THIS WARRANTY, OR ADDITIONAL WARRANTIES ON BEHALF
-OF ID. 
-
-        Exclusive Remedies.  The Software is being offered to you
-free of any charge.  You agree that you have no remedy against ID, its
-affiliates, contractors, suppliers, and agents for loss or damage 
-caused by any defect or failure in the Software regardless of the form
-of action, whether in contract, tort, includinegligence, strict
-liability or otherwise, with regard to the Software.  This Agreement
-shall be construed in accordance with and governed by the laws of the
-State of Texas.  Copyright and other proprietary matters will be
-governed by United States laws and international treaties.  IN ANY 
-CASE, ID SHALL NOT BE LIABLE FOR LOSS OF DATA, LOSS OF PROFITS, LOST
-SAVINGS, SPECIAL, INCIDENTAL, CONSEQUENTIAL, INDIRECT OR OTHER
-SIMILAR DAMAGES ARISING FROM BREACH OF WARRANTY, BREACH OF CONTRACT,
-NEGLIGENCE, OR OTHER LEGAL THEORY EVEN IF ID OR ITS AGENT HAS BEEN
-ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY
-OTHER PARTY. Some jurisdictions do not allow the exclusion or
-limitation of incidental or consequential damages, so the above
-limitation or exclusion may not apply to you.
-
-
-
-
diff --git a/frosted-doom/FILES b/frosted-doom/FILES
deleted file mode 100644 (file)
index 33af95d..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-total 1258
--rw-r--r--   1 b1       prog            0 Jan 18 15:08 FILES
--rw-r--r--   1 b1       prog         5799 Jan 18 15:07 Makefile
--rw-r--r--   1 b1       prog         1943 Jan 18 15:07 am_data.h
--rw-r--r--   1 b1       prog        20263 Jan 18 15:07 am_map.c
--rw-r--r--   1 b1       prog         2494 Jan 18 15:07 am_map.h
--rw-r--r--   1 b1       prog         1499 Jan 18 15:07 am_oids.c
--rw-r--r--   1 b1       prog          338 Jan 18 15:07 am_oids.h
--rw-r--r--   1 b1       prog        14005 Jan 18 15:07 d_french.h
--rw-r--r--   1 b1       prog        25287 Jan 18 15:07 d_main.c
--rw-r--r--   1 b1       prog        15586 Jan 18 15:07 d_net.c
--rw-r--r--   1 b1       prog          744 Jan 18 15:07 defs.inc
--rw-r--r--   1 b1       prog         3569 Jan 18 15:07 dither.c
--rw-r--r--   1 b1       prog          355 Jan 18 15:07 dither.h
--rw-r--r--   1 b1       prog         4234 Jan 18 15:07 doomdata.h
--rw-r--r--   1 b1       prog        32779 Jan 18 15:07 doomdef.h
--rw-r--r--   1 b1       prog          192 Jan 18 15:07 drcoord.h
--rw-r--r--   1 b1       prog        22377 Jan 18 15:07 dstrings.h
--rw-r--r--   1 b1       prog         6582 Jan 18 15:07 dutils.c
--rw-r--r--   1 b1       prog         1821 Jan 18 15:07 dutils.h
--rw-r--r--   1 b1       prog        14072 Jan 18 15:07 f_finale.c
--rw-r--r--   1 b1       prog         7357 Jan 18 15:07 fpfunc.S
--rw-r--r--   1 b1       prog        34770 Jan 18 15:07 g_game.c
--rw-r--r--   1 b1       prog         5394 Jan 18 15:07 hu_lib.c
--rw-r--r--   1 b1       prog         2878 Jan 18 15:07 hu_lib.h
--rw-r--r--   1 b1       prog        12040 Jan 18 15:07 hu_stuff.c
--rw-r--r--   1 b1       prog          934 Jan 18 15:07 hu_stuff.h
--rw-r--r--   1 b1       prog         6238 Jan 18 15:07 i_cyber.c
--rw-r--r--   1 b1       prog        18324 Jan 18 15:07 i_dga.c
--rw-r--r--   1 b1       prog         2499 Jan 18 15:07 i_header.h
--rw-r--r--   1 b1       prog        32815 Jan 18 15:07 i_ibm.c
--rw-r--r--   1 b1       prog         1867 Jan 18 15:07 i_ibm_a.asm
--rw-r--r--   1 b1       prog          121 Jan 18 15:07 i_main.c
--rw-r--r--   1 b1       prog         8251 Jan 18 15:07 i_pcnet.c
--rw-r--r--   1 b1       prog         8561 Jan 18 15:07 i_sound.c
--rw-r--r--   1 b1       prog          439 Jan 18 15:07 i_sound.h
--rw-r--r--   1 b1       prog         9537 Jan 18 15:07 i_svgalib.c
--rw-r--r--   1 b1       prog        10886 Jan 18 15:07 i_unix.c
--rw-r--r--   1 b1       prog        20891 Jan 18 15:07 i_x.c
--rw-r--r--   1 b1       prog       128797 Jan 18 15:07 info.c
--rw-r--r--   1 b1       prog        15840 Jan 18 15:07 info.h
--rw-r--r--   1 b1       prog         3477 Jan 18 15:07 irix.c
--rw-r--r--   1 b1       prog          240 Jan 18 15:07 irix.h
--rw-r--r--   1 b1       prog         1363 Jan 18 15:07 linux.c
--rw-r--r--   1 b1       prog        34628 Jan 18 15:07 m_menu.c
--rw-r--r--   1 b1       prog        13741 Jan 18 15:07 m_misc.c
--rw-r--r--   1 b1       prog         6117 Jan 18 15:07 p_ceilng.c
--rw-r--r--   1 b1       prog        15062 Jan 18 15:07 p_doors.c
--rw-r--r--   1 b1       prog        33758 Jan 18 15:07 p_enemy.c
--rw-r--r--   1 b1       prog        11409 Jan 18 15:07 p_floor.c
--rw-r--r--   1 b1       prog        16265 Jan 18 15:07 p_inter.c
--rw-r--r--   1 b1       prog         7592 Jan 18 15:07 p_lights.c
--rw-r--r--   1 b1       prog         6447 Jan 18 15:07 p_local.h
--rw-r--r--   1 b1       prog        30138 Jan 18 15:07 p_map.c
--rw-r--r--   1 b1       prog        14672 Jan 18 15:07 p_maputl.c
--rw-r--r--   1 b1       prog        17276 Jan 18 15:07 p_mobj.c
--rw-r--r--   1 b1       prog         5940 Jan 18 15:07 p_plats.c
--rw-r--r--   1 b1       prog        17084 Jan 18 15:07 p_pspr.c
--rw-r--r--   1 b1       prog        12828 Jan 18 15:07 p_setup.c
--rw-r--r--   1 b1       prog         5962 Jan 18 15:07 p_sight.c
--rw-r--r--   1 b1       prog        23846 Jan 18 15:07 p_spec.c
--rw-r--r--   1 b1       prog        11140 Jan 18 15:07 p_spec.h
--rw-r--r--   1 b1       prog        14229 Jan 18 15:07 p_switch.c
--rw-r--r--   1 b1       prog         1910 Jan 18 15:07 p_telept.c
--rw-r--r--   1 b1       prog        14075 Jan 18 15:07 p_tick.c
--rw-r--r--   1 b1       prog         7044 Jan 18 15:07 p_user.c
--rw-r--r--   1 b1       prog        13013 Jan 18 15:07 planar.asm
--rw-r--r--   1 b1       prog         9811 Jan 18 15:07 r_bsp.c
--rw-r--r--   1 b1       prog        14619 Jan 18 15:07 r_data.c
--rw-r--r--   1 b1       prog        13591 Jan 18 15:07 r_draw.c
--rw-r--r--   1 b1       prog        11378 Jan 18 15:07 r_local.h
--rw-r--r--   1 b1       prog        14868 Jan 18 15:07 r_main.c
--rw-r--r--   1 b1       prog         7108 Jan 18 15:07 r_plane.c
--rw-r--r--   1 b1       prog        15420 Jan 18 15:07 r_segs.c
--rw-r--r--   1 b1       prog        18969 Jan 18 15:07 r_things.c
--rw-r--r--   1 b1       prog        12274 Jan 18 15:07 s_sound.c
--rw-r--r--   1 b1       prog        12812 Jan 18 15:07 sndserver.c
--rw-r--r--   1 b1       prog          141 Jan 18 15:07 sndserver.h
--rw-r--r--   1 b1       prog         5811 Jan 18 15:07 sounds.c
--rw-r--r--   1 b1       prog         2674 Jan 18 15:07 sounds.h
--rw-r--r--   1 b1       prog         3975 Jan 18 15:07 soundst.h
--rw-r--r--   1 b1       prog         3461 Jan 18 15:07 st_lib.c
--rw-r--r--   1 b1       prog         2254 Jan 18 15:07 st_lib.h
--rw-r--r--   1 b1       prog        22769 Jan 18 15:07 st_stuff.c
--rw-r--r--   1 b1       prog         4685 Jan 18 15:07 st_stuff.h
--rw-r--r--   1 b1       prog         1725 Jan 18 15:07 sun.c
--rw-r--r--   1 b1       prog           75 Jan 18 15:07 t.c
--rw-r--r--   1 b1       prog       114621 Jan 18 15:07 tables.c
--rw-r--r--   1 b1       prog         5485 Jan 18 15:07 tmap.S
--rw-r--r--   1 b1       prog        10904 Jan 18 15:07 v_video.c
--rw-r--r--   1 b1       prog          268 Jan 18 15:07 vgaview.h
--rw-r--r--   1 b1       prog         9920 Jan 18 15:07 w_wad.c
--rw-r--r--   1 b1       prog         3629 Jan 18 15:07 wadread.c
--rw-r--r--   1 b1       prog          551 Jan 18 15:07 wadread.h
--rw-r--r--   1 b1       prog         3583 Jan 18 15:07 wi_data.h
--rw-r--r--   1 b1       prog        25608 Jan 18 15:07 wi_stuff.c
--rw-r--r--   1 b1       prog         1544 Jan 18 15:07 wi_stuff.h
--rw-r--r--   1 b1       prog         8501 Jan 18 15:07 z_zone.c
diff --git a/frosted-doom/FILES2 b/frosted-doom/FILES2
deleted file mode 100644 (file)
index 066a4ef..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-ChangeLog
-FILES
-FILES2
-Makefile
-
------------------------------------------------------------------------
-Global and misc. stuff
------------------------------------------------------------------------
-doomdata.h   -  external data definitions (WAD file structure)
-doomdef.h    -  internal data definitions (game structs)
-dstrings.h   -  printed strings for translation, english 
-d_french.h   -  printed strings for translation
-
-info.h
-info.c      -  LUT's for Thing TAB, Frame TAB,
-                generated by multigen utility
-dutils.h
-dutils.c     - Dave's utilities
-                 including doubly-linked lists & simple state machines.
-                 Used in WI, ST, AM, and d_main.c
-
-------------------------------------------------------------------------
-DOOM game loop and top level stuff
-------------------------------------------------------------------------
-g_game.c    -  Game loop functions, event handling etc.
-
-                boolean  G_CheckDemoStatus (void); 
-                void     G_ReadDemoTiccmd (ticcmd_t *cmd); 
-                void     G_WriteDemoTiccmd (ticcmd_t *cmd); 
-                void     G_PlayerReborn (int player); 
-                void     G_InitNew (skill_t skill, int episode, int map); 
-                void     G_DoReborn (int playernum); 
-                void     G_DoLoadLevel (void); 
-                void     G_DoNewGame (void); 
-                void     G_DoLoadGame (void); 
-                void     G_DoPlayDemo (void); 
-                void     G_DoCompleted (void); 
-                void     G_DoVictory (void); 
-                void     G_DoWorldDone (void); 
-                void     G_DoSaveGame (void); 
-
-d_main.c    -  event handling, D_DoomMain() and other functions
-                 NOT int main()
-
-d_net.c     -  high level networking protocol code
-
-------------------------------------------------------------------
-I         Interfaces, system specifics
-------------------------------------------------------------------    
-i_main.c    -  main(), calls D_DoomMain().
-i_svgalib.c -  Linux SVGAlib code, including main(),
-                 replaces i_main.c
-
-i_x.c       -  X11 with SHM code, use with i_main.c
-i_dga.c     -  X11 DGA code, use with i_main.c
-i_unix.c    -  fixed point, networking, and display stuff for UNIX
-
-i_ibm.c     -  IBM DOS VGA graphics and key/mouse/joystick,
-                 use with i_main.c
-i_pcnet.c   -  IPX networking, DOS 
-
-fpfunc.S     - fixed point assembly and (currently) duplicate of
-tmap.S       - texture mapping assembly (currently unused)
-
-------------------------------------------------------------------
-AM        AutoMap
-------------------------------------------------------------------
-am_data.h    -  vector graphics for the automap
-
-am_map.h
-am_map.c     -  automap code
-
-------------------------------------------------------------------
-HU         Heads Up
-------------------------------------------------------------------
-hu_lib.h
-hu_lib.c    -  heads-up text and input code
-
-hu_stuff.h
-hu_stuff.c  -  Heads-up displays
-
-
--------------------------------------------------------------------
-M          Menu
--------------------------------------------------------------------
-m_menu.c    -  DOOM options code and leaving messages
-
-m_misc.c    -  misc. HUD text display, input checks, and
-                random table, file I/O
-
-
--------------------------------------------------------------------
-P          Play???
--------------------------------------------------------------------
-p_local.h   -  header for all play modules
-
-p_spec.h    -  specials, lighting, doors, plats, texture animation
-p_spec.c    -  specials, texture animation
-
-p_doors.c   -  door code
-p_plats.c   -  platform raising/lowering code
-p_ceilng.c  -  active (e.g. crushing) ceilings
-p_floor.c   -  active (e.g. raising) floors
-p_lights.c  -  dynamic (e.g. flickering) lighting
-p_switch.c  -  button switches and animation
-
-p_enemy.c   -  enemy AI and animation
-p_inter.c   -  object/object interaction?
-p_map.c     -  movement objects, handling of collisions
-p_maputl.c  -  distance, position etc. utilities for movement
-p_mobj.c    -  mobile objects handling, spawn etc.
-p_user.c    -  more movement, bobbing etc.
-
-p_telept.c  -  teleportation code
-
-p_sight.c   -  LOS checks, REJECT
-
-
-p_pspr.c    -  weapon overlays, bobbing, raising, sprite tables,
-               firing, ammo bookkeeping
-
-p_setup.c   -  load map from WAF file, setup code
-
-
-p_tick.c    -  savegame function (archive/unarchive),
-                thinker list handling, allocation,
-                game tick execution (updates)
-
-
--------------------------------------------------------------------
-R          Rendering    
--------------------------------------------------------------------
-r_local.h   - header for all rendering modules,
-                internal map data structure definitions
-
-r_bsp.c     - BSP seg's clipping
-
-r_data.c    - texture column caching, patch assembly, 
-                 flats, colormaps, sprites,
-                 lookup by name
-
-r_draw.c    - access to framebuffer API, drawing C functions
-
-
-r_main.c    - geometry functions, trigonometry lookups, 
-                 R_RenderPlayerView
-
-r_plane.c   - floor/ceiling visplanes, sky
-
-r_segs.c    - drawing segs, marking hslices for floors/ceilings
-
-r_things.c  - sprite and sprite frame/rotation handling, drawing
-
-
-tables.c    - trigonometry lookup tables, static
-
-v_video.c   - gamma correction lookup, patch drawing to rectangle
-
--------------------------------------------------------------------
-S          Sound
--------------------------------------------------------------------
-s_sound.c   - more sound and music handling
-
-soundst.h   - sound and music data structures
-sounds.h
-sounds.c    - sound and music lump LUT's (manually maintained)
-
-sndserver.h
-sndserver.c -  (Irix) sndserver code
-
-irix.h
-irix.c      -  SGI Irix sound/sndserver support code
-
-linux.c     -  Linux voxware sound/sndserver support code,
-                 replaces irix.c, uses irix.h
-sun.c       -  SUN replacement for irix.c
-
-
-i_sound.h
-i_sound.c   -  DOS DMX music and sound interface 
-
--------------------------------------------------------------------
-ST         STatus bar
--------------------------------------------------------------------
-st_lib.h
-st_lib.c    -  status bar widget code
-
-st_stuff.c
-st_stuff.h  -  status bar code
-
-
--------------------------------------------------------------------
-W          Wad file I/O
--------------------------------------------------------------------
-w_wad.c     -  lump based functions
-wadread.h
-wadread.c   -  lump I/O, get SFX
-
--------------------------------------------------------------------
-WI         WIn / level end screens
--------------------------------------------------------------------
-wi_data.h   -  lookups for intermission screens, patch positions
-
-wi_stuff.h  
-wi_stuff.c  -  intermission animation patchwork
-
--------------------------------------------------------------------
-Z          Zone memory allocation
--------------------------------------------------------------------
-z_zone.c
-
--------------------------------------------------------------------
-F          Final screen animation
--------------------------------------------------------------------
-f_finale.c   - DOOM mission end screens? (bunny)
-
-
-
--------------------------------------------------------------------
index 8bb5bef64e0048e02786da113bee387adea9568f..038ae011a760f004acac955e1ceccbc62dd17329 100644 (file)
@@ -15,7 +15,7 @@ endif
 
 ifeq ($(ARM),1)
        CROSS_COMPILE = arm-frosted-eabi-
-       OBJS+=$(O)/i_video_fbdev.o
+       OBJS+=$(OBJDIR)/i_video_fbdev.o
        CFLAGS+=-mthumb -mlittle-endian -mthumb-interwork -ffunction-sections -fdata-sections -mcpu=cortex-m3
        CFLAGS+=-DCORE_M3 -D__frosted__
        # COMPILER FLAGS -- No gcc libraries
@@ -26,109 +26,51 @@ ifeq ($(ARM),1)
        LDFLAGS+=-fPIC -mlong-calls -fno-common -Wl,-elf2flt -lgloss
 else
        CFLAGS+=-m32 -fsanitize=address -Wunused-const-variable=0 
-       LIBS+=-lXext -lX11 -lnsl -lm -lSDL2
-       OBJS+=$(O)/i_video_SDL.o
+       LIBS+=-lXext -lX11 -lnsl -lm -lSDL
+       OBJS+=$(OBJDIR)/i_video.o
 endif
 
 CC=  $(CROSS_COMPILE)gcc  # gcc or g++
-
-
-# Debugging
-CFLAGS+=-ggdb3
+CFLAGS+=-ggdb3 -Os
 LDFLAGS+=-Wl,--gc-sections
 CFLAGS+=-ggdb3 -Wall -DNORMALUNIX -DLINUX -DSNDSERV # -DUSEASM
-CFLAGS+=-Icompat
 LIBS+=-lm -lc
 
-#LDFLAGS=-L/usr/X11R6/lib
-#LIBS=-lXext -lX11 -lnsl -lm
-
 # subdirectory for objects
-O=frosted
+OBJDIR=build
+OUTPUT=fdoom
 
-# not too sophisticated dependency
-OBJS+=                         \
-               $(O)/stubs.o            \
-               $(O)/doomdef.o          \
-               $(O)/doomstat.o         \
-               $(O)/dstrings.o         \
-               $(O)/i_system.o         \
-               $(O)/i_sound_dummy.o          \
-               $(O)/i_net.o                    \
-               $(O)/tables.o                   \
-               $(O)/f_finale.o         \
-               $(O)/f_wipe.o           \
-               $(O)/d_main.o                   \
-               $(O)/d_net.o                    \
-               $(O)/d_items.o          \
-               $(O)/g_game.o                   \
-               $(O)/m_menu.o                   \
-               $(O)/m_misc.o                   \
-               $(O)/m_argv.o           \
-               $(O)/m_bbox.o                   \
-               $(O)/m_fixed.o          \
-               $(O)/m_swap.o                   \
-               $(O)/m_cheat.o          \
-               $(O)/m_random.o         \
-               $(O)/am_map.o                   \
-               $(O)/p_ceilng.o         \
-               $(O)/p_doors.o          \
-               $(O)/p_enemy.o          \
-               $(O)/p_floor.o          \
-               $(O)/p_inter.o          \
-               $(O)/p_lights.o         \
-               $(O)/p_map.o                    \
-               $(O)/p_maputl.o         \
-               $(O)/p_plats.o          \
-               $(O)/p_pspr.o                   \
-               $(O)/p_setup.o          \
-               $(O)/p_sight.o          \
-               $(O)/p_spec.o                   \
-               $(O)/p_switch.o         \
-               $(O)/p_mobj.o                   \
-               $(O)/p_telept.o         \
-               $(O)/p_tick.o                   \
-               $(O)/p_saveg.o          \
-               $(O)/p_user.o                   \
-               $(O)/r_bsp.o                    \
-               $(O)/r_data.o                   \
-               $(O)/r_draw.o                   \
-               $(O)/r_main.o                   \
-               $(O)/r_plane.o          \
-               $(O)/r_segs.o                   \
-               $(O)/r_sky.o                    \
-               $(O)/r_things.o         \
-               $(O)/w_wad.o                    \
-               $(O)/wi_stuff.o         \
-               $(O)/v_video.o          \
-               $(O)/st_lib.o                   \
-               $(O)/st_stuff.o         \
-               $(O)/hu_stuff.o         \
-               $(O)/hu_lib.o                   \
-               $(O)/s_sound.o          \
-               $(O)/z_zone.o                   \
-               $(O)/info.o                             \
-               $(O)/sounds.o
+SRC_DOOM = i_main.o dummy.o am_map.o doomdef.o doomstat.o dstrings.o d_event.o d_items.o d_iwad.o d_loop.o d_main.o d_mode.o d_net.o f_finale.o f_wipe.o g_game.o hu_lib.o hu_stuff.o info.o i_cdmus.o i_endoom.o i_joystick.o i_scale.o i_sound.o i_system.o i_timer.o memio.o m_argv.o m_bbox.o m_cheat.o m_config.o m_controls.o m_fixed.o m_menu.o m_misc.o m_random.o p_ceilng.o p_doors.o p_enemy.o p_floor.o p_inter.o p_lights.o p_map.o p_maputl.o p_mobj.o p_plats.o p_pspr.o p_saveg.o p_setup.o p_sight.o p_spec.o p_switch.o p_telept.o p_tick.o p_user.o r_bsp.o r_data.o r_draw.o r_main.o r_plane.o r_segs.o r_sky.o r_things.o sha1.o sounds.o statdump.o st_lib.o st_stuff.o s_sound.o tables.o v_video.o wi_stuff.o w_checksum.o w_file.o w_file_stdc_unbuffered.o w_main.o w_wad.o z_zone.o
+OBJS += $(addprefix $(OBJDIR)/, $(SRC_DOOM))
 
-all:    $(O)/fdoom
+all:    $(OUTPUT)
 
 clean:
-       rm -f *.o *~ *.flc
-       rm -f frosted/*.o
-       rm -f frosted/fdoom
+       rm -rf $(OBJDIR)
+       rm -f $(OUTPUT)
+       rm -f $(OUTPUT).gdb
+       rm -f $(OUTPUT).map
 
-$(O)/fdoom:    $(OBJS) $(O)/i_main.o
+$(OUTPUT):     $(OBJS)
        @echo [Linking $@]
-       $(VB)$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(O)/i_main.o \
-       -o $(O)/fdoom $(LIBS) -Wl,-Map,fdoom.map
+       $(VB)$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) \
+       -o $(OUTPUT) $(LIBS) -Wl,-Map,$(OUTPUT).map
+       @echo [Size]
+       -$(CROSS_COMPILE)size $(OUTPUT)
+       -$(CROSS_COMPILE)flthdr $(OUTPUT)
 
-$(O):
-       mkdir -p $(O)
+$(OBJS): | $(OBJDIR)
 
-$(O)/%.o:      %.c $(O)
+$(OBJDIR):
+       mkdir -p $(OBJDIR)
+
+$(OBJDIR)/%.o: %.c
        @echo [Compiling $<]
        $(VB)$(CC) $(CFLAGS) -c $< -o $@
 
+print:
+       @echo OBJS: $(OBJS)
+
 #############################################################
 #
 #############################################################
diff --git a/frosted-doom/README.asm b/frosted-doom/README.asm
deleted file mode 100644 (file)
index 8962976..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-
-README - DOOM assembly code
-
-Okay, I add the DOS assembly module for the historically
-inclined here (may rec.games.programmer suffer). If anyone
-feels the urge to port these to GNU GCC; either inline or
-as separate modules including Makefile support, be my guest.
-
-Module tmap.S includes the inner loops for texture mapping,
-the interesting one being the floor/ceiling span rendering.
-
-There was another module in the source dump, fpfunc.S, that
-had both texture mapping and fixed point functions. It
-contained implementations both for i386 and M68k. For
-brevity, I include only the i386 fixed point stuff below.
-
-//====================================================
-// tmap.S  as of January 10th, 1997
-
-//================
-//
-// R_DrawColumn
-//
-//================
-
-       .data
-loopcount      .long   0
-pixelcount     .long   0
-
-       .text
-
-       .align 16
-.globl _R_DrawColumn
-_R_DrawColumn:
-
-       pushad
-
-       movl            ebp,[_dc_yl]
-       movl            ebx,ebp
-       movl     edi,[_ylookup+ebx*4]
-       movl            ebx,[_dc_x]
-       addl     edi,[_columnofs + ebx*4]
-
-       movl            eax,[_dc_yh]
-       incl            eax
-       subl     eax,ebp                        // pixel count
-       movl            [pixelcount],eax                        // save for final pixel
-       js              done                                            // nothing to scale
-       shrl            eax,1                                           // double pixel count
-       movl            [loopcount],eax
-       
-       movl     ecx,[_dc_iscale]
-
-       movl            eax,[_centery]
-       subl            eax,ebp
-       imull   ecx
-       movl            ebp,[_dc_texturemid]
-       subl            ebp,eax
-       shll            ebp,9                                                   // 7 significant bits, 25 frac
-
-       movl     esi,[_dc_source]
-       
-
-       movl            ebx,[_dc_iscale]
-       shll            ebx,9
-       movl            eax,OFFSET patch1+2             // convice tasm to modify code...
-       movl            [eax],ebx
-       movl            eax,OFFSET patch2+2             // convice tasm to modify code...
-       movl            [eax],ebx
-       
-// eax         aligned colormap
-// ebx         aligned colormap
-// ecx,edx     scratch
-// esi         virtual source
-// edi         moving destination pointer
-// ebp         frac
-       
-       movl    ecx,ebp                                 // begin calculating first pixel
-       addl    ebp,ebx                                 // advance frac pointer
-       shrl ecx,25                                     // finish calculation for first pixel
-       movl    edx,ebp                                 // begin calculating second pixel
-       addl    ebp,ebx                                 // advance frac pointer
-       shrl edx,25                                     // finish calculation for second pixel
-       movl eax,[_dc_colormap]
-       movl ebx,eax
-       movb    al,[esi+ecx]                    // get first pixel
-       movb    bl,[esi+edx]                    // get second pixel
-       movb    al,[eax]                                // color translate first pixel
-       movb    bl,[ebx]                                // color translate second pixel
-       
-       testl   [pixelcount],0fffffffeh
-       jnz     doubleloop                              // at least two pixels to map
-       jmp     checklast
-       
-       .align  16
-doubleloop:
-       movl    ecx,ebp                                 // begin calculating third pixel
-patch1:
-       addl    ebp,12345678h                   // advance frac pointer
-       movb    [edi],al                                // write first pixel
-       shrl ecx,25                                     // finish calculation for third pixel
-       movl    edx,ebp                                 // begin calculating fourth pixel
-patch2:
-       addl    ebp,12345678h                   // advance frac pointer
-       movl    [edi+SCREENWIDTH],bl    // write second pixel
-       shrl edx,25                                     // finish calculation for fourth pixel
-       movb    al,[esi+ecx]                    // get third pixel
-       addl    edi,SCREENWIDTH*2               // advance to third pixel destination
-       movb    bl,[esi+edx]                    // get fourth pixel
-       decl    [loopcount]                             // done with loop?
-       movb    al,[eax]                                // color translate third pixel
-       movb    bl,[ebx]                                // color translate fourth pixel
-       jnz     doubleloop
-       
-// check for final pixel
-checklast:
-       testl   [pixelcount],1
-       jz      done
-       movb    [edi],al                                // write final pixel
-       
-done:
-       popad
-       ret
-       
-
-
-//================
-//
-// R_DrawSpan
-//
-// Horizontal texture mapping
-//
-//================
-
-
-       .align  16
-.globl _R_DrawSpan
-_R_DrawSpan:
-       pushad
-
-//
-// find loop count
-//     
-       movl            eax,[_ds_x2]
-       incl            eax
-       subl     eax,[_ds_x1]                   // pixel count
-       movl            [pixelcount],eax                        // save for final pixel
-       js              hdone                                           // nothing to scale
-       shrl            eax,1                                           // double pixel count
-       movl            [loopcount],eax
-
-//
-// build composite position
-//
-       movl    ebp,[_ds_xfrac]
-       shll    ebp,10
-       andl    ebp,0ffff0000h
-       movl    eax,[_ds_yfrac]
-       shrl    eax,6
-       andl    eax,0ffffh
-       orl     ebp,eax
-
-       movl    esi,[_ds_source]
-
-//
-// calculate screen dest
-//
-       movl    edi,[_ds_y]
-       movl    edi,[_ylookup+edi*4]
-       movl    eax,[_ds_x1]
-       addl edi,[_columnofs+eax*4]
-
-//
-// build composite step
-//
-       movl    ebx,[_ds_xstep]
-       shll    ebx,10
-       andl    ebx,0ffff0000h
-       movl    eax,[_ds_ystep]
-       shrl    eax,6
-       andl    eax,0ffffh
-       orl     ebx,eax
-
-       movl            eax,OFFSET hpatch1+2            // convice tasm to modify code...
-       movl            [eax],ebx
-       movl            eax,OFFSET hpatch2+2            // convice tasm to modify code...
-       movl            [eax],ebx
-       
-// eax         aligned colormap
-// ebx         aligned colormap
-// ecx,edx     scratch
-// esi         virtual source
-// edi         moving destination pointer
-// ebp         frac
-       
-       shldl ecx,ebp,22                                // begin calculating third pixel (y units)
-       shldl ecx,ebp,6                         // begin calculating third pixel (x units)
-       addl    ebp,ebx                                 // advance frac pointer
-       andl ecx,4095                           // finish calculation for third pixel
-       shldl edx,ebp,22                                // begin calculating fourth pixel (y units)
-       shldl edx,ebp,6                         // begin calculating fourth pixel (x units)
-       addl    ebp,ebx                                 // advance frac pointer
-       andl edx,4095                           // finish calculation for fourth pixel
-       movl eax,[_ds_colormap]
-       movl ebx,eax
-       movb    al,[esi+ecx]                    // get first pixel
-       movb    bl,[esi+edx]                    // get second pixel
-       movb    al,[eax]                                // color translate first pixel
-       movb    bl,[ebx]                                // color translate second pixel
-       
-       testl   [pixelcount],0fffffffeh
-       jnz     hdoubleloop                             // at least two pixels to map
-       jmp     hchecklast
-       
-
-       .align  16
-hdoubleloop:
-       shldl ecx,ebp,22                                // begin calculating third pixel (y units)
-       shldl ecx,ebp,6                         // begin calculating third pixel (x units)
-hpatch1:
-       addl    ebp,12345678h                   // advance frac pointer
-       movb    [edi],al                                // write first pixel
-       andl ecx,4095                           // finish calculation for third pixel
-       shldl edx,ebp,22                                // begin calculating fourth pixel (y units)
-       shldl edx,ebp,6                         // begin calculating fourth pixel (x units)
-hpatch2:
-       addl    ebp,12345678h                   // advance frac pointer
-       movb    [edi+1],bl                              // write second pixel
-       andl edx,4095                           // finish calculation for fourth pixel
-       movb    al,[esi+ecx]                    // get third pixel
-       addl    edi,2                                   // advance to third pixel destination
-       movb    bl,[esi+edx]                    // get fourth pixel
-       decl    [loopcount]                             // done with loop?
-       movb    al,[eax]                                // color translate third pixel
-       movb    bl,[ebx]                                // color translate fourth pixel
-       jnz     hdoubleloop
-
-// check for final pixel
-hchecklast:
-       testl   [pixelcount],1
-       jz      hdone
-       movb    [edi],al                                // write final pixel
-       
-hdone:
-       popad
-       ret
-
-
-
-
-//====================================================
-// fpfunc.S  as of January 10th, 1997 (parts)
-
-#ifdef i386
-
-.text
-       .align 4
-.globl _FixedMul
-_FixedMul:     
-       pushl %ebp
-       movl %esp,%ebp
-       movl 8(%ebp),%eax
-       imull 12(%ebp)
-       shrdl $16,%edx,%eax
-       popl %ebp
-       ret
-
-
-       .align 4
-.globl _FixedDiv2
-_FixedDiv2:
-       pushl %ebp
-       movl %esp,%ebp
-       movl 8(%ebp),%eax
-       cdq
-       shldl $16,%eax,%edx
-       sall    $16,%eax
-       idivl   12(%ebp)
-       popl %ebp
-       ret
-
-#endif
-
diff --git a/frosted-doom/README.b b/frosted-doom/README.b
deleted file mode 100644 (file)
index 3d2fa2f..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-
-README for Linux DOOM Source distribution
-=========================================
-
-
-DISCLAIMER
-----------
-This is not "The DOOM Source Code" dump for a bunch
-of reasons. It is based on a DOOM development directory
-snapshot as of January 10th, but has been stripped and
-changed. Thus it is the DOOM source, but there are many
-minor differences to the source as last used by id
-Software.
-
-Note that thus neither John Carmack nor Dave Taylor nor
-anybody else at id is responsible for the contents of
-this archive, or the changes introduced to the original
-source.
-
-If there are any questions, contact me at bk@gamers.org,
-or preferably post to the mailing list at
-
-                doom-editing@gamers.org
-
-(send mail to majordomo@gamers.org, content just
-a single "info doom-editing"). I will post any updates
-or notifcation of corrections there. I will probably
-put some stuff at 
-
-          http://www.gamers.org/dEngine/doom/
-
-as well. Look there for the "Unofficial DOOM Specs" as
-minimal recommended documentation.
-
-
-
-REMARKS
--------
-I made a few minor bug fixes, added some experimental sound
-code, and, and changed the handling of IWAD dependend game
-modes. Most of the changes though have been shuffling
-around sources in a sometimes futile attempt to separate
-modules more cleanly, and make certain parts easier
-to locate and modify. There is still much left to do, but
-I hope that the current source is a good base to start
-with, especially with a cooperative effort in mind. Those
-so inclined will find the source prepared for CVS.  
-
-There is a list of changes and fixes I did not get around
-to in TODO, and an incomplete worklog in ChangeLog, that
-also includes some minor ToDo statements scattered throughout
-the log. 
-
-
-a) Linux SVGA
-There is no SVGA support. For development and debug
-purposes, the X11 version seems to be more handy.
-
-b) Sound - see README.sound,
-    and the sndserver.tgz archive.
-
-c) GLDOOM - see README.gl
-
-d) Win32
-There was no Win32 support in the original dump.
-
-e) DOS
-Original DOS support (including the texture
-mapping and fixed point assembler) has been
-removed, mainly because of the lack of sound
-support.
-
-f) DoomEd
-The NeXTStep DoomEd sources in the dump were
-garbled (filenames - prolly an issue of ISO9660
-with or w/o extensions). Somehow  Bear never got
-around to send me a list of the correct filenames,
-and I won't bother guessing without a NeXT box
-at hand.
-
-There is a plethora of useful editors
-for DOOM. I suggest using DEU for X11.
-
-g) BSP Tools
-The BSP builder and other tools have
-been released by John Carmack long ago,
-and since improved/replaced by others.
-Again, I recommend taking a pick among
-the tools available for Linux.  
-
-h) DOOM game tools
-There are a number of tools that have
-not been released, namely those which
-compiled the Things and State Tables,
-the frame animation LUT's, sound tables
-etc. Basically, they compile similarly
-complex LUT's to generate C files. The
-tools are omitted from this distribution.
-
-There are some files in the
-distribution (info.h/c, sounds.h/c)
-that are essentially the output of these
-tools. This is the data that defines
-DOOM (as a game) for all practical
-purposes.
-
-I recommend keeping them, as they are
-part of the source. In the long run,
-handling them as well as the action/
-animation functions as a separate game.so
-library (as with Quake2) seems to be a
-good idea.
-
-i) Artwork
-Neither the original artwork nor the
-misc. WAD files are included in this
-archive. You will at least need the
-shareware WAD file to run the executable,
-but it shouldn't be to difficult to get
-a hold of that.
-
-Note that the mechanism to detect the
-presence of a registered or commercial
-version is still in the source, and
-homebrew maps are still disabled. This
-is easily removed now, but as FinalDOOM,
-Ultimate DOOM and DOOM 2 are still in
-the shops, it is probably polite not
-to distribute a source or binary without
-that mechanism.
-
-This version of Linuxdoom supports Plutonia
-and TNT WAD from FinalDOOM as well. No
-guarantees, though.
-
-
-Enjoy!
-
-                          b. 97/12/22
diff --git a/frosted-doom/README.book b/frosted-doom/README.book
deleted file mode 100644 (file)
index 0fe5949..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-
-The DOOM Book
-
-Shortly after the Wolfenstein 3D source release,
-I sent a mail to Jay Wilbur suggesting a book
-about the DOOM engine. I anticipated a similar
-release of the DOOM sources within a year or
-two, and the obvious problems with the Wolfenstein
-sources (lack of accompanying artwork, a code 
-base not maintained for quite some time) seemed
-to demand a better approach. I talked to some
-publishing company reps at the Book Fair in 1995,
-and while they were cautiously interested, id was
-not.
-
-In the last weeks of 1996, following a visit at
-id Software two months earlier, and after the
-departure of Jay Wilbur, John Carmack asked me
-whether I was still interested in doing the book.
-I was, Bear sent me a code dump, and  Todd
-Hollenshead set out to address the legal concerns
-(of which were many).
-
-Unfortunately, what might have worked in 1995
-turned out to be a doomed attempt in 1997. I won't
-go into the details - let's just say that my
-leaving university and going back to full time
-writing for a living repeatedly forced me to
-change priorities on what looked more and more
-like a project unlikely to generate any revenue.
-
-By mid of the year, when the legal issues had
-finally been settled, it didn't look like I was
-going to find a publisher at all. Following the
-Book Fair in 1997 and some more discussions
-(with about a dozen publishers, total), I gritted
-my teeth and decided to abandon the project.
-
-Note that the book project as such wasn't supposed
-to hold up the source release to the public.
-However, given the legal concerns relating to
-the third party sound code in DOS DOOM, and the
-lack of Win32 support as well as the advantages of
-an OpenGL based release, the idea was to put
-together a consistent, stable code base prior to
-public release - most of which was supposed to be
-an offspring of my reformatting and modifying the
-code for the book.
-
-None of this worked out as intended. However, I
-hope that, at long last, this distribution
-will finally provide a good point to start for
-any cooperative effort to extend the already
-impressive lifespan of DOOM into the age of
-multiplayer servers and hardware-accelerated
-clients.
-
diff --git a/frosted-doom/README.gl b/frosted-doom/README.gl
deleted file mode 100644 (file)
index df443a9..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-
-README: glDOOM
-
-I never got around to do anything with respect to
-a Linux glDOOM port except for assembling a Linux3Dfx
-HOWTO (which, at that time, was a prerequisite
-to get permission to publicly distribute the
-already finished LinuxGlide port by Daryll Strauss).
-
-Linux q2test (and soon LinuxQuake2) demonstrate that
-Mesa with the MesaVoodoo driver is quite up to the
-requirements for a glDOOM port. If anybody wants to
-get into Linux glDOOM, please drop me a line.
-
-There is a Win32 GLDOOM port in the works, by Jim Dose.
-Quoting a recent posting by him:
-
-"I haven't had as much time lately to really work on
-the conversion. I currently have the renderer drawing
-the walls and floors as texture spans as the are in
-the software renderer. There's lighting on the walls,
-but not the floors, and sprites are being drawn, but
-not with the right texture. I figure that this is one
-nights work to get the game looking "normal". I haven't
-tested the game on less than a p200, so I'm not sure
-how it will perform under the average machine, but I
-don't expect it to be blindingly fast because of the
-number of spans that have to be drawn each frame.
-Rendering as polys is definitely the way to go.
-
-The reason I chose to do spans first was because it
-left the base renderer intact and I could concentrate
-on ironing out any Windows compatibility problems.
-Actually, the first version I had running was simply
-a blit of the 320x200 game screen through Open GL.
-Surprisingly, this actually was very playable, but
-certainly wasn't taking any advantage of 3D acceleration.
-Once the game was running, I started converting all
-the span routines over."
-
-Comment: for merging Linuxdoom with Win32, this is
-probably the best source for getting the Win32
-environment done - before more significant changes
-occur.
-
-"One problem with drawing spans is that the engine
-doesn't calculate the texture coordinates with
-fractional accuracy, so the bilinear filtering works
-vertically, but not horizontally on the walls. I may
-try to fix this, but since I plan to use polys for
-the final version, it's not really high priority.
-Also, spans don't really allow for looking up and
-down."
-
-Comment: true looking up/down vs. Heretic-style
-y-shearing seems to require either a strange kind
-of transofrmation matrix (he probably does not use
-the OpenGL transformation at all), or rendering
-all the spans as textured rectangular slices
-instead of using glDrawBitmap. No, polys are the
-way to go.
-   
-"When I tackle the conversion to polys, one big problem
-I'll encounter is drawing floors. Since the world is
-stored in a 2D bsp tree, there is no information on
-the shape of the floors. In fact the floors can be
-concave and may include holes (typically, most renderers
-break concave polys down into a collection of convex
-polys or triangles). In software, the floors are actually
-drawn using an algorithm that's similar to a flood fill
-(except that a list of open spans is kept instead of a
-buffer of pixels).  This makes drawing the floors as
-polys fairly difficult."
-
-A polygon based approach will require significant changes
-to the data structures used in the refresh module. I
-recommend either separating a libref_soft.so first (a
-Quake2 like approach), and creating libref_gl afterwards,
-or abandoning the software rendering entirely.
-
-John Carmack wrote once upon a time:
-"... the U64 DOOM engine is much more what I would consider
-The Right Thing now -- it turns the subsector boundaries
-into polygons for the floors and ceilings ahead of time,
-then for rendering it walks the BSP front to back, doing
-visibility determination of subsectors by the one dimensional
-occlusion buffer and clipping sprites into subsectors, then
-it goes backwards through the visible subsectors, drawing
-floors, ceilings, walls, then sorted internal sprite fragments.
-It's a ton simpler and a ton faster, although it does suffer
-some overdraw when a high subsector overlooks a low one (but
-that is more than made up for by the simplicity of everything
-else)."
-
-Well, IMO compiling a separate list of floor/ceiling polygons
-after having read the WAD file, and thus introducing this as
-a completely separate data structure to the current code base
-might be the easiest thing to do. Jim Dose writes:
-
-"One method I may use to draw the floors as polys was suggested
-by Billy Zelsnack of Rebel Boat Rocker when we were working
-at 3D Realms together a few years ago. Basically, Billy was
-designing an engine that dealt with the world in a 2D portal
-format similar to the one that Build used, except that it had
-true looking up and down (no shearing). Since floors were
-basically implicit and could be concave, Billy drew them as
-if the walls extended downwards to infinity, but fixed the
-texture coordinates to appear that they were on the plane of
-the floor. The effect was that you could look up and down and
-there were no gaps or overdraw. It's a fairly clever method
-and allows you to store the world in a simpler data format.
-Had perspective texture mapping been fast enough back then,
-both Build and Doom could have done this in software."
-
-Perhaps the above is sufficient to get you started.
-Other Issues:
-
-1. Occlusion
-DOOM uses a per-column lookup (top/bottom index) to do HLHSR.
-This works fine with span based rendering (well, getting
-horizontal spans of floors/ceilings into the picture is a
-separate story). It isn't really mindboggling with polygon
-based rendering. GLDOOM should abandon that.
-
-2. Precalculated Visibility
-DOOM has the data used by Quake's PVS - in REJECT.
-During Quake development, lots of replacements for the
-occlusion buffer were tried, and PVS turned out to be best.
-I suggest usind the REJECT as PVS.
-
-There have been special effects using a utility named RMB.
-REJECT is a lump meant for enemy AI LoS calculation - a
-nonstandard REJECT will not work as a PVS, and introduce
-rendering errors. I suggest looking for a PVS lump in the
-WAD, and using REJECT if none is found. That way, it might
-be feasible to eat the cake and keep it.
-
-3. Mipmaps
-DOOM does not have mipmapping. As we have 8bit palettized
-textures, OpenGL mipmapping might not give the desired
-results. Plus, composing textures from patches at runtime
-would require runtime mipmapping. Precalculated mipmaps
-in the WAD?
-
-4. Sprites
-Partly transparent textures and sprites impose another
-problem related to mipmapping. Without alpha channel,
-this could give strange results. Precalculated, valid
-sprite mipmaps (w/o alpha)?
diff --git a/frosted-doom/README.sound b/frosted-doom/README.sound
deleted file mode 100644 (file)
index 79541b4..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-
-README: sound in DOOM
-
-
-1) DOS/Win32 sound
-
-id licensed a third party sound library called
-DMX for DOS DOOM. The situation exhibited
-many symptons of serious NIH "Not Invented Here"),
-and one of the consequences is that the original
-DOOM sound code does not work without DMX. As
-DMX is not publicly available, the original DOOM
-sound support is removed.
-
-Win32 was not supported in the source dump I got.
-I have no knowledge how the WinDOOM port did the
-sound handling. A Win32 port should probaly rely on
-DirectSound. So far, the Win32 glDOOM port Jim Dose
-is working on has no sound support.
-
-In consequence, the only target with a working sound
-code is UNIX, which I could only verify with Linux
-on Intel586.
-
-2) Linux sound
-
-DOOM for Linux used a separate process, sndserver.
-
-Quoting Dave Taylor:
-
-"Sound drivers should be an asychronous model, either
-a seperate thread or a seperate process.  This is
-because sound should always be fed to the card without
-interruption or else you get pops and with low latency
-or else you get angry players.
-
-Now it turns out that this kind of code isn't too fun
-to write. In the days of Linux Doom, threads were not a
-happnin thing in Linux. In fact, they still largely
-aren't. You can use them these days if you have gnu's
-libc installed, but you still can't debug them because
-gdb doesn't support them properly yet. I believe the
-original seperate process had a bad latency delay
-because of the time it took for commands to be flushed
-through the pipe used to communicate with the seperate
-process.  I should have looked into this more thoroughly.
-
-In Quake, I discovered that I could feed multiple
-acknowledgements to a SoundBlaster or compatible without
-any side-effects such as pops or other malfunctions. 
-This discovery led me to switch to a completely synchronous
-model, much much easier to debug and understand, so I
-think this was fairly intelligent.  Although we had to
-populate the game with calls in the right places to keep
-the sound buffers fed, and although it wasn't gauranteed to
-be always fed, well over 99% of the time, it was fed, and
-your the latency was never worse than the frequency of your
-refills (several times per frame) plus a small lead time
-(40th of a second?)."
-
-The separate sndserver code base introduced some redundancy
-(WAD access for sound lumps) for each UNIX target (Sun, SGI,
-Linux) and more differences between DOS and UNIX version.
-However, I kept the IPC based parts in the source, and
-separated the sndserver target in another directory to avoid
-further redundancy. There seem to be a few bug-like things
-going on in the sndserver that do not receive penalty as
-the program has to do only a simple task. One example would
-be a libc realloc mixed with zone memory allocation. 
-
-Ungraceful and untimely demise of Linuxdoom (core instead
-of I_Error) will leave idle sndserver processes in your
-system, blocking /dev/bsp. Kill them manually.
-
-I put the non-redundant parts of the sndserver program
-into the i_sound module of doom, and with the SND_SERV
-compiler switch you can choose to use the internal sound
-support. However, there is a problem with e.g. the
-double shotgun and the plasma gun - walk up to a wall,
-face it straight, and fire. The sound output is crappy.
-This vanishes with decreasing screen size. A similar
-problem occurs with trimer driven asynchronous output
-enabled by SNDINTR.
-
-I agree with Dave that threads would be preferable.
-With respect to Linux ports of John Carmack's next
-Trinity engine, this one will rely on Win32
-multithreading e.g. for input sampling. So the Linux
-community will have to sort out threads anyway :-).
-
-To improve the current sound server, other means of
-IPC should take care of the latency. The mixing
-buffer/command buffer as shared memory comes to mind.
-
-
-
-3) Music support
-
-There is, and was, no music support in Linuxdoom. Fine with
-me - I wouldn't give a bat's tail feathers for DOOM music.
-Your mileage may vary. There are a few leftovers of the DOS
-music support also interfacing DMX, so there is a place
-to start. However, in the age of CDROM based music, I
-recommend getting e.g. Workman to cooperate with DOOM
-(currently, DOOM accessing the soundcard SpekerOut
-interferes with Workman controlling the CD drives
-SpeakerOut), so musci could be chosen and run completely
-independend of the game. You could try Linuxdoom with
-Q2 music that way.
-
diff --git a/frosted-doom/TODO b/frosted-doom/TODO
deleted file mode 100644 (file)
index 89529c9..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-
-- create Web repository for sources, patches,
-  news, and pointer to doom-editing mailing
-  list.
-
-- get DOOM Public License from id
-
------------------------------------------------
-
-- remove m_fixed, switch to floating point
-  More stable, and prolly even faster.
-
-- make SCREENWIDTH/HEIGHT work at startup?
-  Well, the HUD/STBar stuff is tied to the
-  scales implied by the graphics. Rather do
-  GLDOOM and use texture mapping.
-
-- fix aspect ratio?
-  320x200 is nothing viable nowadays.
-  A 320x240 base (4:3) would be a lot better.
-  See above on width/height.
-- limited look up/down by y-shearing?
-  Prolly not worth it, rather switch to GLDOOM.
-
-- switch to C++?
-  The action function pointers have varying
-  argument lists (no parameter, one, etc.).
-  C++ doesn't like that much. A major rewrite.
-
-- switch to doommain.c plus libdoom? Have 
-  libref, libgame etc.?
-  Another major rewrite.
-
-- use XFree86 DGA, prolly not that much faster
-  than MIT SHM, but allows for directly sampled
-  mouse (and even freelook). Recommended for
-  GLDOOM.
-
-- put together an accompanying developer toolkit
-  source distribution: DEU, RMB, BSP for Linux/X.
-
-- move info.h, info.c, sounds.h, sounds.c and
-  other data to a separate lump in the WAD,
-  or into a libgame.so, to separate the 
-  generic stuff (refresh, I/O) from the
-  DOOM specifics.
-
-- decide whether precaching all sounds is
-  better than retrieving and releasing
-  every so often. DOOM seems to do that
-  frequently (8bit stuff, originally for
-  DOS), and the Linux sound is 16bit
-  (conversion in the mixing, requires
-  some padding) - we prolly got the memory
-  to spare.
-
-- 16bpp CLUT. The lightmaps and the
-  framebuffer could be changed to switch
-  to 64K colors. Prolly better to do
-  GLDOOM right away.
-
-- remove checks for commercial etc., in
-   non-essential issues (enabling PWAD's).
-
-- change (simplify) determination of
-   sky texture (done by game version).
-   Explicit?
-
-- remove all game version checks
-
-- different handling of Demo - don't
-   exit on "different game version"
-
-- how about shareware/retail "You are here"
-   intermission animation? Wasn't in
-   commercial (DOOM 2).
-
-- double shotgun in DOOM1, all weapons with
-   shareware
-
-- checks for required lumps. We need fallbacks
-   for lumps that are not present, that is,
-   default sounds etc. to be used instead,
-   or removing THINGS w/o sprites etc.
-
-- client/server? I'd suggest ripping off some stuff
-   from the abandoned IBM WebView project
-
-- Blockmap
-   The BLOCKMAP lump might be (partly) redundant,
-   as the BSP allows for clipping (except certain
-   LineDefs that will not spawn Segs).
-
-- LOS
-   REJECT and intersection based LOS checking could be
-   done using the BSP. In case of REJECT, certain
-   monster AI special effects would be lost, though.
-
-- correct handling of height in collision. This is
-   not done, and the checks are scattered around in
-   many places. It does require handling of "player
-   on top of monster" situations, too - we have to 
-   make sure the players falls off far enough to
-   avoid getting "stuck in monster".
-
-- remove obsolete menus (Detail. Music Volume?)
-
-- clip explosion range damage (and sprites) using
-   REJECT? That is, if one Sector/SSector not
-   visible from the other, do not apply damage,
-   not render sprite if player in other sector.
-   Hmmm - explosion behind small pillar might not be
-   visible at all, but do we care?
-
-
-- Ungraceful and untimely demise of Linuxdoom (core
-   instead of I_Error) will leave idle sndserver
-   processes in your system, blocking /dev/bsp.
-  A timeout on lack of input for "sndserver"?
-
-- threaded sndserver? SHM mixing buffer?
-   Or internal, timer-based?
index 84c9cf7baecf0d58362329a18a4ed97d4d46f4e6..d3d504e326c7ee4f4d6145365d01cd896d16b6e0 100644 (file)
@@ -1,38 +1,36 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
-// $Log:$
 //
 // DESCRIPTION:  the automap code
 //
-//-----------------------------------------------------------------------------
 
-static const char rcsid[] = "$Id: am_map.c,v 1.4 1997/02/03 21:24:33 b1 Exp $";
 
 #include <stdio.h>
 
+#include "deh_main.h"
 
 #include "z_zone.h"
+#include "doomkeys.h"
 #include "doomdef.h"
 #include "st_stuff.h"
 #include "p_local.h"
 #include "w_wad.h"
 
 #include "m_cheat.h"
+#include "m_controls.h"
+#include "m_misc.h"
 #include "i_system.h"
 
 // Needs access to LFB.
@@ -85,21 +83,6 @@ static const char rcsid[] = "$Id: am_map.c,v 1.4 1997/02/03 21:24:33 b1 Exp $";
 #define XHAIRCOLORS    GRAYS
 
 // drawing stuff
-#define        FB              0
-
-#define AM_PANDOWNKEY  KEY_DOWNARROW
-#define AM_PANUPKEY    KEY_UPARROW
-#define AM_PANRIGHTKEY KEY_RIGHTARROW
-#define AM_PANLEFTKEY  KEY_LEFTARROW
-#define AM_ZOOMINKEY   '='
-#define AM_ZOOMOUTKEY  '-'
-#define AM_STARTKEY    KEY_TAB
-#define AM_ENDKEY      KEY_TAB
-#define AM_GOBIGKEY    '0'
-#define AM_FOLLOWKEY   'f'
-#define AM_GRIDKEY     'g'
-#define AM_MARKKEY     'm'
-#define AM_CLEARMARKKEY        'c'
 
 #define AM_NUMMARKPOINTS 10
 
@@ -168,7 +151,6 @@ mline_t player_arrow[] = {
     { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }
 };
 #undef R
-#define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t))
 
 #define R ((8*PLAYERRADIUS)/7)
 mline_t cheat_player_arrow[] = {
@@ -190,25 +172,22 @@ mline_t cheat_player_arrow[] = {
     { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } }
 };
 #undef R
-#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t))
 
 #define R (FRACUNIT)
 mline_t triangle_guy[] = {
-    { { -.867*R, -.5*R }, { .867*R, -.5*R } },
-    { { .867*R, -.5*R } , { 0, R } },
-    { { 0, R }, { -.867*R, -.5*R } }
+    { { (fixed_t)(-.867*R), (fixed_t)(-.5*R) }, { (fixed_t)(.867*R ), (fixed_t)(-.5*R) } },
+    { { (fixed_t)(.867*R ), (fixed_t)(-.5*R) }, { (fixed_t)(0      ), (fixed_t)(R    ) } },
+    { { (fixed_t)(0      ), (fixed_t)(R    ) }, { (fixed_t)(-.867*R), (fixed_t)(-.5*R) } }
 };
 #undef R
-#define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t))
 
 #define R (FRACUNIT)
 mline_t thintriangle_guy[] = {
-    { { -.5*R, -.7*R }, { R, 0 } },
-    { { R, 0 }, { -.5*R, .7*R } },
-    { { -.5*R, .7*R }, { -.5*R, -.7*R } }
+    { { (fixed_t)(-.5*R), (fixed_t)(-.7*R) }, { (fixed_t)(R    ), (fixed_t)(0    ) } },
+    { { (fixed_t)(R    ), (fixed_t)(0    ) }, { (fixed_t)(-.5*R), (fixed_t)(.7*R ) } },
+    { { (fixed_t)(-.5*R), (fixed_t)(.7*R ) }, { (fixed_t)(-.5*R), (fixed_t)(-.7*R) } }
 };
 #undef R
-#define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t))
 
 
 
@@ -272,7 +251,7 @@ static fixed_t old_m_x, old_m_y;
 static mpoint_t f_oldloc;
 
 // used by MTOF to scale from map-to-frame-buffer coords
-static fixed_t scale_mtof = INITSCALEMTOF;
+static fixed_t scale_mtof = (fixed_t)INITSCALEMTOF;
 // used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof)
 static fixed_t scale_ftom;
 
@@ -284,23 +263,10 @@ static int markpointnum = 0; // next point to be assigned
 
 static int followplayer = 1; // specifies whether to follow the player around
 
-static unsigned char cheat_amap_seq[] = { 0xb2, 0x26, 0x26, 0x2e, 0xff };
-static cheatseq_t cheat_amap = { cheat_amap_seq, 0 };
+cheatseq_t cheat_amap = CHEAT("iddt", 0);
 
 static boolean stopped = true;
 
-extern boolean viewactive;
-//extern byte screens[][SCREENWIDTH*SCREENHEIGHT];
-
-
-
-void
-V_MarkRect
-( int  x,
-  int  y,
-  int  width,
-  int  height );
-
 // Calculates the slope and slope according to the x-axis of a line
 // segment in map coordinates (with the upright y-axis n' all) so
 // that it can be used with the brain-dead drawing stuff.
@@ -314,9 +280,9 @@ AM_getIslope
 
     dy = ml->a.y - ml->b.y;
     dx = ml->b.x - ml->a.x;
-    if (!dy) is->islp = (dx<0?-MAXINT:MAXINT);
+    if (!dy) is->islp = (dx<0?-INT_MAX:INT_MAX);
     else is->islp = FixedDiv(dx, dy);
-    if (!dx) is->slp = (dy<0?-MAXINT:MAXINT);
+    if (!dx) is->slp = (dy<0?-INT_MAX:INT_MAX);
     else is->slp = FixedDiv(dy, dx);
 
 }
@@ -392,8 +358,8 @@ void AM_findMinMaxBoundaries(void)
     fixed_t a;
     fixed_t b;
 
-    min_x = min_y =  MAXINT;
-    max_x = max_y = -MAXINT;
+    min_x = min_y =  INT_MAX;
+    max_x = max_y = -INT_MAX;
   
     for (i=0;i<numvertexes;i++)
     {
@@ -431,7 +397,7 @@ void AM_changeWindowLoc(void)
     if (m_paninc.x || m_paninc.y)
     {
        followplayer = 0;
-       f_oldloc.x = MAXINT;
+       f_oldloc.x = INT_MAX;
     }
 
     m_x += m_paninc.x;
@@ -458,12 +424,12 @@ void AM_changeWindowLoc(void)
 void AM_initVariables(void)
 {
     int pnum;
-    static event_t st_notify = { ev_keyup, AM_MSGENTERED };
+    static event_t st_notify = { ev_keyup, AM_MSGENTERED, 0, 0 };
 
     automapactive = true;
-    fb = screens[0];
+    fb = I_VideoBuffer;
 
-    f_oldloc.x = MAXINT;
+    f_oldloc.x = INT_MAX;
     amclock = 0;
     lightlev = 0;
 
@@ -475,12 +441,24 @@ void AM_initVariables(void)
     m_h = FTOM(f_h);
 
     // find player to center on initially
-    if (!playeringame[pnum = consoleplayer])
+    if (playeringame[consoleplayer])
+    {
+        plr = &players[consoleplayer];
+    }
+    else
+    {
+        plr = &players[0];
+
        for (pnum=0;pnum<MAXPLAYERS;pnum++)
+        {
            if (playeringame[pnum])
+            {
+                plr = &players[pnum];
                break;
-  
-    plr = &players[pnum];
+            }
+        }
+    }
+
     m_x = plr->mo->x - m_w/2;
     m_y = plr->mo->y - m_h/2;
     AM_changeWindowLoc();
@@ -506,7 +484,7 @@ void AM_loadPics(void)
   
     for (i=0;i<10;i++)
     {
-       sprintf(namebuf, "AMMNUM%d", i);
+       DEH_snprintf(namebuf, 9, "AMMNUM%d", i);
        marknums[i] = W_CacheLumpName(namebuf, PU_STATIC);
     }
 
@@ -515,10 +493,13 @@ void AM_loadPics(void)
 void AM_unloadPics(void)
 {
     int i;
+    char namebuf[9];
   
     for (i=0;i<10;i++)
-       Z_ChangeTag(marknums[i], PU_CACHE);
-
+    {
+       DEH_snprintf(namebuf, 9, "AMMNUM%d", i);
+       W_ReleaseLumpName(namebuf);
+    }
 }
 
 void AM_clearMarks(void)
@@ -559,7 +540,7 @@ void AM_LevelInit(void)
 //
 void AM_Stop (void)
 {
-    static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED };
+    static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED, 0 };
 
     AM_unloadPics();
     automapactive = false;
@@ -616,118 +597,138 @@ AM_Responder
 {
 
     int rc;
-    //static int cheatstate=0;
     static int bigstate=0;
     static char buffer[20];
+    int key;
 
     rc = false;
 
     if (!automapactive)
     {
-       if (ev->type == ev_keydown && ev->data1 == AM_STARTKEY)
+       if (ev->type == ev_keydown && ev->data1 == key_map_toggle)
        {
            AM_Start ();
            viewactive = false;
            rc = true;
        }
     }
-
     else if (ev->type == ev_keydown)
     {
-
        rc = true;
-       switch(ev->data1)
-       {
-         case AM_PANRIGHTKEY: // pan right
-           if (!followplayer) m_paninc.x = FTOM(F_PANINC);
-           else rc = false;
-           break;
-         case AM_PANLEFTKEY: // pan left
-           if (!followplayer) m_paninc.x = -FTOM(F_PANINC);
-           else rc = false;
-           break;
-         case AM_PANUPKEY: // pan up
-           if (!followplayer) m_paninc.y = FTOM(F_PANINC);
-           else rc = false;
-           break;
-         case AM_PANDOWNKEY: // pan down
-           if (!followplayer) m_paninc.y = -FTOM(F_PANINC);
-           else rc = false;
-           break;
-         case AM_ZOOMOUTKEY: // zoom out
-           mtof_zoommul = M_ZOOMOUT;
-           ftom_zoommul = M_ZOOMIN;
-           break;
-         case AM_ZOOMINKEY: // zoom in
-           mtof_zoommul = M_ZOOMIN;
-           ftom_zoommul = M_ZOOMOUT;
-           break;
-         case AM_ENDKEY:
-           bigstate = 0;
-           viewactive = true;
-           AM_Stop ();
-           break;
-         case AM_GOBIGKEY:
-           bigstate = !bigstate;
-           if (bigstate)
-           {
-               AM_saveScaleAndLoc();
-               AM_minOutWindowScale();
-           }
-           else AM_restoreScaleAndLoc();
-           break;
-         case AM_FOLLOWKEY:
-           followplayer = !followplayer;
-           f_oldloc.x = MAXINT;
-           plr->message = followplayer ? AMSTR_FOLLOWON : AMSTR_FOLLOWOFF;
-           break;
-         case AM_GRIDKEY:
-           grid = !grid;
-           plr->message = grid ? AMSTR_GRIDON : AMSTR_GRIDOFF;
-           break;
-         case AM_MARKKEY:
-           sprintf(buffer, "%s %d", AMSTR_MARKEDSPOT, markpointnum);
-           plr->message = buffer;
-           AM_addMark();
-           break;
-         case AM_CLEARMARKKEY:
-           AM_clearMarks();
-           plr->message = AMSTR_MARKSCLEARED;
-           break;
-         default:
-           //cheatstate=0;
-           rc = false;
-       }
-       if (!deathmatch && cht_CheckCheat(&cheat_amap, ev->data1))
+        key = ev->data1;
+
+        if (key == key_map_east)          // pan right
+        {
+            if (!followplayer) m_paninc.x = FTOM(F_PANINC);
+            else rc = false;
+        }
+        else if (key == key_map_west)     // pan left
+        {
+            if (!followplayer) m_paninc.x = -FTOM(F_PANINC);
+            else rc = false;
+        }
+        else if (key == key_map_north)    // pan up
+        {
+            if (!followplayer) m_paninc.y = FTOM(F_PANINC);
+            else rc = false;
+        }
+        else if (key == key_map_south)    // pan down
+        {
+            if (!followplayer) m_paninc.y = -FTOM(F_PANINC);
+            else rc = false;
+        }
+        else if (key == key_map_zoomout)  // zoom out
+        {
+            mtof_zoommul = M_ZOOMOUT;
+            ftom_zoommul = M_ZOOMIN;
+        }
+        else if (key == key_map_zoomin)   // zoom in
+        {
+            mtof_zoommul = M_ZOOMIN;
+            ftom_zoommul = M_ZOOMOUT;
+        }
+        else if (key == key_map_toggle)
+        {
+            bigstate = 0;
+            viewactive = true;
+            AM_Stop ();
+        }
+        else if (key == key_map_maxzoom)
+        {
+            bigstate = !bigstate;
+            if (bigstate)
+            {
+                AM_saveScaleAndLoc();
+                AM_minOutWindowScale();
+            }
+            else AM_restoreScaleAndLoc();
+        }
+        else if (key == key_map_follow)
+        {
+            followplayer = !followplayer;
+            f_oldloc.x = INT_MAX;
+            if (followplayer)
+                plr->message = DEH_String(AMSTR_FOLLOWON);
+            else
+                plr->message = DEH_String(AMSTR_FOLLOWOFF);
+        }
+        else if (key == key_map_grid)
+        {
+            grid = !grid;
+            if (grid)
+                plr->message = DEH_String(AMSTR_GRIDON);
+            else
+                plr->message = DEH_String(AMSTR_GRIDOFF);
+        }
+        else if (key == key_map_mark)
+        {
+            M_snprintf(buffer, sizeof(buffer), "%s %d",
+                       DEH_String(AMSTR_MARKEDSPOT), markpointnum);
+            plr->message = buffer;
+            AM_addMark();
+        }
+        else if (key == key_map_clearmark)
+        {
+            AM_clearMarks();
+            plr->message = DEH_String(AMSTR_MARKSCLEARED);
+        }
+        else
+        {
+            rc = false;
+        }
+
+       if (!deathmatch && cht_CheckCheat(&cheat_amap, ev->data2))
        {
            rc = false;
            cheating = (cheating+1) % 3;
        }
     }
-
     else if (ev->type == ev_keyup)
     {
-       rc = false;
-       switch (ev->data1)
-       {
-         case AM_PANRIGHTKEY:
-           if (!followplayer) m_paninc.x = 0;
-           break;
-         case AM_PANLEFTKEY:
-           if (!followplayer) m_paninc.x = 0;
-           break;
-         case AM_PANUPKEY:
-           if (!followplayer) m_paninc.y = 0;
-           break;
-         case AM_PANDOWNKEY:
-           if (!followplayer) m_paninc.y = 0;
-           break;
-         case AM_ZOOMOUTKEY:
-         case AM_ZOOMINKEY:
-           mtof_zoommul = FRACUNIT;
-           ftom_zoommul = FRACUNIT;
-           break;
-       }
+        rc = false;
+        key = ev->data1;
+
+        if (key == key_map_east)
+        {
+            if (!followplayer) m_paninc.x = 0;
+        }
+        else if (key == key_map_west)
+        {
+            if (!followplayer) m_paninc.x = 0;
+        }
+        else if (key == key_map_north)
+        {
+            if (!followplayer) m_paninc.y = 0;
+        }
+        else if (key == key_map_south)
+        {
+            if (!followplayer) m_paninc.y = 0;
+        }
+        else if (key == key_map_zoomout || key == key_map_zoomin)
+        {
+            mtof_zoommul = FRACUNIT;
+            ftom_zoommul = FRACUNIT;
+        }
     }
 
     return rc;
@@ -792,7 +793,7 @@ void AM_updateLightLev(void)
     if (amclock>nexttic)
     {
        lightlev = litelevels[litelevelscnt++];
-       if (litelevelscnt == sizeof(litelevels)/sizeof(int)) litelevelscnt = 0;
+       if (litelevelscnt == arrlen(litelevels)) litelevelscnt = 0;
        nexttic = amclock + 6 - (amclock % 6);
     }
 
@@ -856,9 +857,9 @@ AM_clipMline
        TOP     =8
     };
     
-    register int outcode1 = 0;
-    register int outcode2 = 0;
-    register int outside;
+    register int       outcode1 = 0;
+    register int       outcode2 = 0;
+    register int       outside;
     
     fpoint_t   tmp;
     int                dx;
@@ -950,6 +951,11 @@ AM_clipMline
            tmp.y = fl->a.y + (dy*(-fl->a.x))/dx;
            tmp.x = 0;
        }
+        else
+        {
+            tmp.x = 0;
+            tmp.y = 0;
+        }
 
        if (outside == outcode1)
        {
@@ -989,7 +995,7 @@ AM_drawFline
     register int ay;
     register int d;
     
-    //static fuck = 0;
+    static int fuck = 0;
 
     // For debugging only
     if (      fl->a.x < 0 || fl->a.x >= f_w
@@ -997,7 +1003,7 @@ AM_drawFline
           || fl->b.x < 0 || fl->b.x >= f_w
           || fl->b.y < 0 || fl->b.y >= f_h)
     {
-       //fprintf(stderr, "fuck %d \r", fuck++);
+        DEH_fprintf(stderr, "fuck %d \r", fuck++);
        return;
     }
 
@@ -1249,11 +1255,11 @@ void AM_drawPlayers(void)
     {
        if (cheating)
            AM_drawLineCharacter
-               (cheat_player_arrow, NUMCHEATPLYRLINES, 0,
+               (cheat_player_arrow, arrlen(cheat_player_arrow), 0,
                 plr->mo->angle, WHITE, plr->mo->x, plr->mo->y);
        else
            AM_drawLineCharacter
-               (player_arrow, NUMPLYRLINES, 0, plr->mo->angle,
+               (player_arrow, arrlen(player_arrow), 0, plr->mo->angle,
                 WHITE, plr->mo->x, plr->mo->y);
        return;
     }
@@ -1275,7 +1281,7 @@ void AM_drawPlayers(void)
            color = their_colors[their_color];
        
        AM_drawLineCharacter
-           (player_arrow, NUMPLYRLINES, 0, p->mo->angle,
+           (player_arrow, arrlen(player_arrow), 0, p->mo->angle,
             color, p->mo->x, p->mo->y);
     }
 
@@ -1295,7 +1301,7 @@ AM_drawThings
        while (t)
        {
            AM_drawLineCharacter
-               (thintriangle_guy, NUMTHINTRIANGLEGUYLINES,
+               (thintriangle_guy, arrlen(thintriangle_guy),
                 16<<FRACBITS, t->angle, colors+lightlev, t->x, t->y);
            t = t->snext;
        }
@@ -1317,7 +1323,7 @@ void AM_drawMarks(void)
            fx = CXMTOF(markpoints[i].x);
            fy = CYMTOF(markpoints[i].y);
            if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h)
-               V_DrawPatch(fx, fy, FB, marknums[i]);
+               V_DrawPatch(fx, fy, marknums[i]);
        }
     }
 
index ff2e0b47cd421ebfcfcfc7657585de1f3a9970f2..572d2389bc28ed4858a8cfc770941bef508e11e6 100644 (file)
@@ -1,27 +1,27 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //  AutoMap module.
 //
-//-----------------------------------------------------------------------------
 
 #ifndef __AMMAP_H__
 #define __AMMAP_H__
 
+#include "d_event.h"
+#include "m_cheat.h"
+
 // Used by ST StatusBar stuff.
 #define AM_MSGHEADER (('a'<<24)+('m'<<16))
 #define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8))
@@ -43,10 +43,7 @@ void AM_Drawer (void);
 void AM_Stop (void);
 
 
+extern cheatseq_t cheat_amap;
+
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
diff --git a/frosted-doom/compat/values.h b/frosted-doom/compat/values.h
deleted file mode 100644 (file)
index 389b9d2..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/* Old compatibility names for <limits.h> and <float.h> constants.
-   Copyright (C) 1995-2016 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-/* This interface is obsolete.  New programs should use
-   <limits.h> and/or <float.h> instead of <values.h>.  */
-
-#ifndef        _VALUES_H
-#define        _VALUES_H       1
-
-#include <features.h>
-
-#include <limits.h>
-
-#define _TYPEBITS(type)        (sizeof (type) * CHAR_BIT)
-
-#define CHARBITS       _TYPEBITS (char)
-#define SHORTBITS      _TYPEBITS (short int)
-#define INTBITS                _TYPEBITS (int)
-#define LONGBITS       _TYPEBITS (long int)
-#define PTRBITS                _TYPEBITS (char *)
-#define DOUBLEBITS     _TYPEBITS (double)
-#define FLOATBITS      _TYPEBITS (float)
-
-#define MINSHORT       SHRT_MIN
-#define        MININT          INT_MIN
-#define        MINLONG         LONG_MIN
-
-#define        MAXSHORT        SHRT_MAX
-#define        MAXINT          INT_MAX
-#define        MAXLONG         LONG_MAX
-
-#define HIBITS         MINSHORT
-#define HIBITL         MINLONG
-
-
-#include <float.h>
-
-#define        MAXDOUBLE       DBL_MAX
-#define        MINDOUBLE       DBL_MIN
-#define        MINFLOAT        FLT_MIN
-#define        DMINEXP         DBL_MIN_EXP
-#define        FMINEXP         FLT_MIN_EXP
-#define        DMAXEXP         DBL_MAX_EXP
-#define        FMAXEXP         FLT_MAX_EXP
-
-
-#ifdef __USE_MISC
-/* Some systems define this name instead of CHAR_BIT or CHARBITS.  */
-# define BITSPERBYTE   CHAR_BIT
-#endif
-
-#endif /* values.h */
diff --git a/frosted-doom/config.h b/frosted-doom/config.h
new file mode 100644 (file)
index 0000000..6c68fca
--- /dev/null
@@ -0,0 +1,100 @@
+/* config.hin.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the <dev/isa/spkrio.h> header file. */
+#undef HAVE_DEV_ISA_SPKRIO_H
+
+/* Define to 1 if you have the <dev/speaker/speaker.h> header file. */
+#undef HAVE_DEV_SPEAKER_SPEAKER_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `ioperm' function. */
+#undef HAVE_IOPERM
+
+/* Define to 1 if you have the `amd64' library (-lamd64). */
+#undef HAVE_LIBAMD64
+
+/* Define to 1 if you have the `i386' library (-li386). */
+#undef HAVE_LIBI386
+
+/* Define to 1 if you have the `m' library (-lm). */
+#undef HAVE_LIBM
+
+/* Define to 1 if you have the `png' library (-lpng). */
+#undef HAVE_LIBPNG
+
+/* Define to 1 if you have the `samplerate' library (-lsamplerate). */
+#undef HAVE_LIBSAMPLERATE
+
+/* Define to 1 if you have the `z' library (-lz). */
+#undef HAVE_LIBZ
+
+/* Define to 1 if you have the <linux/kd.h> header file. */
+#undef HAVE_LINUX_KD_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `mmap' function. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the `sched_setaffinity' function. */
+#undef HAVE_SCHED_SETAFFINITY
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Name of package */
+#define PACKAGE "Doom"
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "FDoom"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "FDoom 0.1"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "fdoom.tar"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION 0.1
+
+/* Change this when you create your awesome forked version */
+#define PROGRAM_PREFIX "fdoom"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION 0.1
+
+/* Define to 1 if you want to compile the unmodified code */
+#undef ORIGCODE
+
+/* Define to the directory where all game files are located */
+#define FILES_DIR "/mnt"
index c0b0786893a65a7b0b572ecb03229cc7cf153ff3..cfb05722c5c9623ede6cfa75a81bfb1bc95c55e4 100644 (file)
@@ -1,24 +1,21 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Printed strings for translation.
 //     English language support (default).
 //
-//-----------------------------------------------------------------------------
 
 #ifndef __D_ENGLSH__
 #define __D_ENGLSH__
@@ -63,7 +60,7 @@
 #define NETEND "you can't end a netgame!\n\n"PRESSKEY
 #define ENDGAME        "are you sure you want to end the game?\n\n"PRESSYN
 
-#define DOSY           "(press y to quit)"
+#define DOSY           "(press y to quit to dos.)"
 
 #define DETAILHI       "High detail"
 #define DETAILLO       "Low detail"
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
diff --git a/frosted-doom/d_event.c b/frosted-doom/d_event.c
new file mode 100644 (file)
index 0000000..3eef572
--- /dev/null
@@ -0,0 +1,63 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+//
+// DESCRIPTION: Event handling.
+//
+// Events are asynchronous inputs generally generated by the game user.
+// Events can be discarded if no responder claims them
+//
+
+#include <stdlib.h>
+#include "d_event.h"
+
+#define MAXEVENTS 64
+
+static event_t events[MAXEVENTS];
+static int eventhead;
+static int eventtail;
+
+//
+// D_PostEvent
+// Called by the I/O functions when input is detected
+//
+void D_PostEvent (event_t* ev)
+{
+    events[eventhead] = *ev;
+    eventhead = (eventhead + 1) % MAXEVENTS;
+}
+
+// Read an event from the queue.
+
+event_t *D_PopEvent(void)
+{
+    event_t *result;
+
+    // No more events waiting.
+
+    if (eventtail == eventhead)
+    {
+        return NULL;
+    }
+    
+    result = &events[eventtail];
+
+    // Advance to the next event in the queue.
+
+    eventtail = (eventtail + 1) % MAXEVENTS;
+
+    return result;
+}
+
+
index feb57833351c60293b4d39a042c9539ff901b605..c9374b296f5e54ef1c341adbeb5a916d11ce78de 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //
 //    
-//-----------------------------------------------------------------------------
 
 
 #ifndef __D_EVENT__
@@ -37,35 +34,40 @@ typedef enum
     ev_keydown,
     ev_keyup,
     ev_mouse,
-    ev_joystick
+    ev_joystick,
+    ev_quit
 } evtype_t;
 
 // Event structure.
 typedef struct
 {
-    evtype_t   type;
-    int                data1;          // keys / mouse/joystick buttons
-    int                data2;          // mouse/joystick x move
-    int                data3;          // mouse/joystick y move
+    evtype_t type;
+
+    // Event-related data that depends on the type of event:
+    //
+    // ev_keydown/ev_keyup:
+    //    data1: Key code (from doomkeys.h) of the key that was
+    //           pressed or released.
+    //    data2: Ascii text of the character that was pressed,
+    //           shifted appropriately (eg. '$' if 4 was pressed
+    //           while shift was held).
+    //
+    // ev_mouse:
+    //    data1: Bitfield of buttons currently held down.
+    //           (bit 0 = left; bit 1 = right; bit 2 = middle).
+    //    data2: X axis mouse movement (turn).
+    //    data3: Y axis mouse movement (forward/backward).
+    //
+    // ev_joystick:
+    //    data1: Bitfield of buttons currently pressed.
+    //    data2: X axis mouse movement (turn).
+    //    data3: Y axis mouse movement (forward/backward).
+    //    data4: Third axis mouse movement (strafe).
+
+    int data1, data2, data3, data4;
 } event_t;
 
  
-typedef enum
-{
-    ga_nothing,
-    ga_loadlevel,
-    ga_newgame,
-    ga_loadgame,
-    ga_savegame,
-    ga_playdemo,
-    ga_completed,
-    ga_victory,
-    ga_worlddone,
-    ga_screenshot
-} gameaction_t;
-
-
-
 //
 // Button/action code definitions.
 //
@@ -99,24 +101,37 @@ typedef enum
   
 } buttoncode_t;
 
+// villsa [STRIFE] Strife specific buttons
+// TODO - not finished
+typedef enum
+{
+    // Player view look up
+    BT2_LOOKUP          = 1,
+    // Player view look down
+    BT2_LOOKDOWN        = 2,
+    // Center player's view
+    BT2_CENTERVIEW      = 4,
+    // Use inventory item
+    BT2_INVUSE          = 8,
+    // Drop inventory item
+    BT2_INVDROP         = 16,
+    // Jump up and down
+    BT2_JUMP            = 32,
+    // Use medkit
+    BT2_HEALTH          = 128,
+  
+} buttoncode2_t;
 
 
 
-//
-// GLOBAL VARIABLES
-//
-#define MAXEVENTS              64
 
-extern  event_t                events[MAXEVENTS];
-extern  int             eventhead;
-extern int             eventtail;
+// Called by IO functions when input is detected.
+void D_PostEvent (event_t *ev);
+
+// Read an event from the event queue
 
-extern  gameaction_t    gameaction;
+event_t *D_PopEvent(void);
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
+
diff --git a/frosted-doom/d_french.h b/frosted-doom/d_french.h
deleted file mode 100644 (file)
index d4807ab..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
-//
-// $Id:$
-//
-// Copyright (C) 1993-1996 by id Software, Inc.
-//
-// This source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// DESCRIPTION:
-//     Printed strings, french translation.
-//
-//-----------------------------------------------------------------------------
-
-
-#ifndef __D_FRENCH__
-#define __D_FRENCH__
-
-//
-// D_Main.C
-//
-#define D_DEVSTR       "MODE DEVELOPPEMENT ON.\n"
-#define D_CDROM                "VERSION CD-ROM: DEFAULT.CFG DANS C:\\DOOMDATA\n"
-
-//
-//     M_Menu.C
-//
-#define PRESSKEY       "APPUYEZ SUR UNE TOUCHE."
-#define PRESSYN        "APPUYEZ SUR Y OU N"
-#define QUITMSG                "VOUS VOULEZ VRAIMENT\nQUITTER CE SUPER JEU?"
-#define LOADNET        "VOUS NE POUVEZ PAS CHARGER\nUN JEU EN RESEAU!\n\n"PRESSKEY
-#define QLOADNET       "CHARGEMENT RAPIDE INTERDIT EN RESEAU!\n\n"PRESSKEY
-#define QSAVESPOT      "VOUS N'AVEZ PAS CHOISI UN EMPLACEMENT!\n\n"PRESSKEY
-#define SAVEDEAD       "VOUS NE POUVEZ PAS SAUVER SI VOUS NE JOUEZ "\
-"PAS!\n\n"PRESSKEY
-#define QSPROMPT       "SAUVEGARDE RAPIDE DANS LE FICHIER \n\n'%s'?\n\n"PRESSYN
-#define QLPROMPT       "VOULEZ-VOUS CHARGER LA SAUVEGARDE"\
-"\n\n'%s'?\n\n"PRESSYN
-#define NEWGAME                "VOUS NE POUVEZ PAS LANCER\n"\
-"UN NOUVEAU JEU SUR RESEAU.\n\n"PRESSKEY
-#define NIGHTMARE      "VOUS CONFIRMEZ? CE NIVEAU EST\n"\
-"VRAIMENT IMPITOYABLE!n"PRESSYN
-#define SWSTRING       "CECI EST UNE VERSION SHAREWARE DE DOOM.\n\n"\
-"VOUS DEVRIEZ COMMANDER LA TRILOGIE COMPLETE.\n\n"PRESSKEY
-#define MSGOFF         "MESSAGES OFF"
-#define MSGON          "MESSAGES ON"
-#define NETEND         "VOUS NE POUVEZ PAS METTRE FIN A UN JEU SUR "\
-"RESEAU!\n\n"PRESSKEY
-#define ENDGAME                "VOUS VOULEZ VRAIMENT METTRE FIN AU JEU?\n\n"PRESSYN
-
-#define DOSY           "(APPUYEZ SUR Y POUR REVENIR AU OS.)"
-
-#define DETAILHI       "GRAPHISMES MAXIMUM "
-#define DETAILLO       "GRAPHISMES MINIMUM "
-#define GAMMALVL0      "CORRECTION GAMMA OFF"
-#define GAMMALVL1      "CORRECTION GAMMA NIVEAU 1"
-#define GAMMALVL2      "CORRECTION GAMMA NIVEAU 2"
-#define GAMMALVL3      "CORRECTION GAMMA NIVEAU 3"
-#define GAMMALVL4      "CORRECTION GAMMA NIVEAU 4"
-#define EMPTYSTRING    "EMPLACEMENT VIDE"
-
-//
-//     P_inter.C
-//
-#define GOTARMOR       "ARMURE RECUPEREE."
-#define GOTMEGA                "MEGA-ARMURE RECUPEREE!"
-#define GOTHTHBONUS    "BONUS DE SANTE RECUPERE."
-#define GOTARMBONUS    "BONUS D'ARMURE RECUPERE."
-#define GOTSTIM                "STIMPACK RECUPERE."
-#define GOTMEDINEED    "MEDIKIT RECUPERE. VOUS EN AVEZ VRAIMENT BESOIN!"
-#define GOTMEDIKIT     "MEDIKIT RECUPERE."
-#define GOTSUPER       "SUPERCHARGE!"
-
-#define GOTBLUECARD    "CARTE MAGNETIQUE BLEUE RECUPEREE."
-#define GOTYELWCARD    "CARTE MAGNETIQUE JAUNE RECUPEREE."
-#define GOTREDCARD     "CARTE MAGNETIQUE ROUGE RECUPEREE."
-#define GOTBLUESKUL    "CLEF CRANE BLEUE RECUPEREE."
-#define GOTYELWSKUL    "CLEF CRANE JAUNE RECUPEREE."
-#define GOTREDSKULL    "CLEF CRANE ROUGE RECUPEREE."
-
-#define GOTINVUL       "INVULNERABILITE!"
-#define GOTBERSERK     "BERSERK!"
-#define GOTINVIS       "INVISIBILITE PARTIELLE "
-#define GOTSUIT                "COMBINAISON ANTI-RADIATIONS "
-#define GOTMAP         "CARTE INFORMATIQUE "
-#define GOTVISOR       "VISEUR A AMPLIFICATION DE LUMIERE "
-#define GOTMSPHERE     "MEGASPHERE!"
-
-#define GOTCLIP                "CHARGEUR RECUPERE."
-#define GOTCLIPBOX     "BOITE DE BALLES RECUPEREE."
-#define GOTROCKET      "ROQUETTE RECUPEREE."
-#define GOTROCKBOX     "CAISSE DE ROQUETTES RECUPEREE."
-#define GOTCELL                "CELLULE D'ENERGIE RECUPEREE."
-#define GOTCELLBOX     "PACK DE CELLULES D'ENERGIE RECUPERE."
-#define GOTSHELLS      "4 CARTOUCHES RECUPEREES."
-#define GOTSHELLBOX    "BOITE DE CARTOUCHES RECUPEREE."
-#define GOTBACKPACK    "SAC PLEIN DE MUNITIONS RECUPERE!"
-
-#define GOTBFG9000     "VOUS AVEZ UN BFG9000!  OH, OUI!"
-#define GOTCHAINGUN    "VOUS AVEZ LA MITRAILLEUSE!"
-#define GOTCHAINSAW    "UNE TRONCONNEUSE!"
-#define GOTLAUNCHER    "VOUS AVEZ UN LANCE-ROQUETTES!"
-#define GOTPLASMA      "VOUS AVEZ UN FUSIL A PLASMA!"
-#define GOTSHOTGUN     "VOUS AVEZ UN FUSIL!"
-#define GOTSHOTGUN2    "VOUS AVEZ UN SUPER FUSIL!"
-
-//
-// P_Doors.C
-//
-#define PD_BLUEO       "IL VOUS FAUT UNE CLEF BLEUE"
-#define PD_REDO                "IL VOUS FAUT UNE CLEF ROUGE"
-#define PD_YELLOWO     "IL VOUS FAUT UNE CLEF JAUNE"
-#define PD_BLUEK       PD_BLUEO
-#define PD_REDK                PD_REDO
-#define PD_YELLOWK     PD_YELLOWO
-
-//
-//     G_game.C
-//
-#define GGSAVED                "JEU SAUVEGARDE."
-
-//
-//     HU_stuff.C
-//
-#define HUSTR_MSGU     "[MESSAGE NON ENVOYE]"
-
-#define HUSTR_E1M1     "E1M1: HANGAR"
-#define HUSTR_E1M2     "E1M2: USINE NUCLEAIRE "
-#define HUSTR_E1M3     "E1M3: RAFFINERIE DE TOXINES "
-#define HUSTR_E1M4     "E1M4: CENTRE DE CONTROLE "
-#define HUSTR_E1M5     "E1M5: LABORATOIRE PHOBOS "
-#define HUSTR_E1M6     "E1M6: TRAITEMENT CENTRAL "
-#define HUSTR_E1M7     "E1M7: CENTRE INFORMATIQUE "
-#define HUSTR_E1M8     "E1M8: ANOMALIE PHOBOS "
-#define HUSTR_E1M9     "E1M9: BASE MILITAIRE "
-
-#define HUSTR_E2M1     "E2M1: ANOMALIE DEIMOS "
-#define HUSTR_E2M2     "E2M2: ZONE DE CONFINEMENT "
-#define HUSTR_E2M3     "E2M3: RAFFINERIE"
-#define HUSTR_E2M4     "E2M4: LABORATOIRE DEIMOS "
-#define HUSTR_E2M5     "E2M5: CENTRE DE CONTROLE "
-#define HUSTR_E2M6     "E2M6: HALLS DES DAMNES "
-#define HUSTR_E2M7     "E2M7: CUVES DE REPRODUCTION "
-#define HUSTR_E2M8     "E2M8: TOUR DE BABEL "
-#define HUSTR_E2M9     "E2M9: FORTERESSE DU MYSTERE "
-
-#define HUSTR_E3M1     "E3M1: DONJON DE L'ENFER "
-#define HUSTR_E3M2     "E3M2: BOURBIER DU DESESPOIR "
-#define HUSTR_E3M3     "E3M3: PANDEMONIUM"
-#define HUSTR_E3M4     "E3M4: MAISON DE LA DOULEUR "
-#define HUSTR_E3M5     "E3M5: CATHEDRALE PROFANE "
-#define HUSTR_E3M6     "E3M6: MONT EREBUS"
-#define HUSTR_E3M7     "E3M7: LIMBES"
-#define HUSTR_E3M8     "E3M8: DIS"
-#define HUSTR_E3M9     "E3M9: CLAPIERS"
-
-#define HUSTR_1                "NIVEAU 1: ENTREE "
-#define HUSTR_2                "NIVEAU 2: HALLS SOUTERRAINS "
-#define HUSTR_3                "NIVEAU 3: LE FEU NOURRI "
-#define HUSTR_4                "NIVEAU 4: LE FOYER "
-#define HUSTR_5                "NIVEAU 5: LES EGOUTS "
-#define HUSTR_6                "NIVEAU 6: LE BROYEUR "
-#define HUSTR_7                "NIVEAU 7: L'HERBE DE LA MORT"
-#define HUSTR_8                "NIVEAU 8: RUSES ET PIEGES "
-#define HUSTR_9                "NIVEAU 9: LE PUITS "
-#define HUSTR_10       "NIVEAU 10: BASE DE RAVITAILLEMENT "
-#define HUSTR_11       "NIVEAU 11: LE CERCLE DE LA MORT!"
-
-#define HUSTR_12       "NIVEAU 12: L'USINE "
-#define HUSTR_13       "NIVEAU 13: LE CENTRE VILLE"
-#define HUSTR_14       "NIVEAU 14: LES ANTRES PROFONDES "
-#define HUSTR_15       "NIVEAU 15: LA ZONE INDUSTRIELLE "
-#define HUSTR_16       "NIVEAU 16: LA BANLIEUE"
-#define HUSTR_17       "NIVEAU 17: LES IMMEUBLES"
-#define HUSTR_18       "NIVEAU 18: LA COUR "
-#define HUSTR_19       "NIVEAU 19: LA CITADELLE "
-#define HUSTR_20       "NIVEAU 20: JE T'AI EU!"
-
-#define HUSTR_21       "NIVEAU 21: LE NIRVANA"
-#define HUSTR_22       "NIVEAU 22: LES CATACOMBES "
-#define HUSTR_23       "NIVEAU 23: LA GRANDE FETE "
-#define HUSTR_24       "NIVEAU 24: LE GOUFFRE "
-#define HUSTR_25       "NIVEAU 25: LES CHUTES DE SANG"
-#define HUSTR_26       "NIVEAU 26: LES MINES ABANDONNEES "
-#define HUSTR_27       "NIVEAU 27: CHEZ LES MONSTRES "
-#define HUSTR_28       "NIVEAU 28: LE MONDE DE L'ESPRIT "
-#define HUSTR_29       "NIVEAU 29: LA LIMITE "
-#define HUSTR_30       "NIVEAU 30: L'ICONE DU PECHE "
-
-#define HUSTR_31       "NIVEAU 31: WOLFENSTEIN"
-#define HUSTR_32       "NIVEAU 32: LE MASSACRE"
-
-
-#define HUSTR_CHATMACRO1       "JE SUIS PRET A LEUR EN FAIRE BAVER!"
-#define HUSTR_CHATMACRO2       "JE VAIS BIEN."
-#define HUSTR_CHATMACRO3       "JE N'AI PAS L'AIR EN FORME!"
-#define HUSTR_CHATMACRO4       "AU SECOURS!"
-#define HUSTR_CHATMACRO5       "TU CRAINS!"
-#define HUSTR_CHATMACRO6       "LA PROCHAINE FOIS, MINABLE..."
-#define HUSTR_CHATMACRO7       "VIENS ICI!"
-#define HUSTR_CHATMACRO8       "JE VAIS M'EN OCCUPER."
-#define HUSTR_CHATMACRO9       "OUI"
-#define HUSTR_CHATMACRO0       "NON"
-
-#define HUSTR_TALKTOSELF1      "VOUS PARLEZ TOUT SEUL "
-#define HUSTR_TALKTOSELF2      "QUI EST LA?"
-#define HUSTR_TALKTOSELF3      "VOUS VOUS FAITES PEUR "
-#define HUSTR_TALKTOSELF4      "VOUS COMMENCEZ A DELIRER "
-#define HUSTR_TALKTOSELF5      "VOUS ETES LARGUE..."
-
-#define HUSTR_MESSAGESENT      "[MESSAGE ENVOYE]"
-
-// The following should NOT be changed unless it seems
-// just AWFULLY necessary
-
-#define HUSTR_PLRGREEN "VERT: "
-#define HUSTR_PLRINDIGO        "INDIGO: "
-#define HUSTR_PLRBROWN "BRUN: "
-#define HUSTR_PLRRED           "ROUGE: "
-
-#define HUSTR_KEYGREEN 'g'     // french key should be "V"
-#define HUSTR_KEYINDIGO        'i'     
-#define HUSTR_KEYBROWN 'b'     
-#define HUSTR_KEYRED           'r'
-
-//
-//     AM_map.C
-//
-
-#define AMSTR_FOLLOWON         "MODE POURSUITE ON"
-#define AMSTR_FOLLOWOFF                "MODE POURSUITE OFF"
-
-#define AMSTR_GRIDON           "GRILLE ON"
-#define AMSTR_GRIDOFF          "GRILLE OFF"
-
-#define AMSTR_MARKEDSPOT       "REPERE MARQUE "
-#define AMSTR_MARKSCLEARED     "REPERES EFFACES "
-
-//
-//     ST_stuff.C
-//
-
-#define STSTR_MUS              "CHANGEMENT DE MUSIQUE "
-#define STSTR_NOMUS            "IMPOSSIBLE SELECTION"
-#define STSTR_DQDON            "INVULNERABILITE ON "
-#define STSTR_DQDOFF           "INVULNERABILITE OFF"
-
-#define STSTR_KFAADDED         "ARMEMENT MAXIMUM! "
-#define STSTR_FAADDED          "ARMES (SAUF CLEFS) AJOUTEES"
-
-#define STSTR_NCON             "BARRIERES ON"
-#define STSTR_NCOFF            "BARRIERES OFF"
-
-#define STSTR_BEHOLD           " inVuln, Str, Inviso, Rad, Allmap, or Lite-amp"
-#define STSTR_BEHOLDX          "AMELIORATION ACTIVEE"
-
-#define STSTR_CHOPPERS         "... DOESN'T SUCK - GM"
-#define STSTR_CLEV             "CHANGEMENT DE NIVEAU..."
-
-//
-//     F_Finale.C
-//
-#define E1TEXT "APRES AVOIR VAINCU LES GROS MECHANTS\n"\
-"ET NETTOYE LA BASE LUNAIRE, VOUS AVEZ\n"\
-"GAGNE, NON? PAS VRAI? OU EST DONC VOTRE\n"\
-" RECOMPENSE ET VOTRE BILLET DE\n"\
-"RETOUR? QU'EST-QUE CA VEUT DIRE?CE"\
-"N'EST PAS LA FIN ESPEREE!\n"\
-"\n" \
-"CA SENT LA VIANDE PUTREFIEE, MAIS\n"\
-"ON DIRAIT LA BASE DEIMOS. VOUS ETES\n"\
-"APPAREMMENT BLOQUE AUX PORTES DE L'ENFER.\n"\
-"LA SEULE ISSUE EST DE L'AUTRE COTE.\n"\
-"\n"\
-"POUR VIVRE LA SUITE DE DOOM, JOUEZ\n"\
-"A 'AUX PORTES DE L'ENFER' ET A\n"\
-"L'EPISODE SUIVANT, 'L'ENFER'!\n"
-                               
-#define E2TEXT "VOUS AVEZ REUSSI. L'INFAME DEMON\n"\
-"QUI CONTROLAIT LA BASE LUNAIRE DE\n"\
-"DEIMOS EST MORT, ET VOUS AVEZ\n"\
-"TRIOMPHE! MAIS... OU ETES-VOUS?\n"\
-"VOUS GRIMPEZ JUSQU'AU BORD DE LA\n"\
-"LUNE ET VOUS DECOUVREZ L'ATROCE\n"\
-"VERITE.\n" \
-"\n"\
-"DEIMOS EST AU-DESSUS DE L'ENFER!\n"\
-"VOUS SAVEZ QUE PERSONNE NE S'EN\n"\
-"EST JAMAIS ECHAPPE, MAIS CES FUMIERS\n"\
-"VONT REGRETTER DE VOUS AVOIR CONNU!\n"\
-"VOUS REDESCENDEZ RAPIDEMENT VERS\n"\
-"LA SURFACE DE L'ENFER.\n"\
-"\n" \
-"VOICI MAINTENANT LE CHAPITRE FINAL DE\n"\
-"DOOM! -- L'ENFER."
-
-#define E3TEXT "LE DEMON ARACHNEEN ET REPUGNANT\n"\
-"QUI A DIRIGE L'INVASION DES BASES\n"\
-"LUNAIRES ET SEME LA MORT VIENT DE SE\n"\
-"FAIRE PULVERISER UNE FOIS POUR TOUTES.\n"\
-"\n"\
-"UNE PORTE SECRETE S'OUVRE. VOUS ENTREZ.\n"\
-"VOUS AVEZ PROUVE QUE VOUS POUVIEZ\n"\
-"RESISTER AUX HORREURS DE L'ENFER.\n"\
-"IL SAIT ETRE BEAU JOUEUR, ET LORSQUE\n"\
-"VOUS SORTEZ, VOUS REVOYEZ LES VERTES\n"\
-"PRAIRIES DE LA TERRE, VOTRE PLANETE.\n"\
-"\n"\
-"VOUS VOUS DEMANDEZ CE QUI S'EST PASSE\n"\
-"SUR TERRE PENDANT QUE VOUS AVEZ\n"\
-"COMBATTU LE DEMON. HEUREUSEMENT,\n"\
-"AUCUN GERME DU MAL N'A FRANCHI\n"\
-"CETTE PORTE AVEC VOUS..."
-
-
-
-// after level 6, put this:
-
-#define C1TEXT "VOUS ETES AU PLUS PROFOND DE L'ASTROPORT\n" \
-"INFESTE DE MONSTRES, MAIS QUELQUE CHOSE\n" \
-"NE VA PAS. ILS ONT APPORTE LEUR PROPRE\n" \
-"REALITE, ET LA TECHNOLOGIE DE L'ASTROPORT\n" \
-"EST AFFECTEE PAR LEUR PRESENCE.\n" \
-"\n"\
-"DEVANT VOUS, VOUS VOYEZ UN POSTE AVANCE\n" \
-"DE L'ENFER, UNE ZONE FORTIFIEE. SI VOUS\n" \
-"POUVEZ PASSER, VOUS POURREZ PENETRER AU\n" \
-"COEUR DE LA BASE HANTEE ET TROUVER \n" \
-"L'INTERRUPTEUR DE CONTROLE QUI GARDE LA \n" \
-"POPULATION DE LA TERRE EN OTAGE."
-
-// After level 11, put this:
-
-#define C2TEXT "VOUS AVEZ GAGNE! VOTRE VICTOIRE A PERMIS\n" \
-"A L'HUMANITE D'EVACUER LA TERRE ET \n"\
-"D'ECHAPPER AU CAUCHEMAR. VOUS ETES \n"\
-"MAINTENANT LE DERNIER HUMAIN A LA SURFACE \n"\
-"DE LA PLANETE. VOUS ETES ENTOURE DE \n"\
-"MUTANTS CANNIBALES, D'EXTRATERRESTRES \n"\
-"CARNIVORES ET D'ESPRITS DU MAL. VOUS \n"\
-"ATTENDEZ CALMEMENT LA MORT, HEUREUX \n"\
-"D'AVOIR PU SAUVER VOTRE RACE.\n"\
-"MAIS UN MESSAGE VOUS PARVIENT SOUDAIN\n"\
-"DE L'ESPACE: \"NOS CAPTEURS ONT LOCALISE\n"\
-"LA SOURCE DE L'INVASION EXTRATERRESTRE.\n"\
-"SI VOUS Y ALLEZ, VOUS POURREZ PEUT-ETRE\n"\
-"LES ARRETER. LEUR BASE EST SITUEE AU COEUR\n"\
-"DE VOTRE VILLE NATALE, PRES DE L'ASTROPORT.\n"\
-"VOUS VOUS RELEVEZ LENTEMENT ET PENIBLEMENT\n"\
-"ET VOUS REPARTEZ POUR LE FRONT."
-
-// After level 20, put this:
-
-#define C3TEXT "VOUS ETES AU COEUR DE LA CITE CORROMPUE,\n"\
-"ENTOURE PAR LES CADAVRES DE VOS ENNEMIS.\n"\
-"VOUS NE VOYEZ PAS COMMENT DETRUIRE LA PORTE\n"\
-"DES CREATURES DE CE COTE. VOUS SERREZ\n"\
-"LES DENTS ET PLONGEZ DANS L'OUVERTURE.\n"\
-"\n"\
-"IL DOIT Y AVOIR UN MOYEN DE LA FERMER\n"\
-"DE L'AUTRE COTE. VOUS ACCEPTEZ DE\n"\
-"TRAVERSER L'ENFER POUR LE FAIRE?"
-
-// After level 29, put this:
-
-#define C4TEXT "LE VISAGE HORRIBLE D'UN DEMON D'UNE\n"\
-"TAILLE INCROYABLE S'EFFONDRE DEVANT\n"\
-"VOUS LORSQUE VOUS TIREZ UNE SALVE DE\n"\
-"ROQUETTES DANS SON CERVEAU. LE MONSTRE\n"\
-"SE RATATINE, SES MEMBRES DECHIQUETES\n"\
-"SE REPANDANT SUR DES CENTAINES DE\n"\
-"KILOMETRES A LA SURFACE DE L'ENFER.\n"\
-"\n"\
-"VOUS AVEZ REUSSI. L'INVASION N'AURA.\n"\
-"PAS LIEU. LA TERRE EST SAUVEE. L'ENFER\n"\
-"EST ANEANTI. EN VOUS DEMANDANT OU IRONT\n"\
-"MAINTENANT LES DAMNES, VOUS ESSUYEZ\n"\
-"VOTRE FRONT COUVERT DE SUEUR ET REPARTEZ\n"\
-"VERS LA TERRE. SA RECONSTRUCTION SERA\n"\
-"BEAUCOUP PLUS DROLE QUE SA DESTRUCTION.\n"
-
-// Before level 31, put this:
-
-#define C5TEXT "FELICITATIONS! VOUS AVEZ TROUVE LE\n"\
-"NIVEAU SECRET! IL SEMBLE AVOIR ETE\n"\
-"CONSTRUIT PAR LES HUMAINS. VOUS VOUS\n"\
-"DEMANDEZ QUELS PEUVENT ETRE LES\n"\
-"HABITANTS DE CE COIN PERDU DE L'ENFER."
-
-// Before level 32, put this:
-
-#define C6TEXT "FELICITATIONS! VOUS AVEZ DECOUVERT\n"\
-"LE NIVEAU SUPER SECRET! VOUS FERIEZ\n"\
-"MIEUX DE FONCER DANS CELUI-LA!\n"
-
-//
-// Character cast strings F_FINALE.C
-//
-#define CC_ZOMBIE      "ZOMBIE"
-#define CC_SHOTGUN     "TYPE AU FUSIL"
-#define CC_HEAVY       "MEC SUPER-ARME"
-#define CC_IMP         "DIABLOTIN"
-#define CC_DEMON       "DEMON"
-#define CC_LOST                "AME PERDUE"
-#define CC_CACO                "CACODEMON"
-#define CC_HELL                "CHEVALIER DE L'ENFER"
-#define CC_BARON       "BARON DE L'ENFER"
-#define CC_ARACH       "ARACHNOTRON"
-#define CC_PAIN                "ELEMENTAIRE DE LA DOULEUR"
-#define CC_REVEN       "REVENANT"
-#define CC_MANCU       "MANCUBUS"
-#define CC_ARCH                "ARCHI-INFAME"
-#define CC_SPIDER      "L'ARAIGNEE CERVEAU"
-#define CC_CYBER       "LE CYBERDEMON"
-#define CC_HERO                "NOTRE HEROS"
-
-
-
-#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-
-
index 2267da44e9c0eed2c0738c2b041287044d800e6a..33f310c63b3a83fae380ed495f5ac49456f9b23b 100644 (file)
@@ -1,34 +1,24 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id:$";
 
 // We are referring to sprite numbers.
 #include "info.h"
 
-#ifdef __GNUG__
-#pragma implementation "d_items.h"
-#endif
 #include "d_items.h"
 
 
index 01b64117494138d64efc966d6a6e32b4442f183c..3d22a063030db2e181e37246c1875ef17a5a3a71 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Items: key cards, artifacts, weapon, ammunition.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __D_ITEMS__
@@ -25,9 +22,6 @@
 
 #include "doomdef.h"
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 
 // Weapon info: sprite frames, ammunition use.
@@ -45,8 +39,3 @@ typedef struct
 extern  weaponinfo_t    weaponinfo[NUMWEAPONS];
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
diff --git a/frosted-doom/d_iwad.c b/frosted-doom/d_iwad.c
new file mode 100644 (file)
index 0000000..6a51ea8
--- /dev/null
@@ -0,0 +1,844 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//     Search for and locate an IWAD file, and initialize according
+//     to the IWAD type.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "config.h"
+#include "deh_str.h"
+#include "doomkeys.h"
+#include "d_iwad.h"
+#include "i_system.h"
+#include "m_argv.h"
+#include "m_config.h"
+#include "m_misc.h"
+#include "w_wad.h"
+#include "z_zone.h"
+
+static const iwad_t iwads[] =
+{
+    { "doom2.wad",    doom2,     commercial, "Doom II" },
+    { "plutonia.wad", pack_plut, commercial, "Final Doom: Plutonia Experiment" },
+    { "tnt.wad",      pack_tnt,  commercial, "Final Doom: TNT: Evilution" },
+    { "doom.wad",     doom,      retail,     "Doom" },
+    { "DOOM1.WAD",    doom,      shareware,  "Doom Shareware" },
+    { "chex.wad",     pack_chex, shareware,  "Chex Quest" },
+    { "hacx.wad",     pack_hacx, commercial, "Hacx" },
+    { "freedm.wad",   doom2,     commercial, "FreeDM" },
+    { "freedoom2.wad", doom2,    commercial, "Freedoom: Phase 2" },
+    { "freedoom1.wad", doom,     retail,     "Freedoom: Phase 1" },
+    { "heretic.wad",  heretic,   retail,     "Heretic" },
+    { "heretic1.wad", heretic,   shareware,  "Heretic Shareware" },
+    { "hexen.wad",    hexen,     commercial, "Hexen" },
+    //{ "strife0.wad",  strife,    commercial, "Strife" }, // haleyjd: STRIFE-FIXME
+    { "strife1.wad",  strife,    commercial, "Strife" },
+};
+
+// Array of locations to search for IWAD files
+//
+// "128 IWAD search directories should be enough for anybody".
+
+#define MAX_IWAD_DIRS 128
+
+static boolean iwad_dirs_built = false;
+static char *iwad_dirs[MAX_IWAD_DIRS];
+static int num_iwad_dirs = 0;
+
+static void AddIWADDir(char *dir)
+{
+    if (num_iwad_dirs < MAX_IWAD_DIRS)
+    {
+        iwad_dirs[num_iwad_dirs] = dir;
+        ++num_iwad_dirs;
+    }
+}
+
+// This is Windows-specific code that automatically finds the location
+// of installed IWAD files.  The registry is inspected to find special
+// keys installed by the Windows installers for various CD versions
+// of Doom.  From these keys we can deduce where to find an IWAD.
+
+#if defined(_WIN32) && !defined(_WIN32_WCE)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef struct 
+{
+    HKEY root;
+    char *path;
+    char *value;
+} registry_value_t;
+
+#define UNINSTALLER_STRING "\\uninstl.exe /S "
+
+// Keys installed by the various CD editions.  These are actually the 
+// commands to invoke the uninstaller and look like this:
+//
+// C:\Program Files\Path\uninstl.exe /S C:\Program Files\Path
+//
+// With some munging we can find where Doom was installed.
+
+// [AlexMax] From the persepctive of a 64-bit executable, 32-bit registry
+// keys are located in a different spot.
+#if _WIN64
+#define SOFTWARE_KEY "Software\\Wow6432Node"
+#else
+#define SOFTWARE_KEY "Software"
+#endif
+
+static registry_value_t uninstall_values[] =
+{
+    // Ultimate Doom, CD version (Depths of Doom trilogy)
+
+    {
+        HKEY_LOCAL_MACHINE,
+        SOFTWARE_KEY "\\Microsoft\\Windows\\CurrentVersion\\"
+            "Uninstall\\Ultimate Doom for Windows 95",
+        "UninstallString",
+    },
+
+    // Doom II, CD version (Depths of Doom trilogy)
+
+    {
+        HKEY_LOCAL_MACHINE,
+        SOFTWARE_KEY "\\Microsoft\\Windows\\CurrentVersion\\"
+            "Uninstall\\Doom II for Windows 95",
+        "UninstallString",
+    },
+
+    // Final Doom
+
+    {
+        HKEY_LOCAL_MACHINE,
+        SOFTWARE_KEY "\\Microsoft\\Windows\\CurrentVersion\\"
+            "Uninstall\\Final Doom for Windows 95",
+        "UninstallString",
+    },
+
+    // Shareware version
+
+    {
+        HKEY_LOCAL_MACHINE,
+        SOFTWARE_KEY "\\Microsoft\\Windows\\CurrentVersion\\"
+            "Uninstall\\Doom Shareware for Windows 95",
+        "UninstallString",
+    },
+};
+
+// Value installed by the Collector's Edition when it is installed
+
+static registry_value_t collectors_edition_value =
+{
+    HKEY_LOCAL_MACHINE,
+    SOFTWARE_KEY "\\Activision\\DOOM Collector's Edition\\v1.0",
+    "INSTALLPATH",
+};
+
+// Subdirectories of the above install path, where IWADs are installed.
+
+static char *collectors_edition_subdirs[] = 
+{
+    "Doom2",
+    "Final Doom",
+    "Ultimate Doom",
+};
+
+// Location where Steam is installed
+
+static registry_value_t steam_install_location =
+{
+    HKEY_LOCAL_MACHINE,
+    SOFTWARE_KEY "\\Valve\\Steam",
+    "InstallPath",
+};
+
+// Subdirs of the steam install directory where IWADs are found
+
+static char *steam_install_subdirs[] =
+{
+    "steamapps\\common\\doom 2\\base",
+    "steamapps\\common\\final doom\\base",
+    "steamapps\\common\\ultimate doom\\base",
+    "steamapps\\common\\heretic shadow of the serpent riders\\base",
+    "steamapps\\common\\hexen\\base",
+    "steamapps\\common\\hexen deathkings of the dark citadel\\base",
+
+    // From Doom 3: BFG Edition:
+
+    "steamapps\\common\\DOOM 3 BFG Edition\\base\\wads",
+};
+
+#define STEAM_BFG_GUS_PATCHES \
+    "steamapps\\common\\DOOM 3 BFG Edition\\base\\classicmusic\\instruments"
+
+static char *GetRegistryString(registry_value_t *reg_val)
+{
+    HKEY key;
+    DWORD len;
+    DWORD valtype;
+    char *result;
+
+    // Open the key (directory where the value is stored)
+
+    if (RegOpenKeyEx(reg_val->root, reg_val->path,
+                     0, KEY_READ, &key) != ERROR_SUCCESS)
+    {
+        return NULL;
+    }
+
+    result = NULL;
+
+    // Find the type and length of the string, and only accept strings.
+
+    if (RegQueryValueEx(key, reg_val->value,
+                        NULL, &valtype, NULL, &len) == ERROR_SUCCESS
+     && valtype == REG_SZ)
+    {
+        // Allocate a buffer for the value and read the value
+
+        result = malloc(len);
+
+        if (RegQueryValueEx(key, reg_val->value, NULL, &valtype,
+                            (unsigned char *) result, &len) != ERROR_SUCCESS)
+        {
+            free(result);
+            result = NULL;
+        }
+    }
+
+    // Close the key
+
+    RegCloseKey(key);
+
+    return result;
+}
+
+// Check for the uninstall strings from the CD versions
+
+static void CheckUninstallStrings(void)
+{
+    unsigned int i;
+
+    for (i=0; i<arrlen(uninstall_values); ++i)
+    {
+        char *val;
+        char *path;
+        char *unstr;
+
+        val = GetRegistryString(&uninstall_values[i]);
+
+        if (val == NULL)
+        {
+            continue;
+        }
+
+        unstr = strstr(val, UNINSTALLER_STRING);
+
+        if (unstr == NULL)
+        {
+            free(val);
+        }
+        else
+        {
+            path = unstr + strlen(UNINSTALLER_STRING);
+
+            AddIWADDir(path);
+        }
+    }
+}
+
+// Check for Doom: Collector's Edition
+
+static void CheckCollectorsEdition(void)
+{
+    char *install_path;
+    char *subpath;
+    unsigned int i;
+
+    install_path = GetRegistryString(&collectors_edition_value);
+
+    if (install_path == NULL)
+    {
+        return;
+    }
+
+    for (i=0; i<arrlen(collectors_edition_subdirs); ++i)
+    {
+        subpath = M_StringJoin(install_path, DIR_SEPARATOR_S,
+                               collectors_edition_subdirs[i], NULL);
+
+        AddIWADDir(subpath);
+    }
+
+    free(install_path);
+}
+
+
+// Check for Doom downloaded via Steam
+
+static void CheckSteamEdition(void)
+{
+    char *install_path;
+    char *subpath;
+    size_t i;
+
+    install_path = GetRegistryString(&steam_install_location);
+
+    if (install_path == NULL)
+    {
+        return;
+    }
+
+    for (i=0; i<arrlen(steam_install_subdirs); ++i)
+    {
+        subpath = M_StringJoin(install_path, DIR_SEPARATOR_S,
+                               steam_install_subdirs[i], NULL);
+
+        AddIWADDir(subpath);
+    }
+
+    free(install_path);
+}
+
+// The BFG edition ships with a full set of GUS patches. If we find them,
+// we can autoconfigure to use them.
+
+static void CheckSteamGUSPatches(void)
+{
+    const char *current_path;
+    char *install_path;
+    char *patch_path;
+    int len;
+
+    // Already configured? Don't stomp on the user's choices.
+    current_path = M_GetStrVariable("gus_patch_path");
+    if (current_path != NULL && strlen(current_path) > 0)
+    {
+        return;
+    }
+
+    install_path = GetRegistryString(&steam_install_location);
+
+    if (install_path == NULL)
+    {
+        return;
+    }
+
+    len = strlen(install_path) + strlen(STEAM_BFG_GUS_PATCHES) + 20;
+    patch_path = malloc(len);
+    M_snprintf(patch_path, len, "%s\\%s\\ACBASS.PAT",
+               install_path, STEAM_BFG_GUS_PATCHES);
+
+    // Does acbass.pat exist? If so, then set gus_patch_path.
+    if (M_FileExists(patch_path))
+    {
+        M_snprintf(patch_path, len, "%s\\%s",
+                   install_path, STEAM_BFG_GUS_PATCHES);
+        M_SetVariable("gus_patch_path", patch_path);
+    }
+
+    free(patch_path);
+    free(install_path);
+}
+
+// Default install directories for DOS Doom
+
+static void CheckDOSDefaults(void)
+{
+    // These are the default install directories used by the deice
+    // installer program:
+
+    AddIWADDir("\\doom2");              // Doom II
+    AddIWADDir("\\plutonia");           // Final Doom
+    AddIWADDir("\\tnt");
+    AddIWADDir("\\doom_se");            // Ultimate Doom
+    AddIWADDir("\\doom");               // Shareware / Registered Doom
+    AddIWADDir("\\dooms");              // Shareware versions
+    AddIWADDir("\\doomsw");
+
+    AddIWADDir("\\heretic");            // Heretic
+    AddIWADDir("\\hrtic_se");           // Heretic Shareware from Quake disc
+
+    AddIWADDir("\\hexen");              // Hexen
+    AddIWADDir("\\hexendk");            // Hexen Deathkings of the Dark Citadel
+
+    AddIWADDir("\\strife");             // Strife
+}
+
+#endif
+
+// Returns true if the specified path is a path to a file
+// of the specified name.
+
+static boolean DirIsFile(char *path, char *filename)
+{
+    size_t path_len;
+    size_t filename_len;
+
+    path_len = strlen(path);
+    filename_len = strlen(filename);
+
+    return path_len >= filename_len + 1
+        && path[path_len - filename_len - 1] == DIR_SEPARATOR
+        && !strcasecmp(&path[path_len - filename_len], filename);
+}
+
+// Check if the specified directory contains the specified IWAD
+// file, returning the full path to the IWAD if found, or NULL
+// if not found.
+
+static char *CheckDirectoryHasIWAD(char *dir, char *iwadname)
+{
+    char *filename; 
+
+    // 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))
+    {
+        return strdup(dir);
+    }
+
+    // Construct the full path to the IWAD if it is located in
+    // this directory, and check if it exists.
+
+    if (!strcmp(dir, "."))
+    {
+        filename = strdup(iwadname);
+    }
+    else
+    {
+        filename = M_StringJoin(dir, DIR_SEPARATOR_S, iwadname, NULL);
+    }
+
+    if (M_FileExists(filename))
+    {
+        return filename;
+    }
+
+    free(filename);
+
+    return NULL;
+}
+
+// Search a directory to try to find an IWAD
+// Returns the location of the IWAD if found, otherwise NULL.
+
+static char *SearchDirectoryForIWAD(char *dir, int mask, GameMission_t *mission)
+{
+    char *filename;
+    size_t i;
+
+    for (i=0; i<arrlen(iwads); ++i) 
+    {
+        if (((1 << iwads[i].mission) & mask) == 0)
+        {
+            continue;
+        }
+
+        filename = CheckDirectoryHasIWAD(dir, DEH_String(iwads[i].name));
+
+        if (filename != NULL)
+        {
+            *mission = iwads[i].mission;
+
+            return filename;
+        }
+    }
+
+    return NULL;
+}
+
+// When given an IWAD with the '-iwad' parameter,
+// attempt to identify it by its name.
+
+static GameMission_t IdentifyIWADByName(char *name, int mask)
+{
+    size_t i;
+    GameMission_t mission;
+    char *p;
+
+    p = strrchr(name, DIR_SEPARATOR);
+
+    if (p != NULL)
+    {
+        name = p + 1;
+    }
+
+    mission = none;
+
+    for (i=0; i<arrlen(iwads); ++i)
+    {
+        // Check if the filename is this IWAD name.
+
+        // Only use supported missions:
+
+        if (((1 << iwads[i].mission) & mask) == 0)
+            continue;
+
+        // Check if it ends in this IWAD name.
+
+        if (!strcasecmp(name, iwads[i].name))
+        {
+            mission = iwads[i].mission;
+            break;
+        }
+    }
+
+    return mission;
+}
+
+#if ORIGCODE
+//
+// Add directories from the list in the DOOMWADPATH environment variable.
+//
+
+static void AddDoomWadPath(void)
+{
+    char *doomwadpath;
+    char *p;
+
+    // Check the DOOMWADPATH environment variable.
+
+    doomwadpath = getenv("DOOMWADPATH");
+
+    if (doomwadpath == NULL)
+    {
+        return;
+    }
+
+    doomwadpath = strdup(doomwadpath);
+
+    // Add the initial directory
+
+    AddIWADDir(doomwadpath);
+
+    // Split into individual dirs within the list.
+
+    p = doomwadpath;
+
+    for (;;)
+    {
+        p = strchr(p, PATH_SEPARATOR);
+
+        if (p != NULL)
+        {
+            // Break at the separator and store the right hand side
+            // as another iwad dir
+  
+            *p = '\0';
+            p += 1;
+
+            AddIWADDir(p);
+        }
+        else
+        {
+            break;
+        }
+    }
+}
+
+#endif
+
+//
+// Build a list of IWAD files
+//
+
+static void BuildIWADDirList(void)
+{
+#if ORIGCODE
+    char *doomwaddir;
+
+    if (iwad_dirs_built)
+    {
+        return;
+    }
+
+    // Look in the current directory.  Doom always does this.
+
+    AddIWADDir(".");
+
+    // Add DOOMWADDIR if it is in the environment
+
+    doomwaddir = getenv("DOOMWADDIR");
+
+    if (doomwaddir != NULL)
+    {
+        AddIWADDir(doomwaddir);
+    }        
+
+    // Add dirs from DOOMWADPATH
+
+    AddDoomWadPath();
+
+#ifdef _WIN32
+
+    // Search the registry and find where IWADs have been installed.
+
+    CheckUninstallStrings();
+    CheckCollectorsEdition();
+    CheckSteamEdition();
+    CheckDOSDefaults();
+
+    // Check for GUS patches installed with the BFG edition!
+
+    CheckSteamGUSPatches();
+
+#else
+
+    // Standard places where IWAD files are installed under Unix.
+
+    AddIWADDir("/usr/share/games/doom");
+    AddIWADDir("/usr/local/share/games/doom");
+
+#endif
+#else
+    AddIWADDir (FILES_DIR);
+
+    // Don't run this function again.
+
+    iwad_dirs_built = true;
+#endif
+}
+
+//
+// Searches WAD search paths for an WAD with a specific filename.
+// 
+
+char *D_FindWADByName(char *name)
+{
+    char *path;
+    int i;
+    
+    // Absolute path?
+
+    if (M_FileExists(name))
+    {
+        return name;
+    }
+
+    BuildIWADDirList();
+
+    // Search through all IWAD paths for a file with the given name.
+
+    for (i=0; i<num_iwad_dirs; ++i)
+    {
+        // As a special case, if this is in DOOMWADDIR or DOOMWADPATH,
+        // the "directory" may actually refer directly to an IWAD
+        // file.
+
+        if (DirIsFile(iwad_dirs[i], name) && M_FileExists(iwad_dirs[i]))
+        {
+            return strdup(iwad_dirs[i]);
+        }
+
+        // Construct a string for the full path
+
+        path = M_StringJoin(iwad_dirs[i], DIR_SEPARATOR_S, name, NULL);
+
+        if (M_FileExists(path))
+        {
+            return path;
+        }
+
+        free(path);
+    }
+
+    // File not found
+
+    return NULL;
+}
+
+//
+// D_TryWADByName
+//
+// Searches for a WAD by its filename, or passes through the filename
+// if not found.
+//
+
+char *D_TryFindWADByName(char *filename)
+{
+    char *result;
+
+    result = D_FindWADByName(filename);
+
+    if (result != NULL)
+    {
+        return result;
+    }
+    else
+    {
+        return filename;
+    }
+}
+
+//
+// FindIWAD
+// Checks availability of IWAD files by name,
+// to determine whether registered/commercial features
+// should be executed (notably loading PWADs).
+//
+
+char *D_FindIWAD(int mask, GameMission_t *mission)
+{
+    char *result;
+    char *iwadfile;
+    int iwadparm;
+    int i;
+
+    // Check for the -iwad parameter
+
+    //!
+    // Specify an IWAD file to use.
+    //
+    // @arg <file>
+    //
+
+    iwadparm = M_CheckParmWithArgs("-iwad", 1);
+
+    if (iwadparm)
+    {
+        // Search through IWAD dirs for an IWAD with the given name.
+
+        iwadfile = myargv[iwadparm + 1];
+
+        result = D_FindWADByName(iwadfile);
+
+        if (result == NULL)
+        {
+            I_Error("IWAD file '%s' not found!", iwadfile);
+        }
+        
+        *mission = IdentifyIWADByName(result, mask);
+    }
+    else
+    {
+        // Search through the list and look for an IWAD
+
+        result = NULL;
+
+        BuildIWADDirList();
+    
+        for (i=0; result == NULL && i<num_iwad_dirs; ++i)
+        {
+            result = SearchDirectoryForIWAD(iwad_dirs[i], mask, mission);
+        }
+    }
+
+    return result;
+}
+
+// Find all IWADs in the IWAD search path matching the given mask.
+
+const iwad_t **D_FindAllIWADs(int mask)
+{
+    const iwad_t **result;
+    int result_len;
+    char *filename;
+    int i;
+
+    result = malloc(sizeof(iwad_t *) * (arrlen(iwads) + 1));
+    result_len = 0;
+
+    // Try to find all IWADs
+
+    for (i=0; i<arrlen(iwads); ++i)
+    {
+        if (((1 << iwads[i].mission) & mask) == 0)
+        {
+            continue;
+        }
+
+        filename = D_FindWADByName(iwads[i].name);
+
+        if (filename != NULL)
+        {
+            result[result_len] = &iwads[i];
+            ++result_len;
+        }
+    }
+
+    // End of list
+
+    result[result_len] = NULL;
+
+    return result;
+}
+
+//
+// Get the IWAD name used for savegames.
+//
+
+char *D_SaveGameIWADName(GameMission_t gamemission)
+{
+    size_t i;
+
+    // Determine the IWAD name to use for savegames.
+    // This determines the directory the savegame files get put into.
+    //
+    // Note that we match on gamemission rather than on IWAD name.
+    // This ensures that doom1.wad and doom.wad saves are stored
+    // in the same place.
+
+    for (i=0; i<arrlen(iwads); ++i)
+    {
+        if (gamemission == iwads[i].mission)
+        {
+            return iwads[i].name;
+        }
+    }
+
+    // Default fallback:
+
+    return "unknown.wad";
+}
+
+char *D_SuggestIWADName(GameMission_t mission, GameMode_t mode)
+{
+    int i;
+
+    for (i = 0; i < arrlen(iwads); ++i)
+    {
+        if (iwads[i].mission == mission && iwads[i].mode == mode)
+        {
+            return iwads[i].name;
+        }
+    }
+
+    return "unknown.wad";
+}
+
+char *D_SuggestGameName(GameMission_t mission, GameMode_t mode)
+{
+    int i;
+
+    for (i = 0; i < arrlen(iwads); ++i)
+    {
+        if (iwads[i].mission == mission
+         && (mode == indetermined || iwads[i].mode == mode))
+        {
+            return iwads[i].description;
+        }
+    }
+
+    return "Unknown game?";
+}
+
diff --git a/frosted-doom/d_iwad.h b/frosted-doom/d_iwad.h
new file mode 100644 (file)
index 0000000..91a804f
--- /dev/null
@@ -0,0 +1,52 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//     Find IWAD and initialize according to IWAD type.
+//
+
+
+#ifndef __D_IWAD__
+#define __D_IWAD__
+
+#include "d_mode.h"
+
+#define IWAD_MASK_DOOM    ((1 << doom)           \
+                         | (1 << doom2)          \
+                         | (1 << pack_tnt)       \
+                         | (1 << pack_plut)      \
+                         | (1 << pack_chex)      \
+                         | (1 << pack_hacx))
+#define IWAD_MASK_HERETIC (1 << heretic)
+#define IWAD_MASK_HEXEN   (1 << hexen)
+#define IWAD_MASK_STRIFE  (1 << strife)
+
+typedef struct
+{
+    char *name;
+    GameMission_t mission;
+    GameMode_t mode;
+    char *description;
+} iwad_t;
+
+char *D_FindWADByName(char *filename);
+char *D_TryFindWADByName(char *filename);
+char *D_FindIWAD(int mask, GameMission_t *mission);
+const iwad_t **D_FindAllIWADs(int mask);
+char *D_SaveGameIWADName(GameMission_t gamemission);
+char *D_SuggestIWADName(GameMission_t mission, GameMode_t mode);
+char *D_SuggestGameName(GameMission_t mission, GameMode_t mode);
+void D_CheckCorrectIWAD(GameMission_t mission);
+
+#endif
+
diff --git a/frosted-doom/d_loop.c b/frosted-doom/d_loop.c
new file mode 100644 (file)
index 0000000..1939dbd
--- /dev/null
@@ -0,0 +1,826 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//     Main loop code.
+//
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomfeatures.h"
+
+#include "d_event.h"
+#include "d_loop.h"
+#include "d_ticcmd.h"
+
+#include "i_system.h"
+#include "i_timer.h"
+#include "i_video.h"
+
+#include "m_argv.h"
+#include "m_fixed.h"
+
+#include "net_client.h"
+#include "net_gui.h"
+#include "net_io.h"
+#include "net_query.h"
+#include "net_server.h"
+#include "net_sdl.h"
+#include "net_loop.h"
+
+// The complete set of data for a particular tic.
+
+typedef struct
+{
+    ticcmd_t cmds[NET_MAXPLAYERS];
+    boolean ingame[NET_MAXPLAYERS];
+} ticcmd_set_t;
+
+//
+// gametic is the tic about to (or currently being) run
+// maketic is the tic that hasn't had control made for it yet
+// recvtic is the latest tic received from the server.
+//
+// a gametic cannot be run until ticcmds are received for it
+// from all players.
+//
+
+static ticcmd_set_t ticdata[BACKUPTICS];
+
+// The index of the next tic to be made (with a call to BuildTiccmd).
+
+static int maketic;
+
+// The number of complete tics received from the server so far.
+
+static int recvtic;
+
+// The number of tics that have been run (using RunTic) so far.
+
+int gametic;
+
+// When set to true, a single tic is run each time TryRunTics() is called.
+// This is used for -timedemo mode.
+
+boolean singletics = false;
+
+// Index of the local player.
+
+static int localplayer;
+
+// Used for original sync code.
+
+static int      skiptics = 0;
+
+// Reduce the bandwidth needed by sampling game input less and transmitting
+// less.  If ticdup is 2, sample half normal, 3 = one third normal, etc.
+
+int            ticdup;
+
+// Amount to offset the timer for game sync.
+
+fixed_t         offsetms;
+
+// Use new client syncronisation code
+
+static boolean  new_sync = true;
+
+// Callback functions for loop code.
+
+static loop_interface_t *loop_interface = NULL;
+
+// Current players in the multiplayer game.
+// This is distinct from playeringame[] used by the game code, which may
+// modify playeringame[] when playing back multiplayer demos.
+
+static boolean local_playeringame[NET_MAXPLAYERS];
+
+// Requested player class "sent" to the server on connect.
+// If we are only doing a single player game then this needs to be remembered
+// and saved in the game settings.
+
+static int player_class;
+
+
+// 35 fps clock adjusted by offsetms milliseconds
+
+static int GetAdjustedTime(void)
+{
+    int time_ms;
+
+    time_ms = I_GetTimeMS();
+
+    if (new_sync)
+    {
+       // Use the adjustments from net_client.c only if we are
+       // using the new sync mode.
+
+        time_ms += (offsetms / FRACUNIT);
+    }
+
+    return (time_ms * TICRATE) / 1000;
+}
+
+static boolean BuildNewTic(void)
+{
+    int        gameticdiv;
+    ticcmd_t cmd;
+
+    gameticdiv = gametic/ticdup;
+
+    I_StartTic ();
+    loop_interface->ProcessEvents();
+
+    // Always run the menu
+
+    loop_interface->RunMenu();
+
+    if (drone)
+    {
+        // In drone mode, do not generate any ticcmds.
+
+        return false;
+    }
+
+    if (new_sync)
+    {
+       // If playing single player, do not allow tics to buffer
+       // up very far
+
+       if (!net_client_connected && maketic - gameticdiv > 2)
+           return false;
+
+       // Never go more than ~200ms ahead
+
+       if (maketic - gameticdiv > 8)
+           return false;
+    }
+    else
+    {
+       if (maketic - gameticdiv >= 5)
+           return false;
+    }
+
+    //printf ("mk:%i ",maketic);
+    memset(&cmd, 0, sizeof(ticcmd_t));
+    loop_interface->BuildTiccmd(&cmd, maketic);
+
+#ifdef FEATURE_MULTIPLAYER
+
+    if (net_client_connected)
+    {
+        NET_CL_SendTiccmd(&cmd, maketic);
+    }
+
+#endif
+    ticdata[maketic % BACKUPTICS].cmds[localplayer] = cmd;
+    ticdata[maketic % BACKUPTICS].ingame[localplayer] = true;
+
+    ++maketic;
+
+    return true;
+}
+
+//
+// NetUpdate
+// Builds ticcmds for console player,
+// sends out a packet
+//
+int      lasttime;
+
+void NetUpdate (void)
+{
+    int nowtime;
+    int newtics;
+    int        i;
+
+    // If we are running with singletics (timing a demo), this
+    // is all done separately.
+
+    if (singletics)
+        return;
+
+#ifdef FEATURE_MULTIPLAYER
+
+    // Run network subsystems
+
+    NET_CL_Run();
+    NET_SV_Run();
+
+#endif
+
+    // check time
+    nowtime = GetAdjustedTime() / ticdup;
+    newtics = nowtime - lasttime;
+
+    lasttime = nowtime;
+
+    if (skiptics <= newtics)
+    {
+        newtics -= skiptics;
+        skiptics = 0;
+    }
+    else
+    {
+        skiptics -= newtics;
+        newtics = 0;
+    }
+
+    // build new ticcmds for console player
+
+    for (i=0 ; i<newtics ; i++)
+    {
+        if (!BuildNewTic())
+        {
+            break;
+        }
+    }
+}
+
+static void D_Disconnected(void)
+{
+    // In drone mode, the game cannot continue once disconnected.
+
+    if (drone)
+    {
+        I_Error("Disconnected from server in drone mode.");
+    }
+
+    // disconnected from server
+
+    printf("Disconnected from server.\n");
+}
+
+//
+// Invoked by the network engine when a complete set of ticcmds is
+// available.
+//
+
+void D_ReceiveTic(ticcmd_t *ticcmds, boolean *players_mask)
+{
+    int i;
+
+    // Disconnected from server?
+
+    if (ticcmds == NULL && players_mask == NULL)
+    {
+        D_Disconnected();
+        return;
+    }
+
+    for (i = 0; i < NET_MAXPLAYERS; ++i)
+    {
+        if (!drone && i == localplayer)
+        {
+            // This is us.  Don't overwrite it.
+        }
+        else
+        {
+            ticdata[recvtic % BACKUPTICS].cmds[i] = ticcmds[i];
+            ticdata[recvtic % BACKUPTICS].ingame[i] = players_mask[i];
+        }
+    }
+
+    ++recvtic;
+}
+
+//
+// Start game loop
+//
+// Called after the screen is set but before the game starts running.
+//
+
+void D_StartGameLoop(void)
+{
+    lasttime = GetAdjustedTime() / ticdup;
+}
+
+#if ORIGCODE
+//
+// Block until the game start message is received from the server.
+//
+
+static void BlockUntilStart(net_gamesettings_t *settings,
+                            netgame_startup_callback_t callback)
+{
+    while (!NET_CL_GetSettings(settings))
+    {
+        NET_CL_Run();
+        NET_SV_Run();
+
+        if (!net_client_connected)
+        {
+            I_Error("Lost connection to server");
+        }
+
+        if (callback != NULL && !callback(net_client_wait_data.ready_players,
+                                          net_client_wait_data.num_players))
+        {
+            I_Error("Netgame startup aborted.");
+        }
+
+        I_Sleep(100);
+    }
+}
+
+#endif
+
+void D_StartNetGame(net_gamesettings_t *settings,
+                    netgame_startup_callback_t callback)
+{
+#if ORIGCODE
+    int i;
+
+    offsetms = 0;
+    recvtic = 0;
+
+    settings->consoleplayer = 0;
+    settings->num_players = 1;
+    settings->player_classes[0] = player_class;
+
+    //!
+    // @category net
+    //
+    // Use new network client sync code rather than the classic
+    // sync code. This is currently disabled by default because it
+    // has some bugs.
+    //
+    if (M_CheckParm("-newsync") > 0)
+        settings->new_sync = 1;
+    else
+        settings->new_sync = 0;
+
+    // TODO: New sync code is not enabled by default because it's
+    // currently broken. 
+    //if (M_CheckParm("-oldsync") > 0)
+    //    settings->new_sync = 0;
+    //else
+    //    settings->new_sync = 1;
+
+    //!
+    // @category net
+    // @arg <n>
+    //
+    // Send n extra tics in every packet as insurance against dropped
+    // packets.
+    //
+
+    i = M_CheckParmWithArgs("-extratics", 1);
+
+    if (i > 0)
+        settings->extratics = atoi(myargv[i+1]);
+    else
+        settings->extratics = 1;
+
+    //!
+    // @category net
+    // @arg <n>
+    //
+    // Reduce the resolution of the game by a factor of n, reducing
+    // the amount of network bandwidth needed.
+    //
+
+    i = M_CheckParmWithArgs("-dup", 1);
+
+    if (i > 0)
+        settings->ticdup = atoi(myargv[i+1]);
+    else
+        settings->ticdup = 1;
+
+    if (net_client_connected)
+    {
+        // Send our game settings and block until game start is received
+        // from the server.
+
+        NET_CL_StartGame(settings);
+        BlockUntilStart(settings, callback);
+
+        // Read the game settings that were received.
+
+        NET_CL_GetSettings(settings);
+    }
+
+    if (drone)
+    {
+        settings->consoleplayer = 0;
+    }
+
+    // Set the local player and playeringame[] values.
+
+    localplayer = settings->consoleplayer;
+
+    for (i = 0; i < NET_MAXPLAYERS; ++i)
+    {
+        local_playeringame[i] = i < settings->num_players;
+    }
+
+    // Copy settings to global variables.
+
+    ticdup = settings->ticdup;
+    new_sync = settings->new_sync;
+
+    // TODO: Message disabled until we fix new_sync.
+    //if (!new_sync)
+    //{
+    //    printf("Syncing netgames like Vanilla Doom.\n");
+    //}
+#else
+    settings->consoleplayer = 0;
+       settings->num_players = 1;
+       settings->player_classes[0] = player_class;
+       settings->new_sync = 0;
+       settings->extratics = 1;
+       settings->ticdup = 1;
+
+       ticdup = settings->ticdup;
+       new_sync = settings->new_sync;
+#endif
+}
+
+boolean D_InitNetGame(net_connect_data_t *connect_data)
+{
+    boolean result = false;
+#ifdef FEATURE_MULTIPLAYER
+    net_addr_t *addr = NULL;
+    int i;
+#endif
+
+    // Call D_QuitNetGame on exit:
+
+    I_AtExit(D_QuitNetGame, true);
+
+    player_class = connect_data->player_class;
+
+#ifdef FEATURE_MULTIPLAYER
+
+    //!
+    // @category net
+    //
+    // Start a multiplayer server, listening for connections.
+    //
+
+    if (M_CheckParm("-server") > 0
+     || M_CheckParm("-privateserver") > 0)
+    {
+        NET_SV_Init();
+        NET_SV_AddModule(&net_loop_server_module);
+        NET_SV_AddModule(&net_sdl_module);
+        NET_SV_RegisterWithMaster();
+
+        net_loop_client_module.InitClient();
+        addr = net_loop_client_module.ResolveAddress(NULL);
+    }
+    else
+    {
+        //!
+        // @category net
+        //
+        // Automatically search the local LAN for a multiplayer
+        // server and join it.
+        //
+
+        i = M_CheckParm("-autojoin");
+
+        if (i > 0)
+        {
+            addr = NET_FindLANServer();
+
+            if (addr == NULL)
+            {
+                I_Error("No server found on local LAN");
+            }
+        }
+
+        //!
+        // @arg <address>
+        // @category net
+        //
+        // Connect to a multiplayer server running on the given
+        // address.
+        //
+
+        i = M_CheckParmWithArgs("-connect", 1);
+
+        if (i > 0)
+        {
+            net_sdl_module.InitClient();
+            addr = net_sdl_module.ResolveAddress(myargv[i+1]);
+
+            if (addr == NULL)
+            {
+                I_Error("Unable to resolve '%s'\n", myargv[i+1]);
+            }
+        }
+    }
+
+    if (addr != NULL)
+    {
+        if (M_CheckParm("-drone") > 0)
+        {
+            connect_data->drone = true;
+        }
+
+        if (!NET_CL_Connect(addr, connect_data))
+        {
+            I_Error("D_InitNetGame: Failed to connect to %s\n",
+                    NET_AddrToString(addr));
+        }
+
+        printf("D_InitNetGame: Connected to %s\n", NET_AddrToString(addr));
+
+        // Wait for launch message received from server.
+
+        NET_WaitForLaunch();
+
+        result = true;
+    }
+#endif
+
+    return result;
+}
+
+
+//
+// D_QuitNetGame
+// Called before quitting to leave a net game
+// without hanging the other players
+//
+void D_QuitNetGame (void)
+{
+#ifdef FEATURE_MULTIPLAYER
+    NET_SV_Shutdown();
+    NET_CL_Disconnect();
+#endif
+}
+
+static int GetLowTic(void)
+{
+    int lowtic;
+
+    lowtic = maketic;
+
+#ifdef FEATURE_MULTIPLAYER
+    if (net_client_connected)
+    {
+        if (drone || recvtic < lowtic)
+        {
+            lowtic = recvtic;
+        }
+    }
+#endif
+
+    return lowtic;
+}
+
+static int frameon;
+static int frameskip[4];
+static int oldnettics;
+
+static void OldNetSync(void)
+{
+    unsigned int i;
+    int keyplayer = -1;
+
+    frameon++;
+
+    // ideally maketic should be 1 - 3 tics above lowtic
+    // if we are consistantly slower, speed up time
+
+    for (i=0 ; i<NET_MAXPLAYERS ; i++)
+    {
+        if (local_playeringame[i])
+        {
+            keyplayer = i;
+            break;
+        }
+    }
+
+    if (keyplayer < 0)
+    {
+        // If there are no players, we can never advance anyway
+
+        return;
+    }
+
+    if (localplayer == keyplayer)
+    {
+        // the key player does not adapt
+    }
+    else
+    {
+        if (maketic <= recvtic)
+        {
+            lasttime--;
+            // printf ("-");
+        }
+
+        frameskip[frameon & 3] = oldnettics > recvtic;
+        oldnettics = maketic;
+
+        if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
+        {
+            skiptics = 1;
+            // printf ("+");
+        }
+    }
+}
+
+// Returns true if there are players in the game:
+
+static boolean PlayersInGame(void)
+{
+    boolean result = false;
+    unsigned int i;
+
+    // If we are connected to a server, check if there are any players
+    // in the game.
+
+    if (net_client_connected)
+    {
+        for (i = 0; i < NET_MAXPLAYERS; ++i)
+        {
+            result = result || local_playeringame[i];
+        }
+    }
+
+    // Whether single or multi-player, unless we are running as a drone,
+    // we are in the game.
+
+    if (!drone)
+    {
+        result = true;
+    }
+
+    return result;
+}
+
+// When using ticdup, certain values must be cleared out when running
+// the duplicate ticcmds.
+
+static void TicdupSquash(ticcmd_set_t *set)
+{
+    ticcmd_t *cmd;
+    unsigned int i;
+
+    for (i = 0; i < NET_MAXPLAYERS ; ++i)
+    {
+        cmd = &set->cmds[i];
+        cmd->chatchar = 0;
+        if (cmd->buttons & BT_SPECIAL)
+            cmd->buttons = 0;
+    }
+}
+
+// When running in single player mode, clear all the ingame[] array
+// except the local player.
+
+static void SinglePlayerClear(ticcmd_set_t *set)
+{
+    unsigned int i;
+
+    for (i = 0; i < NET_MAXPLAYERS; ++i)
+    {
+        if (i != localplayer)
+        {
+            set->ingame[i] = false;
+        }
+    }
+}
+
+//
+// TryRunTics
+//
+
+void TryRunTics (void)
+{
+    int        i;
+    int        lowtic;
+    int        entertic;
+    static int oldentertics;
+    int realtics;
+    int        availabletics;
+    int        counts;
+
+    // get real tics
+    entertic = I_GetTime() / ticdup;
+    realtics = entertic - oldentertics;
+    oldentertics = entertic;
+
+    // in singletics mode, run a single tic every time this function
+    // is called.
+
+    if (singletics)
+    {
+        BuildNewTic();
+    }
+    else
+    {
+        NetUpdate ();
+    }
+
+    lowtic = GetLowTic();
+
+    availabletics = lowtic - gametic/ticdup;
+
+    // decide how many tics to run
+
+    if (new_sync)
+    {
+       counts = availabletics;
+    }
+    else
+    {
+        // decide how many tics to run
+        if (realtics < availabletics-1)
+            counts = realtics+1;
+        else if (realtics < availabletics)
+            counts = realtics;
+        else
+            counts = availabletics;
+
+        if (counts < 1)
+            counts = 1;
+
+        if (net_client_connected)
+        {
+            OldNetSync();
+        }
+    }
+
+    if (counts < 1)
+       counts = 1;
+
+    // wait for new tics if needed
+
+    while (!PlayersInGame() || lowtic < gametic/ticdup + counts)
+    {
+       NetUpdate ();
+
+        lowtic = GetLowTic();
+
+       if (lowtic < gametic/ticdup)
+           I_Error ("TryRunTics: lowtic < gametic");
+
+        // Don't stay in this loop forever.  The menu is still running,
+        // so return to update the screen
+
+       if (I_GetTime() / ticdup - entertic > 0)
+       {
+           return;
+       }
+
+        I_Sleep(1);
+    }
+
+    // run the count * ticdup dics
+    while (counts--)
+    {
+        ticcmd_set_t *set;
+
+        if (!PlayersInGame())
+        {
+            return;
+        }
+
+        set = &ticdata[(gametic / ticdup) % BACKUPTICS];
+
+        if (!net_client_connected)
+        {
+            SinglePlayerClear(set);
+        }
+
+       for (i=0 ; i<ticdup ; i++)
+       {
+            if (gametic/ticdup > lowtic)
+                I_Error ("gametic>lowtic");
+
+            memcpy(local_playeringame, set->ingame, sizeof(local_playeringame));
+
+            loop_interface->RunTic(set->cmds, set->ingame);
+           gametic++;
+
+           // modify command for duplicated tics
+
+            TicdupSquash(set);
+       }
+
+       NetUpdate ();   // check for new console commands
+    }
+}
+
+void D_RegisterLoopCallbacks(loop_interface_t *i)
+{
+    loop_interface = i;
+}
diff --git a/frosted-doom/d_loop.h b/frosted-doom/d_loop.h
new file mode 100644 (file)
index 0000000..eb87d84
--- /dev/null
@@ -0,0 +1,81 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//     Main loop stuff.
+//
+
+#ifndef __D_LOOP__
+#define __D_LOOP__
+
+#include "net_defs.h"
+
+// Callback function invoked while waiting for the netgame to start.
+// The callback is invoked when new players are ready. The callback
+// should return true, or return false to abort startup.
+
+typedef boolean (*netgame_startup_callback_t)(int ready_players,
+                                              int num_players);
+
+typedef struct
+{
+    // Read events from the event queue, and process them.
+
+    void (*ProcessEvents)();
+
+    // Given the current input state, fill in the fields of the specified
+    // ticcmd_t structure with data for a new tic.
+
+    void (*BuildTiccmd)(ticcmd_t *cmd, int maketic);
+
+    // Advance the game forward one tic, using the specified player input.
+
+    void (*RunTic)(ticcmd_t *cmds, boolean *ingame);
+
+    // Run the menu (runs independently of the game).
+
+    void (*RunMenu)();
+} loop_interface_t;
+
+// Register callback functions for the main loop code to use.
+void D_RegisterLoopCallbacks(loop_interface_t *i);
+
+// Create any new ticcmds and broadcast to other players.
+void NetUpdate (void);
+
+// Broadcasts special packets to other players
+//  to notify of game exit
+void D_QuitNetGame (void);
+
+//? how many ticks to run?
+void TryRunTics (void);
+
+// Called at start of game loop to initialize timers
+void D_StartGameLoop(void);
+
+// Initialize networking code and connect to server.
+
+boolean D_InitNetGame(net_connect_data_t *connect_data);
+
+// Start game with specified settings. The structure will be updated
+// with the actual settings for the game.
+
+void D_StartNetGame(net_gamesettings_t *settings,
+                    netgame_startup_callback_t callback);
+
+extern boolean singletics;
+extern int gametic, ticdup;
+
+#endif
+
index 337bc082291b946db23d5470690434396acfe288..59f67d924c5993d508e4b7087fa5c9daec383566 100644 (file)
@@ -1,20 +1,16 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     DOOM main program (D_DoomMain) and game loop (D_DoomLoop),
 //     parse command line parameters, configure game parameters (turbo),
 //     and call the startup functions.
 //
-//-----------------------------------------------------------------------------
-
-
-static const char rcsid[] = "$Id: d_main.c,v 1.8 1997/02/03 22:45:09 b1 Exp $";
 
-#define        BGCOLOR         7
-#define        FGCOLOR         8
 
-
-#ifdef NORMALUNIX
+#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#endif
-
+#include <string.h>
 
+#include "config.h"
+#include "deh_main.h"
 #include "doomdef.h"
 #include "doomstat.h"
 
 #include "dstrings.h"
+#include "doomfeatures.h"
 #include "sounds.h"
 
+#include "d_iwad.h"
 
 #include "z_zone.h"
+#include "w_main.h"
 #include "w_wad.h"
 #include "s_sound.h"
 #include "v_video.h"
@@ -57,11 +46,16 @@ static const char rcsid[] = "$Id: d_main.c,v 1.8 1997/02/03 22:45:09 b1 Exp $";
 #include "f_wipe.h"
 
 #include "m_argv.h"
+#include "m_config.h"
+#include "m_controls.h"
 #include "m_misc.h"
 #include "m_menu.h"
+#include "p_saveg.h"
 
+#include "i_endoom.h"
+#include "i_joystick.h"
 #include "i_system.h"
-#include "i_sound.h"
+#include "i_timer.h"
 #include "i_video.h"
 
 #include "g_game.h"
@@ -70,9 +64,13 @@ static const char rcsid[] = "$Id: d_main.c,v 1.8 1997/02/03 22:45:09 b1 Exp $";
 #include "wi_stuff.h"
 #include "st_stuff.h"
 #include "am_map.h"
+#include "net_client.h"
+#include "net_dedicated.h"
+#include "net_query.h"
 
 #include "p_setup.h"
 #include "r_local.h"
+#include "statdump.h"
 
 
 #include "d_main.h"
@@ -88,8 +86,13 @@ static const char rcsid[] = "$Id: d_main.c,v 1.8 1997/02/03 22:45:09 b1 Exp $";
 //
 void D_DoomLoop (void);
 
+// Location where savegames are stored
+
+char *          savegamedir;
 
-char*          wadfiles[MAXWADFILES];
+// location of IWAD and WAD files
+
+char *          iwadfile;
 
 
 boolean                devparm;        // started game with -devparm
@@ -97,12 +100,6 @@ boolean         nomonsters; // checkparm of -nomonsters
 boolean         respawnparm;   // checkparm of -respawn
 boolean         fastparm;      // checkparm of -fast
 
-boolean         drone;
-
-boolean                singletics = false; // debug flag to cancel adaptiveness
-
-
-
 //extern int soundVolume;
 //extern  int  sfxVolume;
 //extern  int  musicVolume;
@@ -113,45 +110,27 @@ skill_t           startskill;
 int             startepisode;
 int            startmap;
 boolean                autostart;
-
-FILE*          debugfile;
+int             startloadgame;
 
 boolean                advancedemo;
 
+// Store demo, do not accept any inputs
+boolean         storedemo;
 
+// "BFG Edition" version of doom2.wad does not include TITLEPIC.
+boolean         bfgedition;
 
+// If true, the main game loop has started.
+boolean         main_loop_started = false;
 
 char           wadfile[1024];          // primary wad file
 char           mapdir[1024];           // directory of development maps
-char           basedefault[1024];      // default file
 
+int             show_endoom = 1;
 
-void D_CheckNetGame (void);
-void D_ProcessEvents (void);
-void G_BuildTiccmd (ticcmd_t* cmd);
-void D_DoAdvanceDemo (void);
 
-
-//
-// EVENT HANDLING
-//
-// Events are asynchronous inputs generally generated by the game user.
-// Events can be discarded if no responder claims them
-//
-event_t         events[MAXEVENTS];
-int             eventhead;
-int            eventtail;
-
-
-//
-// D_PostEvent
-// Called by the I/O functions when input is detected
-//
-void D_PostEvent (event_t* ev)
-{
-    events[eventhead] = *ev;
-    eventhead = (eventhead + 1) % MAXEVENTS;
-}
+void D_ConnectNetGame(void);
+void D_CheckNetGame(void);
 
 
 //
@@ -163,13 +142,11 @@ void D_ProcessEvents (void)
     event_t*   ev;
        
     // IF STORE DEMO, DO NOT ACCEPT INPUT
-    if ( ( gamemode == commercial )
-        && (W_CheckNumForName("map01")<0) )
-      return;
+    if (storedemo)
+        return;
        
-    for ( ; eventtail != eventhead ; eventtail = (eventtail+1)%(MAXEVENTS) )
+    while ((ev = D_PopEvent()) != NULL)
     {
-       ev = &events[eventtail];
        if (M_Responder (ev))
            continue;               // menu ate the event
        G_Responder (ev);
@@ -207,57 +184,57 @@ void D_Display (void)
     boolean                    redrawsbar;
 
     if (nodrawers)
-       return;                    // for comparative timing / profiling
+       return;                    // for comparative timing / profiling
                
     redrawsbar = false;
     
     // change the view size if needed
     if (setsizeneeded)
     {
-       R_ExecuteSetViewSize ();
-       oldgamestate = -1;                      // force background redraw
-       borderdrawcount = 3;
+               R_ExecuteSetViewSize ();
+               oldgamestate = -1;                      // force background redraw
+               borderdrawcount = 3;
     }
 
     // save the current screen if about to wipe
     if (gamestate != wipegamestate)
-    {
-       wipe = true;
-       wipe_StartScreen(0, 0, SCREENWIDTH, SCREENHEIGHT);
+               {
+               wipe = true;
+               wipe_StartScreen(0, 0, SCREENWIDTH, SCREENHEIGHT);
     }
     else
-       wipe = false;
+       wipe = false;
 
     if (gamestate == GS_LEVEL && gametic)
-       HU_Erase();
+       HU_Erase();
     
     // do buffered drawing
     switch (gamestate)
     {
       case GS_LEVEL:
-       if (!gametic)
-           break;
-       if (automapactive)
-           AM_Drawer ();
-       if (wipe || (viewheight != 200 && fullscreen) )
-           redrawsbar = true;
-       if (inhelpscreensstate && !inhelpscreens)
-           redrawsbar = true;              // just put away the help screen
-       ST_Drawer (viewheight == 200, redrawsbar );
-       fullscreen = viewheight == 200;
-       break;
+               if (!gametic)
+                       break;
+               if (automapactive)
+                       AM_Drawer ();
+               if (wipe || (viewheight != 200 && fullscreen) )
+                       redrawsbar = true;
+               if (inhelpscreensstate && !inhelpscreens)
+                       redrawsbar = true;              // just put away the help screen
+               ST_Drawer (viewheight == 200, redrawsbar );
+               fullscreen = viewheight == 200;
+               break;
 
       case GS_INTERMISSION:
-       WI_Drawer ();
-       break;
+               WI_Drawer ();
+               break;
 
       case GS_FINALE:
-       F_Drawer ();
-       break;
+               F_Drawer ();
+               break;
 
       case GS_DEMOSCREEN:
-       D_PageDrawer ();
-       break;
+               D_PageDrawer ();
+               break;
     }
     
     // draw buffered stuff to screen
@@ -265,33 +242,39 @@ void D_Display (void)
     
     // draw the view directly
     if (gamestate == GS_LEVEL && !automapactive && gametic)
-       R_RenderPlayerView (&players[displayplayer]);
+       R_RenderPlayerView (&players[displayplayer]);
 
     if (gamestate == GS_LEVEL && gametic)
-       HU_Drawer ();
+       HU_Drawer ();
     
     // clean up border stuff
     if (gamestate != oldgamestate && gamestate != GS_LEVEL)
-       I_SetPalette (W_CacheLumpName ("PLAYPAL",PU_CACHE));
+       I_SetPalette (W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE));
 
     // see if the border needs to be initially drawn
     if (gamestate == GS_LEVEL && oldgamestate != GS_LEVEL)
     {
-       viewactivestate = false;        // view was not active
-       R_FillBackScreen ();    // draw the pattern into the back screen
+               viewactivestate = false;        // view was not active
+               R_FillBackScreen ();    // draw the pattern into the back screen
     }
 
     // see if the border needs to be updated to the screen
     if (gamestate == GS_LEVEL && !automapactive && scaledviewwidth != 320)
     {
-       if (menuactive || menuactivestate || !viewactivestate)
-           borderdrawcount = 3;
-       if (borderdrawcount)
-       {
-           R_DrawViewBorder ();    // erase old menu stuff
-           borderdrawcount--;
-       }
+               if (menuactive || menuactivestate || !viewactivestate)
+                       borderdrawcount = 3;
+               if (borderdrawcount)
+               {
+                       R_DrawViewBorder ();    // erase old menu stuff
+                       borderdrawcount--;
+               }
+    }
 
+    if (testcontrols)
+    {
+        // Box showing current mouse speed
+
+        V_DrawMouseSpeedBox(testcontrols_mousespeed);
     }
 
     menuactivestate = menuactive;
@@ -302,12 +285,12 @@ void D_Display (void)
     // draw pause pic
     if (paused)
     {
-       if (automapactive)
-           y = 4;
-       else
-           y = viewwindowy+4;
-       V_DrawPatchDirect(viewwindowx+(scaledviewwidth-68)/2,
-                         y,0,W_CacheLumpName ("M_PAUSE", PU_CACHE));
+               if (automapactive)
+                       y = 4;
+               else
+                       y = viewwindowy+4;
+               V_DrawPatchDirect(viewwindowx + (scaledviewwidth - 68) / 2, y,
+                                                         W_CacheLumpName (DEH_String("M_PAUSE"), PU_CACHE));
     }
 
 
@@ -334,7 +317,9 @@ void D_Display (void)
        {
            nowtime = I_GetTime ();
            tics = nowtime - wipestart;
-       } while (!tics);
+            I_Sleep(1);
+       } while (tics <= 0);
+        
        wipestart = nowtime;
        done = wipe_ScreenWipe(wipe_Melt
                               , 0, 0, SCREENWIDTH, SCREENHEIGHT, tics);
@@ -344,65 +329,131 @@ void D_Display (void)
     } while (!done);
 }
 
+//
+// Add configuration file variable bindings.
+//
+
+void D_BindVariables(void)
+{
+    int i;
+
+    M_ApplyPlatformDefaults();
+
+    I_BindVideoVariables();
+    I_BindJoystickVariables();
+    I_BindSoundVariables();
+
+    M_BindBaseControls();
+    M_BindWeaponControls();
+    M_BindMapControls();
+    M_BindMenuControls();
+    M_BindChatControls(MAXPLAYERS);
+
+    key_multi_msgplayer[0] = HUSTR_KEYGREEN;
+    key_multi_msgplayer[1] = HUSTR_KEYINDIGO;
+    key_multi_msgplayer[2] = HUSTR_KEYBROWN;
+    key_multi_msgplayer[3] = HUSTR_KEYRED;
 
+#ifdef FEATURE_MULTIPLAYER
+    NET_BindVariables();
+#endif
+
+    M_BindVariable("mouse_sensitivity",      &mouseSensitivity);
+    M_BindVariable("sfx_volume",             &sfxVolume);
+    M_BindVariable("music_volume",           &musicVolume);
+    M_BindVariable("show_messages",          &showMessages);
+    M_BindVariable("screenblocks",           &screenblocks);
+    M_BindVariable("detaillevel",            &detailLevel);
+    M_BindVariable("snd_channels",           &snd_channels);
+    M_BindVariable("vanilla_savegame_limit", &vanilla_savegame_limit);
+    M_BindVariable("vanilla_demo_limit",     &vanilla_demo_limit);
+    M_BindVariable("show_endoom",            &show_endoom);
+
+    // Multiplayer chat macros
+
+    for (i=0; i<10; ++i)
+    {
+        char buf[12];
+
+        M_snprintf(buf, sizeof(buf), "chatmacro%i", i);
+        M_BindVariable(buf, &chat_macros[i]);
+    }
+}
 
 //
-//  D_DoomLoop
+// D_GrabMouseCallback
 //
-extern  boolean         demorecording;
+// Called to determine whether to grab the mouse pointer
+//
+
+boolean D_GrabMouseCallback(void)
+{
+    // Drone players don't need mouse focus
+
+    if (drone)
+        return false;
+
+    // when menu is active or game is paused, release the mouse 
+    if (menuactive || paused)
+        return false;
 
+    // only grab mouse when playing levels (but not demos)
+
+    return (gamestate == GS_LEVEL) && !demoplayback && !advancedemo;
+}
+
+//
+//  D_DoomLoop
+//
 void D_DoomLoop (void)
 {
+    if (bfgedition &&
+        (demorecording || (gameaction == ga_playdemo) || netgame))
+    {
+        printf(" WARNING: You are playing using one of the Doom Classic\n"
+               " IWAD files shipped with the Doom 3: BFG Edition. These are\n"
+               " known to be incompatible with the regular IWAD files and\n"
+               " may cause demos and network games to get out of sync.\n");
+    }
+
     if (demorecording)
-       G_BeginRecording ();
-               
-    if (M_CheckParm ("-debugfile"))
+       G_BeginRecording ();
+
+    main_loop_started = true;
+
+    TryRunTics();
+
+    I_SetWindowTitle(gamedescription);
+    I_GraphicsCheckCommandLine();
+    I_SetGrabMouseCallback(D_GrabMouseCallback);
+    I_InitGraphics();
+    I_EnableLoadingDisk();
+
+    V_RestoreBuffer();
+    R_ExecuteSetViewSize();
+
+    D_StartGameLoop();
+
+    if (testcontrols)
     {
-       char    filename[20];
-       sprintf (filename,"debug%i.txt",consoleplayer);
-       printf ("debug output to: %s\n",filename);
-       debugfile = fopen (filename,"w");
+        wipegamestate = gamestate;
     }
-       
-    I_InitGraphics ();
 
     while (1)
     {
-       // frame syncronous IO operations
-       I_StartFrame ();                
-       
-       // process one or more tics
-       if (singletics)
-       {
-           I_StartTic ();
-           D_ProcessEvents ();
-           G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]);
-           if (advancedemo)
-               D_DoAdvanceDemo ();
-           M_Ticker ();
-           G_Ticker ();
-           gametic++;
-           maketic++;
-       }
-       else
-       {
-           TryRunTics (); // will run at least one tic
-       }
-               
-       S_UpdateSounds (players[consoleplayer].mo);// move positional sounds
-
-       // Update display, next frame, with current state.
-       D_Display ();
-
-#ifndef SNDSERV
-       // Sound mixing for the buffer is snychronous.
-       I_UpdateSound();
-#endif 
-       // Synchronous sound output is explicitly called.
-#ifndef SNDINTR
-       // Update sound output.
-       I_SubmitSound();
-#endif
+               // frame syncronous IO operations
+               I_StartFrame ();
+
+               TryRunTics (); // will run at least one tic
+
+               S_UpdateSounds (players[consoleplayer].mo);// move positional sounds
+
+               // Update display, next frame, with current state.
+               if (screenvisible)
+               {
+                       D_Display ();
+               }
     }
 }
 
@@ -433,7 +484,7 @@ void D_PageTicker (void)
 //
 void D_PageDrawer (void)
 {
-    V_DrawPatch (0,0, 0, W_CacheLumpName(pagename, PU_CACHE));
+    V_DrawPatch (0, 0, W_CacheLumpName(pagename, PU_CACHE));
 }
 
 
@@ -451,7 +502,7 @@ void D_AdvanceDemo (void)
 // This cycles through the demo sequences.
 // FIXME - version dependend demo numbers?
 //
- void D_DoAdvanceDemo (void)
+void D_DoAdvanceDemo (void)
 {
     players[consoleplayer].playerstate = PST_LIVE;  // not reborn
     advancedemo = false;
@@ -459,7 +510,16 @@ void D_AdvanceDemo (void)
     paused = false;
     gameaction = ga_nothing;
 
-    if ( gamemode == retail )
+    // The Ultimate Doom executable changed the demo sequence to add
+    // a DEMO4 demo.  Final Doom was based on Ultimate, so also
+    // includes this change; however, the Final Doom IWADs do not
+    // include a DEMO4 lump, so the game bombs out with an error
+    // when it reaches this point in the demo sequence.
+
+    // However! There is an alternate version of Final Doom that
+    // includes a fixed executable.
+
+    if (gameversion == exe_ultimate || gameversion == exe_final)
       demosequence = (demosequence+1)%7;
     else
       demosequence = (demosequence+1)%6;
@@ -468,33 +528,33 @@ void D_AdvanceDemo (void)
     {
       case 0:
        if ( gamemode == commercial )
-           pagetic = 35 * 11;
+           pagetic = TICRATE * 11;
        else
            pagetic = 170;
        gamestate = GS_DEMOSCREEN;
-       pagename = "TITLEPIC";
+       pagename = DEH_String("TITLEPIC");
        if ( gamemode == commercial )
          S_StartMusic(mus_dm2ttl);
        else
          S_StartMusic (mus_intro);
        break;
       case 1:
-       G_DeferedPlayDemo ("demo1");
+       G_DeferedPlayDemo(DEH_String("demo1"));
        break;
       case 2:
        pagetic = 200;
        gamestate = GS_DEMOSCREEN;
-       pagename = "CREDIT";
+       pagename = DEH_String("CREDIT");
        break;
       case 3:
-       G_DeferedPlayDemo ("demo2");
+       G_DeferedPlayDemo(DEH_String("demo2"));
        break;
       case 4:
        gamestate = GS_DEMOSCREEN;
        if ( gamemode == commercial)
        {
-           pagetic = 35 * 11;
-           pagename = "TITLEPIC";
+           pagetic = TICRATE * 11;
+           pagename = DEH_String("TITLEPIC");
            S_StartMusic(mus_dm2ttl);
        }
        else
@@ -502,19 +562,27 @@ void D_AdvanceDemo (void)
            pagetic = 200;
 
            if ( gamemode == retail )
-             pagename = "CREDIT";
+             pagename = DEH_String("CREDIT");
            else
-             pagename = "HELP2";
+             pagename = DEH_String("HELP2");
        }
        break;
       case 5:
-       G_DeferedPlayDemo ("demo3");
+       G_DeferedPlayDemo(DEH_String("demo3"));
        break;
         // THE DEFINITIVE DOOM Special Edition demo
       case 6:
-       G_DeferedPlayDemo ("demo4");
+       G_DeferedPlayDemo(DEH_String("demo4"));
        break;
     }
+
+    // The Doom 3: BFG Edition version of doom2.wad does not have a
+    // TITLETPIC lump. Use INTERPIC instead as a workaround.
+    if (bfgedition && !strcasecmp(pagename, "TITLEPIC")
+        && W_CheckNumForName("titlepic") < 0)
+    {
+        pagename = DEH_String("INTERPIC");
+    }
 }
 
 
@@ -529,364 +597,736 @@ void D_StartTitle (void)
     D_AdvanceDemo ();
 }
 
+// Strings for dehacked replacements of the startup banner
+//
+// These are from the original source: some of them are perhaps
+// not used in any dehacked patches
 
+static char *banners[] =
+{
+    // doom2.wad
+    "                         "
+    "DOOM 2: Hell on Earth v%i.%i"
+    "                           ",
+    // doom1.wad
+    "                            "
+    "DOOM Shareware Startup v%i.%i"
+    "                           ",
+    // doom.wad
+    "                            "
+    "DOOM Registered Startup v%i.%i"
+    "                           ",
+    // Registered DOOM uses this
+    "                          "
+    "DOOM System Startup v%i.%i"
+    "                          ",
+    // doom.wad (Ultimate DOOM)
+    "                         "
+    "The Ultimate DOOM Startup v%i.%i"
+    "                        ",
+    // tnt.wad
+    "                     "
+    "DOOM 2: TNT - Evilution v%i.%i"
+    "                           ",
+    // plutonia.wad
+    "                   "
+    "DOOM 2: Plutonia Experiment v%i.%i"
+    "                           ",
+};
 
+//
+// Get game name: if the startup banner has been replaced, use that.
+// Otherwise, use the name given
+// 
 
-//      print title for every printed line
-char            title[128];
-
+static char *GetGameName(char *gamename)
+{
+    size_t i;
+    char *deh_sub;
+    
+    for (i=0; i<arrlen(banners); ++i)
+    {
+        // Has the banner been replaced?
+
+        deh_sub = DEH_String(banners[i]);
+        
+        if (deh_sub != banners[i])
+        {
+            size_t gamename_size;
+            int version;
+
+            // Has been replaced.
+            // We need to expand via printf to include the Doom version number
+            // We also need to cut off spaces to get the basic name
+
+            gamename_size = strlen(deh_sub) + 10;
+            gamename = Z_Malloc(gamename_size, PU_STATIC, 0);
+            version = G_VanillaVersionCode();
+            M_snprintf(gamename, gamename_size, deh_sub,
+                       version / 100, version % 100);
+
+            while (gamename[0] != '\0' && isspace((int)gamename[0]))
+            {
+                memmove(gamename, gamename + 1, gamename_size - 1);
+            }
+
+            while (gamename[0] != '\0' && isspace((int)gamename[strlen(gamename)-1]))
+            {
+                gamename[strlen(gamename) - 1] = '\0';
+            }
+
+            return gamename;
+        }
+    }
 
+    return gamename;
+}
 
-//
-// D_AddFile
-//
-void D_AddFile (char *file)
+static void SetMissionForPackName(char *pack_name)
 {
-    int     numwadfiles;
-    char    *newfile;
-       
-    for (numwadfiles = 0 ; wadfiles[numwadfiles] ; numwadfiles++)
-       ;
+    int i;
+    static const struct
+    {
+        char *name;
+        int mission;
+    } packs[] = {
+        { "doom2",    doom2 },
+        { "tnt",      pack_tnt },
+        { "plutonia", pack_plut },
+    };
+
+    for (i = 0; i < arrlen(packs); ++i)
+    {
+        if (!strcasecmp(pack_name, packs[i].name))
+        {
+            gamemission = packs[i].mission;
+            return;
+        }
+    }
 
-    newfile = malloc (strlen(file)+1);
-    strcpy (newfile, file);
-       
-    wadfiles[numwadfiles] = newfile;
+    printf("Valid mission packs are:\n");
+
+    for (i = 0; i < arrlen(packs); ++i)
+    {
+        printf("\t%s\n", packs[i].name);
+    }
+
+    I_Error("Unknown mission pack name: %s", pack_name);
 }
 
 //
-// IdentifyVersion
-// Checks availability of IWAD files by name,
-// to determine whether registered/commercial features
-// should be executed (notably loading PWAD's).
+// Find out what version of Doom is playing.
 //
-void IdentifyVersion (void)
-{
 
-    char*      doom1wad;
-    char*      doomwad;
-    char*      doomuwad;
-    char*      doom2wad;
-
-    char*      doom2fwad;
-    char*      plutoniawad;
-    char*      tntwad;
-
-#ifdef NORMALUNIX
-    char *home;
-    char *doomwaddir;
-    doomwaddir = getenv("DOOMWADDIR");
-#ifdef __linux__
-       doomwaddir = ".";
-#endif
-    if (!doomwaddir)
-        doomwaddir = "/mnt";
-
-    // Commercial.
-    doom2wad = malloc(strlen(doomwaddir)+1+9+1);
-    sprintf(doom2wad, "%s/doom2.wad", doomwaddir);
+void D_IdentifyVersion(void)
+{
+    // gamemission is set up by the D_FindIWAD function.  But if 
+    // we specify '-iwad', we have to identify using 
+    // IdentifyIWADByName.  However, if the iwad does not match
+    // any known IWAD name, we may have a dilemma.  Try to 
+    // identify by its contents.
 
-    // Retail.
-    doomuwad = malloc(strlen(doomwaddir)+1+9+1);
-    sprintf(doomuwad, "%s/doomu.wad", doomwaddir);
-    
-    // Registered.
-    doomwad = malloc(strlen(doomwaddir)+1+8+1);
-    sprintf(doomwad, "%s/doom.wad", doomwaddir);
-    
-    // Shareware.
-    doom1wad = malloc(strlen(doomwaddir)+1+9+1);
-    //XXX sprintf(doom1wad, "%s/doom1.wad", doomwaddir);
-    sprintf(doom1wad, "%s/DOOM1.WAD", doomwaddir);
+    if (gamemission == none)
+    {
+        unsigned int i;
+
+        for (i=0; i<numlumps; ++i)
+        {
+            if (!strncasecmp(lumpinfo[i].name, "MAP01", 8))
+            {
+                gamemission = doom2;
+                break;
+            } 
+            else if (!strncasecmp(lumpinfo[i].name, "E1M1", 8))
+            {
+                gamemission = doom;
+                break;
+            }
+        }
+
+        if (gamemission == none)
+        {
+            // Still no idea.  I don't think this is going to work.
+
+            I_Error("Unknown or invalid IWAD file.");
+        }
+    }
 
-     // Bug, dear Shawn.
-    // Insufficient malloc, caused spurious realloc errors.
-    plutoniawad = malloc(strlen(doomwaddir)+1+/*9*/12+1);
-    sprintf(plutoniawad, "%s/plutonia.wad", doomwaddir);
+    // Make sure gamemode is set up correctly
 
-    tntwad = malloc(strlen(doomwaddir)+1+9+1);
-    sprintf(tntwad, "%s/tnt.wad", doomwaddir);
+    if (logical_gamemission == doom)
+    {
+        // Doom 1.  But which version?
+
+        if (W_CheckNumForName("E4M1") > 0)
+        {
+            // Ultimate Doom
+
+            gamemode = retail;
+        } 
+        else if (W_CheckNumForName("E3M1") > 0)
+        {
+            gamemode = registered;
+        }
+        else
+        {
+            gamemode = shareware;
+        }
+    }
+    else
+    {
+        int p;
+
+        // Doom 2 of some kind.
+        gamemode = commercial;
+
+        // We can manually override the gamemission that we got from the
+        // IWAD detection code. This allows us to eg. play Plutonia 2
+        // with Freedoom and get the right level names.
+
+        //!
+        // @arg <pack>
+        //
+        // Explicitly specify a Doom II "mission pack" to run as, instead of
+        // detecting it based on the filename. Valid values are: "doom2",
+        // "tnt" and "plutonia".
+        //
+        p = M_CheckParmWithArgs("-pack", 1);
+        if (p > 0)
+        {
+            SetMissionForPackName(myargv[p + 1]);
+        }
+    }
+}
 
+// Set the gamedescription string
 
-    // French stuff.
-    doom2fwad = malloc(strlen(doomwaddir)+1+10+1);
-    sprintf(doom2fwad, "%s/doom2f.wad", doomwaddir);
+void D_SetGameDescription(void)
+{
+    boolean is_freedoom = W_CheckNumForName("FREEDOOM") >= 0,
+            is_freedm = W_CheckNumForName("FREEDM") >= 0;
 
-    //home = getenv("HOME");
-    home = "/mnt";
-    if (!home)
-      I_Error("Please set $HOME to your home directory");
-    sprintf(basedefault, "%s/.doomrc", home);
-#endif
+    gamedescription = "Unknown";
 
-    if (M_CheckParm ("-shdev"))
+    if (logical_gamemission == doom)
     {
-       gamemode = shareware;
-       devparm = true;
-       D_AddFile (DEVDATA"doom1.wad");
-       D_AddFile (DEVMAPS"data_se/texture1.lmp");
-       D_AddFile (DEVMAPS"data_se/pnames.lmp");
-       strcpy (basedefault,DEVDATA"default.cfg");
-       return;
+        // Doom 1.  But which version?
+
+        if (is_freedoom)
+        {
+            gamedescription = GetGameName("Freedoom: Phase 1");
+        }
+        else if (gamemode == retail)
+        {
+            // Ultimate Doom
+
+            gamedescription = GetGameName("The Ultimate DOOM");
+        }
+        else if (gamemode == registered)
+        {
+            gamedescription = GetGameName("DOOM Registered");
+        }
+        else if (gamemode == shareware)
+        {
+            gamedescription = GetGameName("DOOM Shareware");
+        }
     }
-
-    if (M_CheckParm ("-regdev"))
+    else
     {
-       gamemode = registered;
-       devparm = true;
-       D_AddFile (DEVDATA"doom.wad");
-       D_AddFile (DEVMAPS"data_se/texture1.lmp");
-       D_AddFile (DEVMAPS"data_se/texture2.lmp");
-       D_AddFile (DEVMAPS"data_se/pnames.lmp");
-       strcpy (basedefault,DEVDATA"default.cfg");
-       return;
+        // Doom 2 of some kind.  But which mission?
+
+        if (is_freedoom)
+        {
+            if (is_freedm)
+            {
+                gamedescription = GetGameName("FreeDM");
+            }
+            else
+            {
+                gamedescription = GetGameName("Freedoom: Phase 2");
+            }
+        }
+        else if (logical_gamemission == doom2)
+        {
+            gamedescription = GetGameName("DOOM 2: Hell on Earth");
+        }
+        else if (logical_gamemission == pack_plut)
+        {
+            gamedescription = GetGameName("DOOM 2: Plutonia Experiment"); 
+        }
+        else if (logical_gamemission == pack_tnt)
+        {
+            gamedescription = GetGameName("DOOM 2: TNT - Evilution");
+        }
     }
+}
 
-    if (M_CheckParm ("-comdev"))
-    {
-       gamemode = commercial;
-       devparm = true;
-       /* I don't bother
-       if(plutonia)
-           D_AddFile (DEVDATA"plutonia.wad");
-       else if(tnt)
-           D_AddFile (DEVDATA"tnt.wad");
-       else*/
-           D_AddFile (DEVDATA"doom2.wad");
-           
-       D_AddFile (DEVMAPS"cdata/texture1.lmp");
-       D_AddFile (DEVMAPS"cdata/pnames.lmp");
-       strcpy (basedefault,DEVDATA"default.cfg");
-       return;
-    }
+//      print title for every printed line
+char            title[128];
+
+static boolean D_AddFile(char *filename)
+{
+    wad_file_t *handle;
+
+    printf(" adding %s\n", filename);
+    handle = W_AddFile(filename);
+
+    return handle != NULL;
+}
+
+// Copyright message banners
+// Some dehacked mods replace these.  These are only displayed if they are 
+// replaced by dehacked.
 
-    if ( !access (doom2fwad,R_OK) )
+static char *copyright_banners[] =
+{
+    "===========================================================================\n"
+    "ATTENTION:  This version of DOOM has been modified.  If you would like to\n"
+    "get a copy of the original game, call 1-800-IDGAMES or see the readme file.\n"
+    "        You will not receive technical support for modified games.\n"
+    "                      press enter to continue\n"
+    "===========================================================================\n",
+
+    "===========================================================================\n"
+    "                 Commercial product - do not distribute!\n"
+    "         Please report software piracy to the SPA: 1-800-388-PIR8\n"
+    "===========================================================================\n",
+
+    "===========================================================================\n"
+    "                                Shareware!\n"
+    "===========================================================================\n"
+};
+
+// Prints a message only if it has been modified by dehacked.
+
+void PrintDehackedBanners(void)
+{
+    size_t i;
+
+    for (i=0; i<arrlen(copyright_banners); ++i)
     {
-       gamemode = commercial;
-       // C'est ridicule!
-       // Let's handle languages in config files, okay?
-       language = french;
-       printf("French version\n");
-       D_AddFile (doom2fwad);
-       return;
+        char *deh_s;
+
+        deh_s = DEH_String(copyright_banners[i]);
+
+        if (deh_s != copyright_banners[i])
+        {
+            printf("%s", deh_s);
+
+            // Make sure the modified banner always ends in a newline character.
+            // If it doesn't, add a newline.  This fixes av.wad.
+
+            if (deh_s[strlen(deh_s) - 1] != '\n')
+            {
+                printf("\n");
+            }
+        }
     }
+}
+
+static struct 
+{
+    char *description;
+    char *cmdline;
+    GameVersion_t version;
+} gameversions[] = {
+    {"Doom 1.666",           "1.666",      exe_doom_1_666},
+    {"Doom 1.7/1.7a",        "1.7",        exe_doom_1_7},
+    {"Doom 1.8",             "1.8",        exe_doom_1_8},
+    {"Doom 1.9",             "1.9",        exe_doom_1_9},
+    {"Hacx",                 "hacx",       exe_hacx},
+    {"Ultimate Doom",        "ultimate",   exe_ultimate},
+    {"Final Doom",           "final",      exe_final},
+    {"Final Doom (alt)",     "final2",     exe_final2},
+    {"Chex Quest",           "chex",       exe_chex},
+    { NULL,                  NULL,         0},
+};
+
+// Initialize the game version
+
+static void InitGameVersion(void)
+{
+    int p;
+    int i;
+
+    //! 
+    // @arg <version>
+    // @category compat
+    //
+    // Emulate a specific version of Doom.  Valid values are "1.9",
+    // "ultimate", "final", "final2", "hacx" and "chex".
+    //
+
+    p = M_CheckParmWithArgs("-gameversion", 1);
 
-    if ( !access (doom2wad,R_OK) )
+    if (p)
     {
-       gamemode = commercial;
-       D_AddFile (doom2wad);
-       return;
+        for (i=0; gameversions[i].description != NULL; ++i)
+        {
+            if (!strcmp(myargv[p+1], gameversions[i].cmdline))
+            {
+                gameversion = gameversions[i].version;
+                break;
+            }
+        }
+        
+        if (gameversions[i].description == NULL) 
+        {
+            printf("Supported game versions:\n");
+
+            for (i=0; gameversions[i].description != NULL; ++i)
+            {
+                printf("\t%s (%s)\n", gameversions[i].cmdline,
+                        gameversions[i].description);
+            }
+            
+            I_Error("Unknown game version '%s'", myargv[p+1]);
+        }
     }
-
-    if ( !access (plutoniawad, R_OK ) )
+    else
     {
-      gamemode = commercial;
-      D_AddFile (plutoniawad);
-      return;
+        // Determine automatically
+
+        if (gamemission == pack_chex)
+        {
+            // chex.exe - identified by iwad filename
+
+            gameversion = exe_chex;
+        }
+        else if (gamemission == pack_hacx)
+        {
+            // hacx.exe: identified by iwad filename
+
+            gameversion = exe_hacx;
+        }
+        else if (gamemode == shareware || gamemode == registered)
+        {
+            // original
+
+            gameversion = exe_doom_1_9;
+
+            // TODO: Detect IWADs earlier than Doom v1.9.
+        }
+        else if (gamemode == retail)
+        {
+            gameversion = exe_ultimate;
+        }
+        else if (gamemode == commercial)
+        {
+            if (gamemission == doom2)
+            {
+                gameversion = exe_doom_1_9;
+            }
+            else
+            {
+                // Final Doom: tnt or plutonia
+                // Defaults to emulating the first Final Doom executable,
+                // which has the crash in the demo loop; however, having
+                // this as the default should mean that it plays back
+                // most demos correctly.
+
+                gameversion = exe_final;
+            }
+        }
     }
+    
+    // The original exe does not support retail - 4th episode not supported
 
-    if ( !access ( tntwad, R_OK ) )
+    if (gameversion < exe_ultimate && gamemode == retail)
     {
-      gamemode = commercial;
-      D_AddFile (tntwad);
-      return;
+        gamemode = registered;
     }
 
-    if ( !access (doomuwad,R_OK) )
+    // EXEs prior to the Final Doom exes do not support Final Doom.
+
+    if (gameversion < exe_final && gamemode == commercial
+     && (gamemission == pack_tnt || gamemission == pack_plut))
     {
-      gamemode = retail;
-      D_AddFile (doomuwad);
-      return;
+        gamemission = doom2;
     }
+}
+
+void PrintGameVersion(void)
+{
+    int i;
 
-    if ( !access (doomwad,R_OK) )
+    for (i=0; gameversions[i].description != NULL; ++i)
     {
-      gamemode = registered;
-      D_AddFile (doomwad);
-      return;
+        if (gameversions[i].version == gameversion)
+        {
+            printf("Emulating the behavior of the "
+                   "'%s' executable.\n", gameversions[i].description);
+            break;
+        }
     }
+}
+
+// Function called at exit to display the ENDOOM screen
 
-    if ( !access (doom1wad,R_OK) )
+static void D_Endoom(void)
+{
+    byte *endoom;
+
+    // Don't show ENDOOM if we have it disabled, or we're running
+    // in screensaver or control test mode. Only show it once the
+    // game has actually started.
+
+    if (!show_endoom || !main_loop_started
+     || screensaver_mode || M_CheckParm("-testcontrols") > 0)
     {
-      gamemode = shareware;
-      D_AddFile (doom1wad);
-      return;
+        return;
     }
 
-    printf("Game mode indeterminate.\n");
-    gamemode = indetermined;
+    endoom = W_CacheLumpName(DEH_String("ENDOOM"), PU_STATIC);
 
-    // We don't abort. Let's see what the PWAD contains.
-    //exit(1);
-    //I_Error ("Game mode indeterminate\n");
+    I_Endoom(endoom);
 }
 
-//
-// Find a Response File
-//
-void FindResponseFile (void)
+#if ORIGCODE
+// Load dehacked patches needed for certain IWADs.
+static void LoadIwadDeh(void)
 {
-    int             i;
-#define MAXARGVS        100
-       
-    for (i = 1;i < myargc;i++)
-       if (myargv[i][0] == '@')
-       {
-           FILE *          handle;
-           int             size;
-           int             k;
-           int             index;
-           int             indexinfile;
-           char    *infile;
-           char    *file;
-           char    *moreargs[20];
-           char    *firstargv;
-                       
-           // READ THE RESPONSE FILE INTO MEMORY
-           handle = fopen (&myargv[i][1],"rb");
-           if (!handle)
-           {
-               printf ("\nNo such response file!");
-               exit(1);
-           }
-           printf("Found response file %s!\n",&myargv[i][1]);
-           fseek (handle,0,SEEK_END);
-           size = ftell(handle);
-           fseek (handle,0,SEEK_SET);
-           file = malloc (size);
-           fread (file,size,1,handle);
-           fclose (handle);
-                       
-           // KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG
-           for (index = 0,k = i+1; k < myargc; k++)
-               moreargs[index++] = myargv[k];
-                       
-           firstargv = myargv[0];
-           myargv = malloc(sizeof(char *)*MAXARGVS);
-           memset(myargv,0,sizeof(char *)*MAXARGVS);
-           myargv[0] = firstargv;
-                       
-           infile = file;
-           indexinfile = k = 0;
-           indexinfile++;  // SKIP PAST ARGV[0] (KEEP IT)
-           do
-           {
-               myargv[indexinfile++] = infile+k;
-               while(k < size &&
-                     ((*(infile+k)>= ' '+1) && (*(infile+k)<='z')))
-                   k++;
-               *(infile+k) = 0;
-               while(k < size &&
-                     ((*(infile+k)<= ' ') || (*(infile+k)>'z')))
-                   k++;
-           } while(k < size);
-                       
-           for (k = 0;k < index;k++)
-               myargv[indexinfile++] = moreargs[k];
-           myargc = indexinfile;
-       
-           // DISPLAY ARGS
-           printf("%d command-line args:\n",myargc);
-           for (k=1;k<myargc;k++)
-               printf("%s\n",myargv[k]);
+    // The Freedoom IWADs have DEHACKED lumps that must be loaded.
+    if (W_CheckNumForName("FREEDOOM") >= 0)
+    {
+        // Old versions of Freedoom (before 2014-09) did not have technically
+        // valid DEHACKED lumps, so ignore errors and just continue if this
+        // is an old IWAD.
+        DEH_LoadLumpByName("DEHACKED", false, true);
+    }
 
-           break;
-       }
-}
+    // If this is the HACX IWAD, we need to load the DEHACKED lump.
+    if (gameversion == exe_hacx)
+    {
+        if (!DEH_LoadLumpByName("DEHACKED", true, false))
+        {
+            I_Error("DEHACKED lump not found.  Please check that this is the "
+                    "Hacx v1.2 IWAD.");
+        }
+    }
 
+    // Chex Quest needs a separate Dehacked patch which must be downloaded
+    // and installed next to the IWAD.
+    if (gameversion == exe_chex)
+    {
+        char *chex_deh = NULL;
+        char *sep;
+
+        // Look for chex.deh in the same directory as the IWAD file.
+        sep = strrchr(iwadfile, DIR_SEPARATOR);
+
+        if (sep != NULL)
+        {
+            size_t chex_deh_len = strlen(iwadfile) + 9;
+            chex_deh = malloc(chex_deh_len);
+            M_StringCopy(chex_deh, iwadfile, chex_deh_len);
+            chex_deh[sep - iwadfile + 1] = '\0';
+            M_StringConcat(chex_deh, "chex.deh", chex_deh_len);
+        }
+        else
+        {
+            chex_deh = strdup("chex.deh");
+        }
+
+        // If the dehacked patch isn't found, try searching the WAD
+        // search path instead.  We might find it...
+        if (!M_FileExists(chex_deh))
+        {
+            free(chex_deh);
+            chex_deh = D_FindWADByName("chex.deh");
+        }
+
+        // Still not found?
+        if (chex_deh == NULL)
+        {
+            I_Error("Unable to find Chex Quest dehacked file (chex.deh).\n"
+                    "The dehacked file is required in order to emulate\n"
+                    "chex.exe correctly.  It can be found in your nearest\n"
+                    "/idgames repository mirror at:\n\n"
+                    "   utils/exe_edit/patches/chexdeh.zip");
+        }
+
+        if (!DEH_LoadFile(chex_deh))
+        {
+            I_Error("Failed to load chex.deh needed for emulating chex.exe.");
+        }
+    }
+}
+#endif
 
 //
 // D_DoomMain
 //
 void D_DoomMain (void)
 {
-    int             p;
-    char                    file[256];
+    int p;
+    char file[256];
+    char demolumpname[9];
+#if ORIGCODE
+    int numiwadlumps;
+#endif
 
-    FindResponseFile ();
-       
-    IdentifyVersion ();
-       
-    //XXX setbuf (stdout, NULL);
-    modifiedgame = false;
+    I_AtExit(D_Endoom, false);
+
+    // print banner
+
+    I_PrintBanner(PACKAGE_STRING);
+
+    DEH_printf("Z_Init: Init zone memory allocation daemon. \n");
+    Z_Init ();
+
+#ifdef FEATURE_MULTIPLAYER
+    //!
+    // @category net
+    //
+    // Start a dedicated server, routing packets but not participating
+    // in the game itself.
+    //
+
+    if (M_CheckParm("-dedicated") > 0)
+    {
+        printf("Dedicated server mode.\n");
+        NET_DedicatedServer();
+
+        // Never returns
+    }
+
+    //!
+    // @category net
+    //
+    // Query the Internet master server for a global list of active
+    // servers.
+    //
+
+    if (M_CheckParm("-search"))
+    {
+        NET_MasterQuery();
+        exit(0);
+    }
+
+    //!
+    // @arg <address>
+    // @category net
+    //
+    // Query the status of the server running on the given IP
+    // address.
+    //
+
+    p = M_CheckParmWithArgs("-query", 1);
+
+    if (p)
+    {
+        NET_QueryAddress(myargv[p+1]);
+        exit(0);
+    }
+
+    //!
+    // @category net
+    //
+    // Search the local LAN for running servers.
+    //
+
+    if (M_CheckParm("-localsearch"))
+    {
+        NET_LANQuery();
+        exit(0);
+    }
+
+#endif
+
+    //!
+    // @vanilla
+    //
+    // Disable monsters.
+    //
        
     nomonsters = M_CheckParm ("-nomonsters");
+
+    //!
+    // @vanilla
+    //
+    // Monsters respawn after being killed.
+    //
+
     respawnparm = M_CheckParm ("-respawn");
+
+    //!
+    // @vanilla
+    //
+    // Monsters move faster.
+    //
+
     fastparm = M_CheckParm ("-fast");
+
+    //! 
+    // @vanilla
+    //
+    // Developer mode.  F1 saves a screenshot in the current working
+    // directory.
+    //
+
     devparm = M_CheckParm ("-devparm");
-    if (M_CheckParm ("-altdeath"))
-       deathmatch = 2;
-    else if (M_CheckParm ("-deathmatch"))
+
+    I_DisplayFPSDots(devparm);
+
+    //!
+    // @category net
+    // @vanilla
+    //
+    // Start a deathmatch game.
+    //
+
+    if (M_CheckParm ("-deathmatch"))
        deathmatch = 1;
 
-    switch ( gamemode )
-    {
-      case retail:
-       sprintf (title,
-                "                         "
-                "The Ultimate DOOM Startup v%i.%i"
-                "                           ",
-                VERSION/100,VERSION%100);
-       break;
-      case shareware:
-       sprintf (title,
-                "                            "
-                "DOOM Shareware Startup v%i.%i"
-                "                           ",
-                VERSION/100,VERSION%100);
-       break;
-      case registered:
-       sprintf (title,
-                "                            "
-                "DOOM Registered Startup v%i.%i"
-                "                           ",
-                VERSION/100,VERSION%100);
-       break;
-      case commercial:
-       sprintf (title,
-                "                         "
-                "DOOM 2: Hell on Earth v%i.%i"
-                "                           ",
-                VERSION/100,VERSION%100);
-       break;
-/*FIXME
-       case pack_plut:
-       sprintf (title,
-                "                   "
-                "DOOM 2: Plutonia Experiment v%i.%i"
-                "                           ",
-                VERSION/100,VERSION%100);
-       break;
-      case pack_tnt:
-       sprintf (title,
-                "                     "
-                "DOOM 2: TNT - Evilution v%i.%i"
-                "                           ",
-                VERSION/100,VERSION%100);
-       break;
-*/
-      default:
-       sprintf (title,
-                "                     "
-                "Public DOOM - v%i.%i"
-                "                           ",
-                VERSION/100,VERSION%100);
-       break;
-    }
-    
-    printf ("%s\n",title);
+    //!
+    // @category net
+    // @vanilla
+    //
+    // Start a deathmatch 2.0 game.  Weapons do not stay in place and
+    // all items respawn after 30 seconds.
+    //
+
+    if (M_CheckParm ("-altdeath"))
+       deathmatch = 2;
 
     if (devparm)
-       printf(D_DEVSTR);
+       DEH_printf(D_DEVSTR);
     
-    if (M_CheckParm("-cdrom"))
+    // find which dir to use for config files
+
+#ifdef _WIN32
+
+    //!
+    // @platform windows
+    // @vanilla
+    //
+    // Save configuration data and savegames in c:\doomdata,
+    // allowing play from CD.
+    //
+
+    if (M_ParmExists("-cdrom"))
     {
-       printf(D_CDROM);
-       mkdir("c:\\doomdata",0);
-       strcpy (basedefault,"c:/doomdata/default.cfg");
-    }  
-    
-    // turbo option
+        printf(D_CDROM);
+
+        M_SetConfigDir("c:\\doomdata\\");
+    }
+    else
+#endif
+    {
+        // Auto-detect the configuration dir.
+
+        M_SetConfigDir(NULL);
+    }
+
+    //!
+    // @arg <x>
+    // @vanilla
+    //
+    // Turbo mode.  The player's speed is multiplied by x%.  If unspecified,
+    // x defaults to 200.  Values are rounded up to 10 and down to 400.
+    //
+
     if ( (p=M_CheckParm ("-turbo")) )
     {
        int     scale = 200;
@@ -899,132 +1339,221 @@ void D_DoomMain (void)
            scale = 10;
        if (scale > 400)
            scale = 400;
-       printf ("turbo scale: %i%%\n",scale);
+        DEH_printf("turbo scale: %i%%\n", scale);
        forwardmove[0] = forwardmove[0]*scale/100;
        forwardmove[1] = forwardmove[1]*scale/100;
        sidemove[0] = sidemove[0]*scale/100;
        sidemove[1] = sidemove[1]*scale/100;
     }
     
-    // add any files specified on the command line with -file wadfile
-    // to the wad list
-    //
-    // convenience hack to allow -wart e m to add a wad file
-    // prepend a tilde to the filename so wadfile will be reloadable
-    p = M_CheckParm ("-wart");
-    if (p)
-    {
-       myargv[p][4] = 'p';     // big hack, change to -warp
+    // init subsystems
+    DEH_printf("V_Init: allocate screens.\n");
+    V_Init ();
 
-       // Map name handling.
-       switch (gamemode )
-       {
-         case shareware:
-         case retail:
-         case registered:
-           sprintf (file,"~"DEVMAPS"E%cM%c.wad",
-                    myargv[p+1][0], myargv[p+2][0]);
-           printf("Warping to Episode %s, Map %s.\n",
-                  myargv[p+1],myargv[p+2]);
-           break;
-           
-         case commercial:
-         default:
-           p = atoi (myargv[p+1]);
-           if (p<10)
-             sprintf (file,"~"DEVMAPS"cdata/map0%i.wad", p);
-           else
-             sprintf (file,"~"DEVMAPS"cdata/map%i.wad", p);
-           break;
-       }
-       D_AddFile (file);
-    }
-       
-    p = M_CheckParm ("-file");
-    if (p)
+    // Load configuration files before initialising other subsystems.
+    DEH_printf("M_LoadDefaults: Load system defaults.\n");
+    M_SetConfigFilenames("default.cfg", PROGRAM_PREFIX "doom.cfg");
+    D_BindVariables();
+    M_LoadDefaults();
+
+    // Save configuration at exit.
+    I_AtExit(M_SaveDefaults, false);
+
+    // Find main IWAD file and load it.
+    iwadfile = D_FindIWAD(IWAD_MASK_DOOM, &gamemission);
+
+    // None found?
+
+    if (iwadfile == NULL)
     {
-       // the parms after p are wadfile/lump names,
-       // until end of parms or another - preceded parm
-       modifiedgame = true;            // homebrew levels
-       while (++p != myargc && myargv[p][0] != '-')
-           D_AddFile (myargv[p]);
+        I_Error("Game mode indeterminate.  No IWAD file was found.  Try\n"
+                "specifying one with the '-iwad' command line parameter.\n");
     }
 
-    p = M_CheckParm ("-playdemo");
+    modifiedgame = false;
 
-    if (!p)
-       p = M_CheckParm ("-timedemo");
+    DEH_printf("W_Init: Init WADfiles.\n");
+    D_AddFile(iwadfile);
+#if ORIGCODE
+    numiwadlumps = numlumps;
+#endif
+
+    W_CheckCorrectIWAD(doom);
+
+    // Now that we've loaded the IWAD, we can figure out what gamemission
+    // we're playing and which version of Vanilla Doom we need to emulate.
+    D_IdentifyVersion();
+    InitGameVersion();
 
-    if (p && p < myargc-1)
+#if ORIGCODE
+    //!
+    // @category mod
+    //
+    // Disable automatic loading of Dehacked patches for certain
+    // IWAD files.
+    //
+    if (!M_ParmExists("-nodeh"))
     {
-       sprintf (file,"%s.lmp", myargv[p+1]);
-       D_AddFile (file);
-       printf("Playing demo %s.lmp.\n",myargv[p+1]);
+        // Some IWADs have dehacked patches that need to be loaded for
+        // them to be played properly.
+        LoadIwadDeh();
     }
-    
-    // get skill / episode / map from parms
-    startskill = sk_medium;
-    startepisode = 1;
-    startmap = 1;
-    autostart = false;
+#endif
 
-               
-    p = M_CheckParm ("-skill");
-    if (p && p < myargc-1)
+    // Doom 3: BFG Edition includes modified versions of the classic
+    // IWADs which can be identified by an additional DMENUPIC lump.
+    // Furthermore, the M_GDHIGH lumps have been modified in a way that
+    // makes them incompatible to Vanilla Doom and the modified version
+    // of doom2.wad is missing the TITLEPIC lump.
+    // We specifically check for DMENUPIC here, before PWADs have been
+    // loaded which could probably include a lump of that name.
+
+    if (W_CheckNumForName("dmenupic") >= 0)
     {
-       startskill = myargv[p+1][0]-'1';
-       autostart = true;
+        printf("BFG Edition: Using workarounds as needed.\n");
+        bfgedition = true;
+
+        // BFG Edition changes the names of the secret levels to
+        // censor the Wolfenstein references. It also has an extra
+        // secret level (MAP33). In Vanilla Doom (meaning the DOS
+        // version), MAP33 overflows into the Plutonia level names
+        // array, so HUSTR_33 is actually PHUSTR_1.
+
+        DEH_AddStringReplacement(HUSTR_31, "level 31: idkfa");
+        DEH_AddStringReplacement(HUSTR_32, "level 32: keen");
+        DEH_AddStringReplacement(PHUSTR_1, "level 33: betray");
+
+        // The BFG edition doesn't have the "low detail" menu option (fair
+        // enough). But bizarrely, it reuses the M_GDHIGH patch as a label
+        // for the options menu (says "Fullscreen:"). Why the perpetrators
+        // couldn't just add a new graphic lump and had to reuse this one,
+        // I don't know.
+        //
+        // The end result is that M_GDHIGH is too wide and causes the game
+        // to crash. As a workaround to get a minimum level of support for
+        // the BFG edition IWADs, use the "ON"/"OFF" graphics instead.
+
+        DEH_AddStringReplacement("M_GDHIGH", "M_MSGON");
+        DEH_AddStringReplacement("M_GDLOW", "M_MSGOFF");
     }
 
-    p = M_CheckParm ("-episode");
-    if (p && p < myargc-1)
+#ifdef FEATURE_DEHACKED
+    // Load Dehacked patches specified on the command line with -deh.
+    // Note that there's a very careful and deliberate ordering to how
+    // Dehacked patches are loaded. The order we use is:
+    //  1. IWAD dehacked patches.
+    //  2. Command line dehacked patches specified with -deh.
+    //  3. PWAD dehacked patches in DEHACKED lumps.
+    DEH_ParseCommandLine();
+#endif
+
+    // Load PWAD files.
+    modifiedgame = W_ParseCommandLine();
+
+    // Debug:
+//    W_PrintDirectory();
+
+    //!
+    // @arg <demo>
+    // @category demo
+    // @vanilla
+    //
+    // Play back the demo named demo.lmp.
+    //
+
+    p = M_CheckParmWithArgs ("-playdemo", 1);
+
+    if (!p)
     {
-       startepisode = myargv[p+1][0]-'0';
-       startmap = 1;
-       autostart = true;
+        //!
+        // @arg <demo>
+        // @category demo
+        // @vanilla
+        //
+        // Play back the demo named demo.lmp, determining the framerate
+        // of the screen.
+        //
+       p = M_CheckParmWithArgs("-timedemo", 1);
+
     }
-       
-    p = M_CheckParm ("-timer");
-    if (p && p < myargc-1 && deathmatch)
+
+    if (p)
     {
-       int     time;
-       time = atoi(myargv[p+1]);
-       printf("Levels will end after %d minute",time);
-       if (time>1)
-           printf("s");
-       printf(".\n");
+        // With Vanilla you have to specify the file without extension,
+        // but make that optional.
+        if (M_StringEndsWith(myargv[p + 1], ".lmp"))
+        {
+            M_StringCopy(file, myargv[p + 1], sizeof(file));
+        }
+        else
+        {
+            DEH_snprintf(file, sizeof(file), "%s.lmp", myargv[p+1]);
+        }
+
+        if (D_AddFile(file))
+        {
+            M_StringCopy(demolumpname, lumpinfo[numlumps - 1].name,
+                         sizeof(demolumpname));
+        }
+        else
+        {
+            // If file failed to load, still continue trying to play
+            // the demo in the same way as Vanilla Doom.  This makes
+            // tricks like "-playdemo demo1" possible.
+
+            M_StringCopy(demolumpname, myargv[p + 1], sizeof(demolumpname));
+        }
+
+        printf("Playing demo %s.\n", file);
     }
 
-    p = M_CheckParm ("-avg");
-    if (p && p < myargc-1 && deathmatch)
-       printf("Austin Virtual Gaming: Levels will end after 20 minutes\n");
+    I_AtExit((atexit_func_t) G_CheckDemoStatus, true);
+
+    // Generate the WAD hash table.  Speed things up a bit.
+    W_GenerateHashTable();
+
+    // Load DEHACKED lumps from WAD files - but only if we give the right
+    // command line parameter.
 
-    p = M_CheckParm ("-warp");
-    if (p && p < myargc-1)
+#if ORIGCODE
+    //!
+    // @category mod
+    //
+    // Load Dehacked patches from DEHACKED lumps contained in one of the
+    // loaded PWAD files.
+    //
+    if (M_ParmExists("-dehlump"))
     {
-       if (gamemode == commercial)
-           startmap = atoi (myargv[p+1]);
-       else
-       {
-           startepisode = myargv[p+1][0]-'0';
-           startmap = myargv[p+2][0]-'0';
-       }
-       autostart = true;
+        int i, loaded = 0;
+
+        for (i = numiwadlumps; i < numlumps; ++i)
+        {
+            if (!strncmp(lumpinfo[i].name, "DEHACKED", 8))
+            {
+                DEH_LoadLump(i, false, false);
+                loaded++;
+            }
+        }
+
+        printf("  loaded %i DEHACKED lumps from PWAD files.\n", loaded);
     }
-    
-    // init subsystems
-    printf ("V_Init: allocate screens.\n");
-    V_Init ();
-
-    printf ("M_LoadDefaults: Load system defaults.\n");
-    M_LoadDefaults ();              // load before initing other systems
+#endif
 
-    printf ("Z_Init: Init zone memory allocation daemon. \n");
-    Z_Init ();
+    // Set the gamedescription string. This is only possible now that
+    // we've finished loading Dehacked patches.
+    D_SetGameDescription();
 
-    printf ("W_Init: Init WADfiles.\n");
-    W_InitMultipleFiles (wadfiles);
-    
+#ifdef _WIN32
+    // In -cdrom mode, we write savegames to c:\doomdata as well as configs.
+    if (M_ParmExists("-cdrom"))
+    {
+        savegamedir = configdir;
+    }
+    else
+#endif
+    {
+        savegamedir = M_GetSaveGameDir(D_SaveGameIWADName(gamemission));
+    }
 
     // Check for -file in shareware
     if (modifiedgame)
@@ -1040,137 +1569,272 @@ void D_DoomMain (void)
        int i;
        
        if ( gamemode == shareware)
-           I_Error("\nYou cannot -file with the shareware "
-                   "version. Register!");
+           I_Error(DEH_String("\nYou cannot -file with the shareware "
+                              "version. Register!"));
 
        // Check for fake IWAD with right name,
        // but w/o all the lumps of the registered version. 
        if (gamemode == registered)
            for (i = 0;i < 23; i++)
                if (W_CheckNumForName(name[i])<0)
-                   I_Error("\nThis is not the registered version.");
+                   I_Error(DEH_String("\nThis is not the registered version."));
     }
-    
-    // Iff additonal PWAD files are used, print modified banner
-    if (modifiedgame)
+
+    if (W_CheckNumForName("SS_START") >= 0
+     || W_CheckNumForName("FF_END") >= 0)
     {
-       /*m*/printf (
-           "===========================================================================\n"
-           "ATTENTION:  This version of DOOM has been modified.  If you would like to\n"
-           "get a copy of the original game, call 1-800-IDGAMES or see the readme file.\n"
-           "        You will not receive technical support for modified games.\n"
-           "                      press enter to continue\n"
-           "===========================================================================\n"
-           );
-       getchar ();
+        I_PrintDivider();
+        printf(" WARNING: The loaded WAD file contains modified sprites or\n"
+               " floor textures.  You may want to use the '-merge' command\n"
+               " line option instead of '-file'.\n");
     }
-       
 
-    // Check and print which version is executed.
-    switch ( gamemode )
+    I_PrintStartupBanner(gamedescription);
+    PrintDehackedBanners();
+
+    // Freedoom's IWADs are Boom-compatible, which means they usually
+    // don't work in Vanilla (though FreeDM is okay). Show a warning
+    // message and give a link to the website.
+    if (W_CheckNumForName("FREEDOOM") >= 0 && W_CheckNumForName("FREEDM") < 0)
     {
-      case shareware:
-      case indetermined:
-       printf (
-           "===========================================================================\n"
-           "                                Shareware!\n"
-           "===========================================================================\n"
-       );
-       break;
-      case registered:
-      case retail:
-      case commercial:
-       printf (
-           "===========================================================================\n"
-           "                 Commercial product - do not distribute!\n"
-           "         Please report software piracy to the SPA: 1-800-388-PIR8\n"
-           "===========================================================================\n"
-       );
-       break;
+        printf(" WARNING: You are playing using one of the Freedoom IWAD\n"
+               " files, which might not work in this port. See this page\n"
+               " for more information on how to play using Freedoom:\n"
+               "   http://www.chocolate-doom.org/wiki/index.php/Freedoom\n");
+        I_PrintDivider();
+    }
+
+    DEH_printf("I_Init: Setting up machine state.\n");
+    I_CheckIsScreensaver();
+    I_InitTimer();
+    I_InitJoystick();
+    I_InitSound(true);
+    I_InitMusic();
+
+#ifdef FEATURE_MULTIPLAYER
+    printf ("NET_Init: Init network subsystem.\n");
+    NET_Init ();
+#endif
+
+    // Initial netgame startup. Connect to server etc.
+    D_ConnectNetGame();
+
+    // get skill / episode / map from parms
+    startskill = sk_medium;
+    startepisode = 1;
+    startmap = 1;
+    autostart = false;
+
+    //!
+    // @arg <skill>
+    // @vanilla
+    //
+    // Set the game skill, 1-5 (1: easiest, 5: hardest).  A skill of
+    // 0 disables all monsters.
+    //
+
+    p = M_CheckParmWithArgs("-skill", 1);
+
+    if (p)
+    {
+       startskill = myargv[p+1][0]-'1';
+       autostart = true;
+    }
+
+    //!
+    // @arg <n>
+    // @vanilla
+    //
+    // Start playing on episode n (1-4)
+    //
+
+    p = M_CheckParmWithArgs("-episode", 1);
+
+    if (p)
+    {
+       startepisode = myargv[p+1][0]-'0';
+       startmap = 1;
+       autostart = true;
+    }
        
-      default:
-       // Ouch.
-       break;
+    timelimit = 0;
+
+    //! 
+    // @arg <n>
+    // @category net
+    // @vanilla
+    //
+    // For multiplayer games: exit each level after n minutes.
+    //
+
+    p = M_CheckParmWithArgs("-timer", 1);
+
+    if (p)
+    {
+       timelimit = atoi(myargv[p+1]);
     }
 
-    printf ("M_Init: Init miscellaneous info.\n");
+    //!
+    // @category net
+    // @vanilla
+    //
+    // Austin Virtual Gaming: end levels after 20 minutes.
+    //
+
+    p = M_CheckParm ("-avg");
+
+    if (p)
+    {
+       timelimit = 20;
+    }
+
+    //!
+    // @arg [<x> <y> | <xy>]
+    // @vanilla
+    //
+    // Start a game immediately, warping to ExMy (Doom 1) or MAPxy
+    // (Doom 2)
+    //
+
+    p = M_CheckParmWithArgs("-warp", 1);
+
+    if (p)
+    {
+        if (gamemode == commercial)
+            startmap = atoi (myargv[p+1]);
+        else
+        {
+            startepisode = myargv[p+1][0]-'0';
+
+            if (p + 2 < myargc)
+            {
+                startmap = myargv[p+2][0]-'0';
+            }
+            else
+            {
+                startmap = 1;
+            }
+        }
+        autostart = true;
+    }
+
+    // Undocumented:
+    // Invoked by setup to test the controls.
+
+    p = M_CheckParm("-testcontrols");
+
+    if (p > 0)
+    {
+        startepisode = 1;
+        startmap = 1;
+        autostart = true;
+        testcontrols = true;
+    }
+
+    // Check for load game parameter
+    // We do this here and save the slot number, so that the network code
+    // can override it or send the load slot to other players.
+
+    //!
+    // @arg <s>
+    // @vanilla
+    //
+    // Load the game in slot s.
+    //
+
+    p = M_CheckParmWithArgs("-loadgame", 1);
+    
+    if (p)
+    {
+        startloadgame = atoi(myargv[p+1]);
+    }
+    else
+    {
+        // Not loading a game
+        startloadgame = -1;
+    }
+
+    DEH_printf("M_Init: Init miscellaneous info.\n");
     M_Init ();
 
-    printf ("R_Init: Init DOOM refresh daemon - ");
+    DEH_printf("R_Init: Init DOOM refresh daemon - ");
     R_Init ();
 
-    printf ("\nP_Init: Init Playloop state.\n");
+    DEH_printf("\nP_Init: Init Playloop state.\n");
     P_Init ();
 
-    printf ("I_Init: Setting up machine state.\n");
-    I_Init ();
+    DEH_printf("S_Init: Setting up sound.\n");
+    S_Init (sfxVolume * 8, musicVolume * 8);
 
-    printf ("D_CheckNetGame: Checking network game status.\n");
+    DEH_printf("D_CheckNetGame: Checking network game status.\n");
     D_CheckNetGame ();
 
-    printf ("S_Init: Setting up sound.\n");
-    S_Init (snd_SfxVolume /* *8 */, snd_MusicVolume /* *8*/ );
+    PrintGameVersion();
 
-    printf ("HU_Init: Setting up heads up display.\n");
+    DEH_printf("HU_Init: Setting up heads up display.\n");
     HU_Init ();
 
-    printf ("ST_Init: Init status bar.\n");
+    DEH_printf("ST_Init: Init status bar.\n");
     ST_Init ();
 
-    // check for a driver that wants intermission stats
-    p = M_CheckParm ("-statcopy");
-    if (p && p<myargc-1)
-    {
-       // for statistics driver
-       extern  void*   statcopy;                            
+    // If Doom II without a MAP01 lump, this is a store demo.
+    // Moved this here so that MAP01 isn't constantly looked up
+    // in the main loop.
 
-       statcopy = (void*)atoi(myargv[p+1]);
-       printf ("External statistics registered.\n");
-    }
-    
-    // start the apropriate game based on parms
-    p = M_CheckParm ("-record");
+    if (gamemode == commercial && W_CheckNumForName("map01") < 0)
+        storedemo = true;
 
-    if (p && p < myargc-1)
+    if (M_CheckParmWithArgs("-statdump", 1))
     {
-       G_RecordDemo (myargv[p+1]);
-       autostart = true;
+        I_AtExit(StatDump, true);
+        DEH_printf("External statistics registered.\n");
     }
-       
-    p = M_CheckParm ("-playdemo");
-    if (p && p < myargc-1)
+
+    //!
+    // @arg <x>
+    // @category demo
+    // @vanilla
+    //
+    // Record a demo named x.lmp.
+    //
+
+    p = M_CheckParmWithArgs("-record", 1);
+
+    if (p)
     {
-       singledemo = true;              // quit after one demo
-       G_DeferedPlayDemo (myargv[p+1]);
-       D_DoomLoop ();  // never returns
+               G_RecordDemo (myargv[p+1]);
+               autostart = true;
     }
-       
-    p = M_CheckParm ("-timedemo");
-    if (p && p < myargc-1)
+
+    p = M_CheckParmWithArgs("-playdemo", 1);
+    if (p)
     {
-       G_TimeDemo (myargv[p+1]);
-       D_DoomLoop ();  // never returns
+               singledemo = true;              // quit after one demo
+               G_DeferedPlayDemo (demolumpname);
+               D_DoomLoop ();  // never returns
     }
-       
-    p = M_CheckParm ("-loadgame");
-    if (p && p < myargc-1)
+
+    p = M_CheckParmWithArgs("-timedemo", 1);
+    if (p)
     {
-       if (M_CheckParm("-cdrom"))
-           sprintf(file, "c:\\doomdata\\"SAVEGAMENAME"%c.dsg",myargv[p+1][0]);
-       else
-           sprintf(file, SAVEGAMENAME"%c.dsg",myargv[p+1][0]);
-       G_LoadGame (file);
+               G_TimeDemo (demolumpname);
+               D_DoomLoop ();  // never returns
     }
-       
 
-    if ( gameaction != ga_loadgame )
+    if (startloadgame >= 0)
     {
-       if (autostart || netgame)
-           G_InitNew (startskill, startepisode, startmap);
-       else
-           D_StartTitle ();                // start up intro loop
+        M_StringCopy(file, P_SaveGameFile(startloadgame), sizeof(file));
+        G_LoadGame(file);
+    }
 
+    if (gameaction != ga_loadgame )
+    {
+               if (autostart || netgame)
+                       G_InitNew (startskill, startepisode, startmap);
+               else
+                       D_StartTitle ();                // start up intro loop
     }
 
     D_DoomLoop ();  // never returns
 }
+
index 7763e13f598e58532e47b2366c527cba944062a1..0fe9547b32cd84343e442fb35b382e76a4b6182b 100644 (file)
@@ -1,56 +1,33 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     System specific interface stuff.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __D_MAIN__
 #define __D_MAIN__
 
-#include "d_event.h"
-
-#ifdef __GNUG__
-#pragma interface
-#endif
-
-
+#include "doomdef.h"
 
-#define MAXWADFILES             20
-extern char*           wadfiles[MAXWADFILES];
 
-void D_AddFile (char *file);
 
 
+// Read events from all input devices
 
-//
-// D_DoomMain()
-// Not a globally visible function, just included for source reference,
-// calls all startup code, parses command line options.
-// If not overrided by user input, calls N_AdvanceDemo.
-//
-void D_DoomMain (void);
-
-// Called by IO functions when input is detected.
-void D_PostEvent (event_t* ev);
-
+void D_ProcessEvents (void); 
        
 
 //
@@ -59,6 +36,15 @@ void D_PostEvent (event_t* ev);
 void D_PageTicker (void);
 void D_PageDrawer (void);
 void D_AdvanceDemo (void);
+void D_DoAdvanceDemo (void);
 void D_StartTitle (void);
+//
+// GLOBAL VARIABLES
+//
+
+extern  gameaction_t    gameaction;
+
 
 #endif
+
diff --git a/frosted-doom/d_mode.c b/frosted-doom/d_mode.c
new file mode 100644 (file)
index 0000000..afd84ac
--- /dev/null
@@ -0,0 +1,209 @@
+//
+// 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.
+//
+//
+// DESCRIPTION:
+//   Functions and definitions relating to the game type and operational
+//   mode.
+//
+
+#include "doomtype.h"
+#include "d_mode.h"
+
+// Valid game mode/mission combinations, with the number of
+// episodes/maps for each.
+
+static struct
+{
+    GameMission_t mission;
+    GameMode_t mode;
+    int episode;
+    int map;
+} valid_modes[] = {
+    { pack_chex, shareware,  1, 5 },
+    { doom,      shareware,  1, 9 },
+    { doom,      registered, 3, 9 },
+    { doom,      retail,     4, 9 },
+    { doom2,     commercial, 1, 32 },
+    { pack_tnt,  commercial, 1, 32 },
+    { pack_plut, commercial, 1, 32 },
+    { pack_hacx, commercial, 1, 32 },
+    { heretic,   shareware,  1, 9 },
+    { heretic,   registered, 3, 9 },
+    { heretic,   retail,     5, 9 },
+    { hexen,     commercial, 1, 60 },
+    { strife,    commercial, 1, 34 },
+};
+
+// Check that a gamemode+gamemission received over the network is valid.
+
+boolean D_ValidGameMode(GameMission_t mission, GameMode_t mode)
+{
+    int i;
+
+    for (i=0; i<arrlen(valid_modes); ++i)
+    {
+        if (valid_modes[i].mode == mode && valid_modes[i].mission == mission)
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+boolean D_ValidEpisodeMap(GameMission_t mission, GameMode_t mode,
+                          int episode, int map)
+{
+    int i;
+
+    // Hacks for Heretic secret episodes
+
+    if (mission == heretic)
+    {
+        if (mode == retail && episode == 6)
+        {
+            return map >= 1 && map <= 3;
+        }
+        else if (mode == registered && episode == 4)
+        {
+            return map == 1;
+        }
+    }
+
+    // Find the table entry for this mission/mode combination.
+
+    for (i=0; i<arrlen(valid_modes); ++i) 
+    {
+        if (mission == valid_modes[i].mission
+         && mode == valid_modes[i].mode)
+        {
+            return episode >= 1 && episode <= valid_modes[i].episode
+                && map >= 1 && map <= valid_modes[i].map;
+        }
+    }
+
+    // Unknown mode/mission combination
+
+    return false;
+}
+
+// Get the number of valid episodes for the specified mission/mode.
+
+int D_GetNumEpisodes(GameMission_t mission, GameMode_t mode)
+{
+    int episode;
+
+    episode = 1;
+
+    while (D_ValidEpisodeMap(mission, mode, episode, 1))
+    {
+        ++episode;
+    }
+
+    return episode - 1;
+}
+
+// Table of valid versions
+
+static struct {
+    GameMission_t mission;
+    GameVersion_t version;
+} valid_versions[] = {
+    { doom,     exe_doom_1_9 },
+    { doom,     exe_hacx },
+    { doom,     exe_ultimate },
+    { doom,     exe_final },
+    { doom,     exe_final2 },
+    { doom,     exe_chex },
+    { heretic,  exe_heretic_1_3 },
+    { hexen,    exe_hexen_1_1 },
+    { strife,   exe_strife_1_2 },
+    { strife,   exe_strife_1_31 },
+};
+
+boolean D_ValidGameVersion(GameMission_t mission, GameVersion_t version)
+{
+    int i;
+
+    // All Doom variants can use the Doom versions.
+
+    if (mission == doom2 || mission == pack_plut || mission == pack_tnt
+     || mission == pack_hacx || mission == pack_chex)
+    {
+        mission = doom;
+    }
+
+    for (i=0; i<arrlen(valid_versions); ++i) 
+    {
+        if (valid_versions[i].mission == mission 
+         && valid_versions[i].version == version)
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+// Does this mission type use ExMy form, rather than MAPxy form?
+
+boolean D_IsEpisodeMap(GameMission_t mission)
+{
+    switch (mission)
+    {
+        case doom:
+        case heretic:
+        case pack_chex:
+            return true;
+
+        case none:
+        case hexen:
+        case doom2:
+        case pack_hacx:
+        case pack_tnt:
+        case pack_plut:
+        case strife:
+        default:
+            return false;
+    }
+}
+
+char *D_GameMissionString(GameMission_t mission)
+{
+    switch (mission)
+    {
+        case none:
+        default:
+            return "none";
+        case doom:
+            return "doom";
+        case doom2:
+            return "doom2";
+        case pack_tnt:
+            return "tnt";
+        case pack_plut:
+            return "plutonia";
+        case pack_hacx:
+            return "hacx";
+        case pack_chex:
+            return "chex";
+        case heretic:
+            return "heretic";
+        case hexen:
+            return "hexen";
+        case strife:
+            return "strife";
+    }
+}
+
diff --git a/frosted-doom/d_mode.h b/frosted-doom/d_mode.h
new file mode 100644 (file)
index 0000000..ebbd0e8
--- /dev/null
@@ -0,0 +1,98 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//   Functions and definitions relating to the game type and operational
+//   mode.
+//
+
+#ifndef __D_MODE__
+#define __D_MODE__
+
+#include "doomtype.h"
+
+// The "mission" controls what game we are playing.
+
+typedef enum
+{
+    doom,            // Doom 1
+    doom2,           // Doom 2
+    pack_tnt,        // Final Doom: TNT: Evilution
+    pack_plut,       // Final Doom: The Plutonia Experiment
+    pack_chex,       // Chex Quest (modded doom)
+    pack_hacx,       // Hacx (modded doom2)
+    heretic,         // Heretic
+    hexen,           // Hexen
+    strife,          // Strife
+
+    none
+} GameMission_t;
+
+// The "mode" allows more accurate specification of the game mode we are
+// in: eg. shareware vs. registered.  So doom1.wad and doom.wad are the
+// same mission, but a different mode.
+
+typedef enum
+{
+    shareware,       // Doom/Heretic shareware
+    registered,      // Doom/Heretic registered
+    commercial,      // Doom II/Hexen
+    retail,          // Ultimate Doom
+    indetermined     // Unknown.
+} GameMode_t;
+
+// What version are we emulating?
+
+typedef enum
+{
+    exe_doom_1_2,    // Doom 1.2: shareware and registered
+    exe_doom_1_666,  // Doom 1.666: for shareware, registered and commercial
+    exe_doom_1_7,    // Doom 1.7/1.7a: "
+    exe_doom_1_8,    // Doom 1.8: "
+    exe_doom_1_9,    // Doom 1.9: "
+    exe_hacx,        // Hacx
+    exe_ultimate,    // Ultimate Doom (retail)
+    exe_final,       // Final Doom
+    exe_final2,      // Final Doom (alternate exe)
+    exe_chex,        // Chex Quest executable (based on Final Doom)
+
+    exe_heretic_1_3, // Heretic 1.3
+
+    exe_hexen_1_1,   // Hexen 1.1
+    exe_strife_1_2,  // Strife v1.2
+    exe_strife_1_31  // Strife v1.31
+} GameVersion_t;
+
+// Skill level.
+
+typedef enum
+{
+    sk_noitems = -1,        // the "-skill 0" hack
+    sk_baby = 0,
+    sk_easy,
+    sk_medium,
+    sk_hard,
+    sk_nightmare
+} skill_t;
+
+boolean D_ValidGameMode(GameMission_t mission, GameMode_t mode);
+boolean D_ValidGameVersion(GameMission_t mission, GameVersion_t version);
+boolean D_ValidEpisodeMap(GameMission_t mission, GameMode_t mode,
+                          int episode, int map);
+int D_GetNumEpisodes(GameMission_t mission, GameMode_t mode);
+boolean D_IsEpisodeMap(GameMission_t mission);
+char *D_GameMissionString(GameMission_t mission);
+
+#endif /* #ifndef __D_MODE__ */
+
index 5853d5100aa096044d6388efa5e98ac7e9992acd..b8962cc6a317dc00133b4992f3b6b69dea0d136e 100644 (file)
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     DOOM Network game communication and protocol,
 //     all OS independend parts.
 //
-//-----------------------------------------------------------------------------
 
+#include <stdlib.h>
 
-static const char rcsid[] = "$Id: d_net.c,v 1.3 1997/02/03 22:01:47 b1 Exp $";
-
+#include "doomfeatures.h"
 
+#include "d_main.h"
+#include "m_argv.h"
 #include "m_menu.h"
+#include "m_misc.h"
 #include "i_system.h"
+#include "i_timer.h"
 #include "i_video.h"
-#include "i_net.h"
 #include "g_game.h"
 #include "doomdef.h"
 #include "doomstat.h"
+#include "w_checksum.h"
+#include "w_wad.h"
 
-#define        NCMD_EXIT               0x80000000
-#define        NCMD_RETRANSMIT         0x40000000
-#define        NCMD_SETUP              0x20000000
-#define        NCMD_KILL               0x10000000      // kill game
-#define        NCMD_CHECKSUM           0x0fffffff
+#include "deh_main.h"
 
-doomcom_t*     doomcom;        
-doomdata_t*    netbuffer;              // points inside doomcom
+#include "d_loop.h"
 
+ticcmd_t *netcmds;
 
-//
-// NETWORKING
-//
-// gametic is the tic about to (or currently being) run
-// maketic is the tick that hasn't had control made for it yet
-// nettics[] has the maketics for all players 
-//
-// a gametic cannot be run until nettics[] > gametic for all players
-//
-#define        RESENDCOUNT     10
-#define        PL_DRONE        0x80    // bit flag in doomdata->player
+// Called when a player leaves the game
 
-ticcmd_t       localcmds[BACKUPTICS];
-
-ticcmd_t        netcmds[MAXPLAYERS][BACKUPTICS];
-int            nettics[MAXNETNODES];
-boolean                nodeingame[MAXNETNODES];                // set false as nodes leave game
-boolean                remoteresend[MAXNETNODES];              // set when local needs tics
-int            resendto[MAXNETNODES];                  // set when remote needs tics
-int            resendcount[MAXNETNODES];
+static void PlayerQuitGame(player_t *player)
+{
+    static char exitmsg[80];
+    unsigned int player_num;
 
-int            nodeforplayer[MAXPLAYERS];
+    player_num = player - players;
 
-int             maketic;
-int            lastnettic;
-int            skiptics;
-int            ticdup;         
-int            maxsend;        // BACKUPTICS/(2*ticdup)-1
+    // Do this the same way as Vanilla Doom does, to allow dehacked
+    // replacements of this message
 
+    M_StringCopy(exitmsg, DEH_String("Player 1 left the game"),
+                 sizeof(exitmsg));
 
-void D_ProcessEvents (void); 
-void G_BuildTiccmd (ticcmd_t *cmd); 
-void D_DoAdvanceDemo (void);
-boolean                reboundpacket;
-doomdata_t     reboundstore;
+    exitmsg[7] += player_num;
 
+    playeringame[player_num] = false;
+    players[consoleplayer].message = exitmsg;
 
+    // TODO: check if it is sensible to do this:
 
-//
-//
-//
-int NetbufferSize (void)
-{
-    return (int)&(((doomdata_t *)0)->cmds[netbuffer->numtics]); 
+    if (demorecording) 
+    {
+        G_CheckDemoStatus ();
+    }
 }
 
-//
-// Checksum 
-//
-unsigned NetbufferChecksum (void)
+static void RunTic(ticcmd_t *cmds, boolean *ingame)
 {
-    unsigned           c;
-    int                i,l;
+    extern boolean advancedemo;
+    unsigned int i;
 
-    c = 0x1234567;
+    // Check for player quits.
 
-    // FIXME -endianess?
-#ifdef NORMALUNIX
-    return 0;                  // byte order problems
-#endif
+    for (i = 0; i < MAXPLAYERS; ++i)
+    {
+        if (!demoplayback && playeringame[i] && !ingame[i])
+        {
+            PlayerQuitGame(&players[i]);
+        }
+    }
 
-    l = (NetbufferSize () - (int)&(((doomdata_t *)0)->retransmitfrom))/4;
-    for (i=0 ; i<l ; i++)
-       c += ((unsigned *)&netbuffer->retransmitfrom)[i] * (i+1);
+    netcmds = cmds;
 
-    return c & NCMD_CHECKSUM;
-}
+    // check that there are players in the game.  if not, we cannot
+    // run a tic.
 
-//
-//
-//
-int ExpandTics (int low)
-{
-    int        delta;
-       
-    delta = low - (maketic&0xff);
-       
-    if (delta >= -64 && delta <= 64)
-       return (maketic&~0xff) + low;
-    if (delta > 64)
-       return (maketic&~0xff) - 256 + low;
-    if (delta < -64)
-       return (maketic&~0xff) + 256 + low;
-               
-    I_Error ("ExpandTics: strange value %i at maketic %i",low,maketic);
-    return 0;
+    if (advancedemo)
+        D_DoAdvanceDemo ();
+
+    G_Ticker ();
 }
 
+static loop_interface_t doom_loop_interface = {
+    D_ProcessEvents,
+    G_BuildTiccmd,
+    RunTic,
+    M_Ticker
+};
 
 
-//
-// HSendPacket
-//
-void
-HSendPacket
- (int  node,
-  int  flags )
-{
-    netbuffer->checksum = NetbufferChecksum () | flags;
+// Load game settings from the specified structure and
+// set global variables.
 
-    if (!node)
+static void LoadGameSettings(net_gamesettings_t *settings)
+{
+    unsigned int i;
+
+    deathmatch = settings->deathmatch;
+    startepisode = settings->episode;
+    startmap = settings->map;
+    startskill = settings->skill;
+    startloadgame = settings->loadgame;
+    lowres_turn = settings->lowres_turn;
+    nomonsters = settings->nomonsters;
+    fastparm = settings->fast_monsters;
+    respawnparm = settings->respawn_monsters;
+    timelimit = settings->timelimit;
+    consoleplayer = settings->consoleplayer;
+
+    if (lowres_turn)
     {
-       reboundstore = *netbuffer;
-       reboundpacket = true;
-       return;
+        printf("NOTE: Turning resolution is reduced; this is probably "
+               "because there is a client recording a Vanilla demo.\n");
     }
 
-    if (demoplayback)
-       return;
-
-    if (!netgame)
-       I_Error ("Tried to transmit to another node");
-               
-    doomcom->command = CMD_SEND;
-    doomcom->remotenode = node;
-    doomcom->datalength = NetbufferSize ();
-       
-    if (debugfile)
+    for (i = 0; i < MAXPLAYERS; ++i)
     {
-       int             i;
-       int             realretrans;
-       if (netbuffer->checksum & NCMD_RETRANSMIT)
-           realretrans = ExpandTics (netbuffer->retransmitfrom);
-       else
-           realretrans = -1;
-
-       fprintf (debugfile,"send (%i + %i, R %i) [%i] ",
-                ExpandTics(netbuffer->starttic),
-                netbuffer->numtics, realretrans, doomcom->datalength);
-       
-       for (i=0 ; i<doomcom->datalength ; i++)
-           fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
-
-       fprintf (debugfile,"\n");
+        playeringame[i] = i < settings->num_players;
     }
-
-    I_NetCmd ();
 }
 
-//
-// HGetPacket
-// Returns false if no packet is waiting
-//
-boolean HGetPacket (void)
-{      
-    if (reboundpacket)
-    {
-       *netbuffer = reboundstore;
-       doomcom->remotenode = 0;
-       reboundpacket = false;
-       return true;
-    }
+// Save the game settings from global variables to the specified
+// game settings structure.
+
+static void SaveGameSettings(net_gamesettings_t *settings)
+{
+    // Fill in game settings structure with appropriate parameters
+    // for the new game
+
+    settings->deathmatch = deathmatch;
+    settings->episode = startepisode;
+    settings->map = startmap;
+    settings->skill = startskill;
+    settings->loadgame = startloadgame;
+    settings->gameversion = gameversion;
+    settings->nomonsters = nomonsters;
+    settings->fast_monsters = fastparm;
+    settings->respawn_monsters = respawnparm;
+    settings->timelimit = timelimit;
+
+    settings->lowres_turn = M_CheckParm("-record") > 0
+                         && M_CheckParm("-longtics") == 0;
+}
 
-    if (!netgame)
-       return false;
+static void InitConnectData(net_connect_data_t *connect_data)
+{
+    connect_data->max_players = MAXPLAYERS;
+    connect_data->drone = false;
 
-    if (demoplayback)
-       return false;
-               
-    doomcom->command = CMD_GET;
-    I_NetCmd ();
-    
-    if (doomcom->remotenode == -1)
-       return false;
+    //!
+    // @category net
+    //
+    // Run as the left screen in three screen mode.
+    //
 
-    if (doomcom->datalength != NetbufferSize ())
+    if (M_CheckParm("-left") > 0)
     {
-       if (debugfile)
-           fprintf (debugfile,"bad packet length %i\n",doomcom->datalength);
-       return false;
-    }
-       
-    if (NetbufferChecksum () != (netbuffer->checksum&NCMD_CHECKSUM) )
-    {
-       if (debugfile)
-           fprintf (debugfile,"bad packet checksum\n");
-       return false;
+        viewangleoffset = ANG90;
+        connect_data->drone = true;
     }
 
-    if (debugfile)
+    //! 
+    // @category net
+    //
+    // Run as the right screen in three screen mode.
+    //
+
+    if (M_CheckParm("-right") > 0)
     {
-       int             realretrans;
-       int     i;
-                       
-       if (netbuffer->checksum & NCMD_SETUP)
-           fprintf (debugfile,"setup packet\n");
-       else
-       {
-           if (netbuffer->checksum & NCMD_RETRANSMIT)
-               realretrans = ExpandTics (netbuffer->retransmitfrom);
-           else
-               realretrans = -1;
-           
-           fprintf (debugfile,"get %i = (%i + %i, R %i)[%i] ",
-                    doomcom->remotenode,
-                    ExpandTics(netbuffer->starttic),
-                    netbuffer->numtics, realretrans, doomcom->datalength);
-
-           for (i=0 ; i<doomcom->datalength ; i++)
-               fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
-           fprintf (debugfile,"\n");
-       }
+        viewangleoffset = ANG270;
+        connect_data->drone = true;
     }
-    return true;       
-}
 
+    //
+    // Connect data
+    //
 
-//
-// GetPackets
-//
-char    exitmsg[80];
+    // Game type fields:
 
-void GetPackets (void)
-{
-    int                netconsole;
-    int                netnode;
-    ticcmd_t   *src, *dest;
-    int                realend;
-    int                realstart;
-                                
-    while ( HGetPacket() )
-    {
-       if (netbuffer->checksum & NCMD_SETUP)
-           continue;           // extra setup packet
-                       
-       netconsole = netbuffer->player & ~PL_DRONE;
-       netnode = doomcom->remotenode;
-       
-       // to save bytes, only the low byte of tic numbers are sent
-       // Figure out what the rest of the bytes are
-       realstart = ExpandTics (netbuffer->starttic);           
-       realend = (realstart+netbuffer->numtics);
-       
-       // check for exiting the game
-       if (netbuffer->checksum & NCMD_EXIT)
-       {
-           if (!nodeingame[netnode])
-               continue;
-           nodeingame[netnode] = false;
-           playeringame[netconsole] = false;
-           strcpy (exitmsg, "Player 1 left the game");
-           exitmsg[7] += netconsole;
-           players[consoleplayer].message = exitmsg;
-           if (demorecording)
-               G_CheckDemoStatus ();
-           continue;
-       }
-       
-       // check for a remote game kill
-       if (netbuffer->checksum & NCMD_KILL)
-           I_Error ("Killed by network driver");
-
-       nodeforplayer[netconsole] = netnode;
-       
-       // check for retransmit request
-       if ( resendcount[netnode] <= 0 
-            && (netbuffer->checksum & NCMD_RETRANSMIT) )
-       {
-           resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
-           if (debugfile)
-               fprintf (debugfile,"retransmit from %i\n", resendto[netnode]);
-           resendcount[netnode] = RESENDCOUNT;
-       }
-       else
-           resendcount[netnode]--;
-       
-       // check for out of order / duplicated packet           
-       if (realend == nettics[netnode])
-           continue;
-                       
-       if (realend < nettics[netnode])
-       {
-           if (debugfile)
-               fprintf (debugfile,
-                        "out of order packet (%i + %i)\n" ,
-                        realstart,netbuffer->numtics);
-           continue;
-       }
-       
-       // check for a missed packet
-       if (realstart > nettics[netnode])
-       {
-           // stop processing until the other system resends the missed tics
-           if (debugfile)
-               fprintf (debugfile,
-                        "missed tics from %i (%i - %i)\n",
-                        netnode, realstart, nettics[netnode]);
-           remoteresend[netnode] = true;
-           continue;
-       }
-
-       // update command store from the packet
-        {
-           int         start;
-
-           remoteresend[netnode] = false;
-               
-           start = nettics[netnode] - realstart;               
-           src = &netbuffer->cmds[start];
-
-           while (nettics[netnode] < realend)
-           {
-               dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS];
-               nettics[netnode]++;
-               *dest = *src;
-               src++;
-           }
-       }
-    }
-}
+    connect_data->gamemode = gamemode;
+    connect_data->gamemission = gamemission;
 
+    // Are we recording a demo? Possibly set lowres turn mode
 
-//
-// NetUpdate
-// Builds ticcmds for console player,
-// sends out a packet
-//
-int      gametime;
+    connect_data->lowres_turn = M_CheckParm("-record") > 0
+                             && M_CheckParm("-longtics") == 0;
 
-void NetUpdate (void)
-{
-    int             nowtime;
-    int             newtics;
-    int                                i,j;
-    int                                realstart;
-    int                                gameticdiv;
-    
-    // check time
-    nowtime = I_GetTime ()/ticdup;
-    newtics = nowtime - gametime;
-    gametime = nowtime;
-       
-    if (newtics <= 0)  // nothing new to update
-       goto listen; 
-
-    if (skiptics <= newtics)
-    {
-       newtics -= skiptics;
-       skiptics = 0;
-    }
-    else
-    {
-       skiptics -= newtics;
-       newtics = 0;
-    }
-       
-               
-    netbuffer->player = consoleplayer;
-    
-    // build new ticcmds for console player
-    gameticdiv = gametic/ticdup;
-    for (i=0 ; i<newtics ; i++)
-    {
-       I_StartTic ();
-       D_ProcessEvents ();
-       if (maketic - gameticdiv >= BACKUPTICS/2-1)
-           break;          // can't hold any more
-       
-       //printf ("mk:%i ",maketic);
-       G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]);
-       maketic++;
-    }
+    // Read checksums of our WAD directory and dehacked information
 
+    W_Checksum(connect_data->wad_sha1sum);
 
-    if (singletics)
-       return;         // singletic update is syncronous
-    
-    // send the packet to the other nodes
-    for (i=0 ; i<doomcom->numnodes ; i++)
-       if (nodeingame[i])
-       {
-           netbuffer->starttic = realstart = resendto[i];
-           netbuffer->numtics = maketic - realstart;
-           if (netbuffer->numtics > BACKUPTICS)
-               I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS");
-
-           resendto[i] = maketic - doomcom->extratics;
-
-           for (j=0 ; j< netbuffer->numtics ; j++)
-               netbuffer->cmds[j] = 
-                   localcmds[(realstart+j)%BACKUPTICS];
-                                       
-           if (remoteresend[i])
-           {
-               netbuffer->retransmitfrom = nettics[i];
-               HSendPacket (i, NCMD_RETRANSMIT);
-           }
-           else
-           {
-               netbuffer->retransmitfrom = 0;
-               HSendPacket (i, 0);
-           }
-       }
-    
-    // listen for other packets
-  listen:
-    GetPackets ();
-}
+#if ORIGCODE
+    DEH_Checksum(connect_data->deh_sha1sum);
+#endif
 
+    // Are we playing with the Freedoom IWAD?
 
+    connect_data->is_freedoom = W_CheckNumForName("FREEDOOM") >= 0;
+}
 
-//
-// CheckAbort
-//
-void CheckAbort (void)
+void D_ConnectNetGame(void)
 {
-    event_t *ev;
-    int                stoptic;
-       
-    stoptic = I_GetTime () + 2; 
-    while (I_GetTime() < stoptic) 
-       I_StartTic (); 
-       
-    I_StartTic ();
-    for ( ; eventtail != eventhead 
-             ; eventtail = (eventtail+1)%(MAXEVENTS) ) 
-    { 
-       ev = &events[eventtail]; 
-       if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
-           I_Error ("Network game synchronization aborted.");
-    } 
-}
+    net_connect_data_t connect_data;
 
+    InitConnectData(&connect_data);
+    netgame = D_InitNetGame(&connect_data);
 
-//
-// D_ArbitrateNetStart
-//
-void D_ArbitrateNetStart (void)
-{
-    int                i;
-    boolean    gotinfo[MAXNETNODES];
-       
-    autostart = true;
-    memset (gotinfo,0,sizeof(gotinfo));
-       
-    if (doomcom->consoleplayer)
-    {
-       // listen for setup info from key player
-       printf ("listening for network start info...\n");
-       while (1)
-       {
-           CheckAbort ();
-           if (!HGetPacket ())
-               continue;
-           if (netbuffer->checksum & NCMD_SETUP)
-           {
-               if (netbuffer->player != VERSION)
-                   I_Error ("Different DOOM versions cannot play a net game!");
-               startskill = netbuffer->retransmitfrom & 15;
-               deathmatch = (netbuffer->retransmitfrom & 0xc0) >> 6;
-               nomonsters = (netbuffer->retransmitfrom & 0x20) > 0;
-               respawnparm = (netbuffer->retransmitfrom & 0x10) > 0;
-               startmap = netbuffer->starttic & 0x3f;
-               startepisode = netbuffer->starttic >> 6;
-               return;
-           }
-       }
-    }
-    else
-    {
-       // key player, send the setup info
-       printf ("sending network start info...\n");
-       do
-       {
-           CheckAbort ();
-           for (i=0 ; i<doomcom->numnodes ; i++)
-           {
-               netbuffer->retransmitfrom = startskill;
-               if (deathmatch)
-                   netbuffer->retransmitfrom |= (deathmatch<<6);
-               if (nomonsters)
-                   netbuffer->retransmitfrom |= 0x20;
-               if (respawnparm)
-                   netbuffer->retransmitfrom |= 0x10;
-               netbuffer->starttic = startepisode * 64 + startmap;
-               netbuffer->player = VERSION;
-               netbuffer->numtics = 0;
-               HSendPacket (i, NCMD_SETUP);
-           }
-
-#if 1
-           for(i = 10 ; i  &&  HGetPacket(); --i)
-           {
-               if((netbuffer->player&0x7f) < MAXNETNODES)
-                   gotinfo[netbuffer->player&0x7f] = true;
-           }
-#else
-           while (HGetPacket ())
-           {
-               gotinfo[netbuffer->player&0x7f] = true;
-           }
-#endif
+    //!
+    // @category net
+    //
+    // Start the game playing as though in a netgame with a single
+    // player.  This can also be used to play back single player netgame
+    // demos.
+    //
 
-           for (i=1 ; i<doomcom->numnodes ; i++)
-               if (!gotinfo[i])
-                   break;
-       } while (i < doomcom->numnodes);
+    if (M_CheckParm("-solo-net") > 0)
+    {
+        netgame = true;
     }
 }
 
@@ -550,218 +237,45 @@ void D_ArbitrateNetStart (void)
 // D_CheckNetGame
 // Works out player numbers among the net participants
 //
-extern int                     viewangleoffset;
-
 void D_CheckNetGame (void)
 {
-    int             i;
-       
-    for (i=0 ; i<MAXNETNODES ; i++)
-    {
-       nodeingame[i] = false;
-               nettics[i] = 0;
-       remoteresend[i] = false;        // set when local needs tics
-       resendto[i] = 0;                // which tic to start sending
-    }
-       
-    // I_InitNetwork sets doomcom and netgame
-    I_InitNetwork ();
-    if (doomcom->id != DOOMCOM_ID)
-       I_Error ("Doomcom buffer invalid!");
-    
-    netbuffer = &doomcom->data;
-    consoleplayer = displayplayer = doomcom->consoleplayer;
-    if (netgame)
-       D_ArbitrateNetStart ();
-
-    printf ("startskill %i  deathmatch: %i  startmap: %i  startepisode: %i\n",
-           startskill, deathmatch, startmap, startepisode);
-       
-    // read values out of doomcom
-    ticdup = doomcom->ticdup;
-    maxsend = BACKUPTICS/(2*ticdup)-1;
-    if (maxsend<1)
-       maxsend = 1;
-                       
-    for (i=0 ; i<doomcom->numplayers ; i++)
-       playeringame[i] = true;
-    for (i=0 ; i<doomcom->numnodes ; i++)
-       nodeingame[i] = true;
-       
-    printf ("player %i of %i (%i nodes)\n",
-           consoleplayer+1, doomcom->numplayers, doomcom->numnodes);
-
-}
+    net_gamesettings_t settings;
 
-
-//
-// D_QuitNetGame
-// Called before quitting to leave a net game
-// without hanging the other players
-//
-void D_QuitNetGame (void)
-{
-    int             i, j;
-       
-    if (debugfile)
-       fclose (debugfile);
-               
-    if (!netgame || !usergame || consoleplayer == -1 || demoplayback)
-       return;
-       
-    // send a bunch of packets for security
-    netbuffer->player = consoleplayer;
-    netbuffer->numtics = 0;
-    for (i=0 ; i<4 ; i++)
+    if (netgame)
     {
-       for (j=1 ; j<doomcom->numnodes ; j++)
-           if (nodeingame[j])
-               HSendPacket (j, NCMD_EXIT);
-       I_WaitVBL (1);
+        autostart = true;
     }
-}
 
+    D_RegisterLoopCallbacks(&doom_loop_interface);
 
+    SaveGameSettings(&settings);
+    D_StartNetGame(&settings, NULL);
+    LoadGameSettings(&settings);
 
-//
-// TryRunTics
-//
-int    frametics[4];
-int    frameon;
-int    frameskip[4];
-int    oldnettics;
+    DEH_printf("startskill %i  deathmatch: %i  startmap: %i  startepisode: %i\n",
+               startskill, deathmatch, startmap, startepisode);
 
-extern boolean advancedemo;
+    DEH_printf("player %i of %i (%i nodes)\n",
+               consoleplayer+1, settings.num_players, settings.num_players);
 
-void TryRunTics (void)
-{
-    int                i;
-    int                lowtic;
-    int                entertic;
-    static int oldentertics;
-    int                realtics;
-    int                availabletics;
-    int                counts;
-    int                numplaying;
-    
-    // get real tics           
-    entertic = I_GetTime ()/ticdup;
-    realtics = entertic - oldentertics;
-    oldentertics = entertic;
-    
-    // get available tics
-    NetUpdate ();
-       
-    lowtic = MAXINT;
-    numplaying = 0;
-    for (i=0 ; i<doomcom->numnodes ; i++)
-    {
-       if (nodeingame[i])
-       {
-           numplaying++;
-           if (nettics[i] < lowtic)
-               lowtic = nettics[i];
-       }
-    }
-    availabletics = lowtic - gametic/ticdup;
-    
-    // decide how many tics to run
-    if (realtics < availabletics-1)
-       counts = realtics+1;
-    else if (realtics < availabletics)
-       counts = realtics;
-    else
-       counts = availabletics;
-    
-    if (counts < 1)
-       counts = 1;
-               
-    frameon++;
-
-    if (debugfile)
-       fprintf (debugfile,
-                "=======real: %i  avail: %i  game: %i\n",
-                realtics, availabletics,counts);
-
-    if (!demoplayback)
-    {  
-       // ideally nettics[0] should be 1 - 3 tics above lowtic
-       // if we are consistantly slower, speed up time
-       for (i=0 ; i<MAXPLAYERS ; i++)
-           if (playeringame[i])
-               break;
-       if (consoleplayer == i)
-       {
-           // the key player does not adapt
-       }
-       else
-       {
-           if (nettics[0] <= nettics[nodeforplayer[i]])
-           {
-               gametime--;
-               // printf ("-");
-           }
-           frameskip[frameon&3] = (oldnettics > nettics[nodeforplayer[i]]);
-           oldnettics = nettics[0];
-           if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
-           {
-               skiptics = 1;
-               // printf ("+");
-           }
-       }
-    }// demoplayback
-       
-    // wait for new tics if needed
-    while (lowtic < gametic/ticdup + counts)   
-    {
-       NetUpdate ();   
-       lowtic = MAXINT;
-       
-       for (i=0 ; i<doomcom->numnodes ; i++)
-           if (nodeingame[i] && nettics[i] < lowtic)
-               lowtic = nettics[i];
-       
-       if (lowtic < gametic/ticdup)
-           I_Error ("TryRunTics: lowtic < gametic");
-                               
-       // don't stay in here forever -- give the menu a chance to work
-       if (I_GetTime ()/ticdup - entertic >= 20)
-       {
-           M_Ticker ();
-           return;
-       } 
-    }
-    
-    // run the count * ticdup dics
-    while (counts--)
+    // Show players here; the server might have specified a time limit
+
+    if (timelimit > 0 && deathmatch)
     {
-       for (i=0 ; i<ticdup ; i++)
-       {
-           if (gametic/ticdup > lowtic)
-               I_Error ("gametic>lowtic");
-           if (advancedemo)
-               D_DoAdvanceDemo ();
-           M_Ticker ();
-           G_Ticker ();
-           gametic++;
-           
-           // modify command for duplicated tics
-           if (i != ticdup-1)
-           {
-               ticcmd_t        *cmd;
-               int                     buf;
-               int                     j;
-                               
-               buf = (gametic/ticdup)%BACKUPTICS; 
-               for (j=0 ; j<MAXPLAYERS ; j++)
-               {
-                   cmd = &netcmds[j][buf];
-                   cmd->chatchar = 0;
-                   if (cmd->buttons & BT_SPECIAL)
-                       cmd->buttons = 0;
-               }
-           }
-       }
-       NetUpdate ();   // check for new console commands
+        // Gross hack to work like Vanilla:
+
+        if (timelimit == 20 && M_CheckParm("-avg"))
+        {
+            DEH_printf("Austin Virtual Gaming: Levels will end "
+                           "after 20 minutes\n");
+        }
+        else
+        {
+            DEH_printf("Levels will end after %d minute", timelimit);
+            if (timelimit > 1)
+                printf("s");
+            printf(".\n");
+        }
     }
 }
+
diff --git a/frosted-doom/d_net.h b/frosted-doom/d_net.h
deleted file mode 100644 (file)
index b277472..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
-//
-// $Id:$
-//
-// Copyright (C) 1993-1996 by id Software, Inc.
-//
-// This source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// DESCRIPTION:
-//     Networking stuff.
-//
-//-----------------------------------------------------------------------------
-
-
-#ifndef __D_NET__
-#define __D_NET__
-
-#include "d_player.h"
-
-
-#ifdef __GNUG__
-#pragma interface
-#endif
-
-
-//
-// Network play related stuff.
-// There is a data struct that stores network
-//  communication related stuff, and another
-//  one that defines the actual packets to
-//  be transmitted.
-//
-
-#define DOOMCOM_ID             0x12345678l
-
-// Max computers/players in a game.
-#define MAXNETNODES            8
-
-
-// Networking and tick handling related.
-#define BACKUPTICS             12
-
-typedef enum
-{
-    CMD_SEND   = 1,
-    CMD_GET    = 2
-
-} command_t;
-
-
-//
-// Network packet data.
-//
-typedef struct
-{
-    // High bit is retransmit request.
-    unsigned           checksum;
-    // Only valid if NCMD_RETRANSMIT.
-    byte               retransmitfrom;
-    
-    byte               starttic;
-    byte               player;
-    byte               numtics;
-    ticcmd_t           cmds[BACKUPTICS];
-
-} doomdata_t;
-
-
-
-
-typedef struct
-{
-    // Supposed to be DOOMCOM_ID?
-    long               id;
-    
-    // DOOM executes an int to execute commands.
-    short              intnum;         
-    // Communication between DOOM and the driver.
-    // Is CMD_SEND or CMD_GET.
-    short              command;
-    // Is dest for send, set by get (-1 = no packet).
-    short              remotenode;
-    
-    // Number of bytes in doomdata to be sent
-    short              datalength;
-
-    // Info common to all nodes.
-    // Console is allways node 0.
-    short              numnodes;
-    // Flag: 1 = no duplication, 2-5 = dup for slow nets.
-    short              ticdup;
-    // Flag: 1 = send a backup tic in every packet.
-    short              extratics;
-    // Flag: 1 = deathmatch.
-    short              deathmatch;
-    // Flag: -1 = new game, 0-5 = load savegame
-    short              savegame;
-    short              episode;        // 1-3
-    short              map;            // 1-9
-    short              skill;          // 1-5
-
-    // Info specific to this node.
-    short              consoleplayer;
-    short              numplayers;
-    
-    // These are related to the 3-display mode,
-    //  in which two drones looking left and right
-    //  were used to render two additional views
-    //  on two additional computers.
-    // Probably not operational anymore.
-    // 1 = left, 0 = center, -1 = right
-    short              angleoffset;
-    // 1 = drone
-    short              drone;          
-
-    // The packet data to be sent.
-    doomdata_t         data;
-    
-} doomcom_t;
-
-
-
-// Create any new ticcmds and broadcast to other players.
-void NetUpdate (void);
-
-// Broadcasts special packets to other players
-//  to notify of game exit
-void D_QuitNetGame (void);
-
-//? how many ticks to run?
-void TryRunTics (void);
-
-
-#endif
-
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-
index 0a4d88788a03938f468bc849d836347872fd5a04..a72c2f5f17558dc2946a718f8499ab3a8aabb3be 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __D_PLAYER__
@@ -40,9 +37,7 @@
 // as commands per game tick.
 #include "d_ticcmd.h"
 
-#ifdef __GNUG__
-#pragma interface
-#endif
+#include "net_defs.h"
 
 
 
@@ -212,8 +207,3 @@ typedef struct
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 3624efb2a3a4f7e44d681af88609fea02d305d17..1afe040eb04c180f4a995afafe94c293b1240379 100644 (file)
@@ -1,24 +1,21 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Typedefs related to to textures etc.,
 //      isolated here to make it easier separating modules.
 //    
-//-----------------------------------------------------------------------------
 
 
 #ifndef __D_TEXTUR__
@@ -44,8 +41,3 @@ typedef struct
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 6a581657a0b0e183b5df6ecde401e8279d470aef..0966ad96023f269e050d4177ad7a71468289df38 100644 (file)
@@ -1,34 +1,28 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //  MapObj data. Map Objects or mobjs are actors, entities,
 //  thinker, take-your-pick... anything that moves, acts, or
 //  suffers state changes of more or less violent nature.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __D_THINK__
 #define __D_THINK__
 
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 
 
@@ -44,8 +38,8 @@ typedef  void (*actionf_p2)( void*, void* );
 
 typedef union
 {
-  actionf_p1   acp1;
   actionf_v    acv;
+  actionf_p1   acp1;
   actionf_p2   acp2;
 
 } actionf_t;
@@ -72,8 +66,3 @@ typedef struct thinker_s
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 581798968e5ada9ecfe5689679c0741d5009cd07..daf0da318ba8fd938f7769224dafc3eb63faad17 100644 (file)
@@ -1,23 +1,21 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     System specific interface stuff.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __D_TICCMD__
 
 #include "doomtype.h"
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 // The data sampled per tick (single player)
 // and transmitted to other peers (multiplayer).
 // Mainly movements/button commands per game tick,
 // plus a checksum for internal state consistency.
+
 typedef struct
 {
-    char       forwardmove;    // *2048 for move
-    char       sidemove;       // *2048 for move
-    short      angleturn;      // <<16 for angle delta
-    short      consistancy;    // checks for net game
-    byte       chatchar;
-    byte       buttons;
+    signed char        forwardmove;    // *2048 for move
+    signed char        sidemove;       // *2048 for move
+    short angleturn;            // <<16 for angle delta
+    byte chatchar;
+    byte buttons;
+    // villsa [STRIFE] according to the asm,
+    // consistancy is a short, not a byte
+    byte consistancy;           // checks for net game
+
+    // villsa - Strife specific:
+
+    byte buttons2;
+    int inventory;
+   
+    // Heretic/Hexen specific:
+
+    byte lookfly;               // look/fly up/down/centering
+    byte arti;                  // artitype_t to use
 } ticcmd_t;
 
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
diff --git a/frosted-doom/deh_main.h b/frosted-doom/deh_main.h
new file mode 100644 (file)
index 0000000..10ac236
--- /dev/null
@@ -0,0 +1,48 @@
+//
+// 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.
+//
+//
+// Dehacked entrypoint and common code
+//
+
+#ifndef DEH_MAIN_H
+#define DEH_MAIN_H
+
+#include "doomtype.h"
+#include "doomfeatures.h"
+#include "deh_str.h"
+#include "sha1.h"
+
+// These are the limits that dehacked uses (from dheinit.h in the dehacked
+// source).  If these limits are exceeded, it does not generate an error, but
+// a warning is displayed.
+
+#define DEH_VANILLA_NUMSTATES 966
+#define DEH_VANILLA_NUMSFX 107
+
+void DEH_ParseCommandLine(void);
+int DEH_LoadFile(char *filename);
+int DEH_LoadLump(int lumpnum, boolean allow_long, boolean allow_error);
+int DEH_LoadLumpByName(char *name, boolean allow_long, boolean allow_error);
+
+boolean DEH_ParseAssignment(char *line, char **variable_name, char **value);
+
+void DEH_Checksum(sha1_digest_t digest);
+
+extern boolean deh_allow_extended_strings;
+extern boolean deh_allow_long_strings;
+extern boolean deh_allow_long_cheats;
+extern boolean deh_apply_cheats;
+
+#endif /* #ifndef DEH_MAIN_H */
+
diff --git a/frosted-doom/deh_misc.h b/frosted-doom/deh_misc.h
new file mode 100644 (file)
index 0000000..319a145
--- /dev/null
@@ -0,0 +1,83 @@
+//
+// 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.
+//
+//
+// Parses "Misc" sections in dehacked files
+//
+
+#ifndef DEH_MISC_H
+#define DEH_MISC_H
+
+#include "doomfeatures.h"
+
+#define DEH_DEFAULT_INITIAL_HEALTH 100
+#define DEH_DEFAULT_INITIAL_BULLETS 50
+#define DEH_DEFAULT_MAX_HEALTH 200
+#define DEH_DEFAULT_MAX_ARMOR 200
+#define DEH_DEFAULT_GREEN_ARMOR_CLASS 1
+#define DEH_DEFAULT_BLUE_ARMOR_CLASS 2
+#define DEH_DEFAULT_MAX_SOULSPHERE 200
+#define DEH_DEFAULT_SOULSPHERE_HEALTH 100
+#define DEH_DEFAULT_MEGASPHERE_HEALTH 200
+#define DEH_DEFAULT_GOD_MODE_HEALTH 100
+#define DEH_DEFAULT_IDFA_ARMOR 200
+#define DEH_DEFAULT_IDFA_ARMOR_CLASS 2
+#define DEH_DEFAULT_IDKFA_ARMOR 200
+#define DEH_DEFAULT_IDKFA_ARMOR_CLASS 2
+#define DEH_DEFAULT_BFG_CELLS_PER_SHOT 40
+#define DEH_DEFAULT_SPECIES_INFIGHTING 0
+
+#ifdef FEATURE_DEHACKED
+
+extern int deh_initial_health;             
+extern int deh_initial_bullets;            
+extern int deh_max_health;                 
+extern int deh_max_armor;                  
+extern int deh_green_armor_class;          
+extern int deh_blue_armor_class;           
+extern int deh_max_soulsphere;             
+extern int deh_soulsphere_health;          
+extern int deh_megasphere_health;          
+extern int deh_god_mode_health;            
+extern int deh_idfa_armor;                 
+extern int deh_idfa_armor_class;           
+extern int deh_idkfa_armor;                
+extern int deh_idkfa_armor_class;          
+extern int deh_bfg_cells_per_shot;         
+extern int deh_species_infighting;           
+
+#else
+
+// If dehacked is disabled, hard coded values
+
+#define deh_initial_health      DEH_DEFAULT_INITIAL_HEALTH
+#define deh_initial_bullets     DEH_DEFAULT_INITIAL_BULLETS
+#define deh_max_health          DEH_DEFAULT_MAX_HEALTH
+#define deh_max_armor           DEH_DEFAULT_MAX_ARMOR
+#define deh_green_armor_class   DEH_DEFAULT_GREEN_ARMOR_CLASS
+#define deh_blue_armor_class    DEH_DEFAULT_BLUE_ARMOR_CLASS
+#define deh_max_soulsphere      DEH_DEFAULT_MAX_SOULSPHERE
+#define deh_soulsphere_health   DEH_DEFAULT_SOULSPHERE_HEALTH
+#define deh_megasphere_health   DEH_DEFAULT_MEGASPHERE_HEALTH
+#define deh_god_mode_health     DEH_DEFAULT_GOD_MODE_HEALTH
+#define deh_idfa_armor          DEH_DEFAULT_IDFA_ARMOR
+#define deh_idfa_armor_class    DEH_DEFAULT_IDFA_ARMOR_CLASS
+#define deh_idkfa_armor         DEH_DEFAULT_IDKFA_ARMOR
+#define deh_idkfa_armor_class   DEH_DEFAULT_IDKFA_ARMOR_CLASS
+#define deh_bfg_cells_per_shot  DEH_DEFAULT_BFG_CELLS_PER_SHOT
+#define deh_species_infighting  DEH_DEFAULT_SPECIES_INFIGHTING
+
+#endif
+
+#endif /* #ifndef DEH_MISC_H */
+
diff --git a/frosted-doom/deh_str.h b/frosted-doom/deh_str.h
new file mode 100644 (file)
index 0000000..cdecaf0
--- /dev/null
@@ -0,0 +1,47 @@
+//
+// 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.
+//
+//
+// Dehacked string replacements
+//
+
+#ifndef DEH_STR_H
+#define DEH_STR_H
+
+#include <stdio.h>
+
+#include "doomfeatures.h"
+
+// Used to do dehacked text substitutions throughout the program
+
+#ifdef FEATURE_DEHACKED
+
+char *DEH_String(char *s);
+void DEH_printf(char *fmt, ...);
+void DEH_fprintf(FILE *fstream, char *fmt, ...);
+void DEH_snprintf(char *buffer, size_t len, char *fmt, ...);
+void DEH_AddStringReplacement(char *from_text, char *to_text);
+
+
+#else
+
+#define DEH_String(x) (x)
+#define DEH_printf printf
+#define DEH_fprintf fprintf
+#define DEH_snprintf snprintf
+#define DEH_AddStringReplacement(x, y)
+
+#endif
+
+#endif /* #ifndef DEH_STR_H */
+
diff --git a/frosted-doom/doom.h b/frosted-doom/doom.h
new file mode 100644 (file)
index 0000000..3c0d0be
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * doom.h
+ *
+ *  Created on: 18.02.2015
+ *      Author: Florian
+ */
+
+
+#ifndef SRC_CHOCDOOM_DOOM_H_
+#define SRC_CHOCDOOM_DOOM_H_
+
+/*---------------------------------------------------------------------*
+ *  additional includes                                                *
+ *---------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------*
+ *  global definitions                                                 *
+ *---------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------*
+ *  type declarations                                                  *
+ *---------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------*
+ *  function prototypes                                                *
+ *---------------------------------------------------------------------*/
+
+void D_DoomMain (void);
+
+/*---------------------------------------------------------------------*
+ *  global data                                                        *
+ *---------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------*
+ *  inline functions and function-like macros                          *
+ *---------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------*
+ *  eof                                                                *
+ *---------------------------------------------------------------------*/
+
+#endif /* SRC_CHOCDOOM_DOOM_H_ */
index bab5e00604dabac4b1e789c37397373d7cd9e070..46b3e11b629b94370436b197105fa8e0e3ac7116 100644 (file)
@@ -1,25 +1,22 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //  all external data is defined here
 //  most of the data is loaded into different structures at run time
 //  some internal structures shared by many modules are here
 //
-//-----------------------------------------------------------------------------
 
 #ifndef __DOOMDATA__
 #define __DOOMDATA__
@@ -61,7 +58,7 @@ typedef struct
 {
   short                x;
   short                y;
-} mapvertex_t;
+} PACKEDATTR mapvertex_t;
 
 
 // A SideDef, defining the visual appearance of a wall,
@@ -75,7 +72,7 @@ typedef struct
   char         midtexture[8];
   // Front sector, towards viewer.
   short                sector;
-} mapsidedef_t;
+} PACKEDATTR mapsidedef_t;
 
 
 
@@ -90,7 +87,7 @@ typedef struct
   short                tag;
   // sidenum[1] will be -1 if one sided
   short                sidenum[2];             
-} maplinedef_t;
+} PACKEDATTR maplinedef_t;
 
 
 //
@@ -147,7 +144,7 @@ typedef     struct
   short                lightlevel;
   short                special;
   short                tag;
-} mapsector_t;
+} PACKEDATTR mapsector_t;
 
 // SubSector, as generated by BSP.
 typedef struct
@@ -155,7 +152,7 @@ typedef struct
   short                numsegs;
   // Index of first one, segs are stored sequentially.
   short                firstseg;       
-} mapsubsector_t;
+} PACKEDATTR mapsubsector_t;
 
 
 // LineSeg, generated by splitting LineDefs
@@ -168,7 +165,7 @@ typedef struct
   short                linedef;
   short                side;
   short                offset;
-} mapseg_t;
+} PACKEDATTR mapseg_t;
 
 
 
@@ -193,7 +190,7 @@ typedef struct
   // else it's a node of another subtree.
   unsigned short       children[2];
 
-} mapnode_t;
+} PACKEDATTR mapnode_t;
 
 
 
@@ -207,16 +204,10 @@ typedef struct
     short              angle;
     short              type;
     short              options;
-} mapthing_t;
+} PACKEDATTR mapthing_t;
 
 
 
 
 
 #endif                 // __DOOMDATA__
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-
index e5fb686565dc95f25c58e8606c4ee833c041b105..d31f3efa2dd7b103fbca573f695c401170a52c00 100644 (file)
@@ -1,34 +1,24 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //  DoomDef - basic defines for DOOM, e.g. Version, game mode
 //   and skill level, and display parameters.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $";
 
 
-#ifdef __GNUG__
-#pragma implementation "doomdef.h"
-#endif
 #include "doomdef.h"
 
 // Location for any defines turned variables.
index a5a4ffa4cc9722194600579ec030902ebea634c3..62d729ddb134664a1df0b753115b48918d5e1dcc 100644 (file)
@@ -1,24 +1,21 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //  Internally used data structures for virtually everything,
-//   key definitions, lots of other stuff.
+//   lots of other stuff.
 //
-//-----------------------------------------------------------------------------
 
 #ifndef __DOOMDEF__
 #define __DOOMDEF__
 #include <stdio.h>
 #include <string.h>
 
+#include "doomtype.h"
+#include "i_timer.h"
+#include "d_mode.h"
+
 //
 // Global parameters/defines.
 //
 // DOOM version
-enum { VERSION =  110 };
-
-
-// Game mode handling - identify IWAD version
-//  to handle IWAD dependend animations etc.
-typedef enum
-{
-  shareware,   // DOOM 1 shareware, E1, M9
-  registered,  // DOOM 1 registered, E3, M27
-  commercial,  // DOOM 2 retail, E1 M34
-  // DOOM 2 german edition not handled
-  retail,      // DOOM 1 retail, E4, M36
-  indetermined // Well, no IWAD found.
-  
-} GameMode_t;
-
-
-// Mission packs - might be useful for TC stuff?
-typedef enum
-{
-  doom,                // DOOM 1
-  doom2,       // DOOM 2
-  pack_tnt,    // TNT mission pack
-  pack_plut,   // Plutonia pack
-  none
-
-} GameMission_t;
-
+#define DOOM_VERSION 109
 
-// Identify language to use, software localization.
-typedef enum
-{
-  english,
-  french,
-  german,
-  unknown
-
-} Language_t;
+// Version code for cph's longtics hack ("v1.91")
+#define DOOM_191_VERSION 111
 
 
 // If rangecheck is undefined,
 // most parameter validation debugging code will not be compiled
 #define RANGECHECK
 
-// Do or do not use external soundserver.
-// The sndserver binary to be run separately
-//  has been introduced by Dave Taylor.
-// The integrated sound support is experimental,
-//  and unfinished. Default is synchronous.
-// Experimental asynchronous timer based is
-//  handled by SNDINTR. 
-#define SNDSERV  1
-//#define SNDINTR  1
-
-
-// This one switches between MIT SHM (no proper mouse)
-// and XFree86 DGA (mickey sampling). The original
-// linuxdoom used SHM, which is default.
-//#define X11_DGA              1
-
-
-//
-// For resize of screen, at start of game.
-// It will not work dynamically, see visplanes.
-//
-#define        BASE_WIDTH              320
-//#define      BASE_WIDTH              480
-
-// It is educational but futile to change this
-//  scaling e.g. to 2. Drawing of status bar,
-//  menues etc. is tied to the scale implied
-//  by the graphics.
-#define        SCREEN_MUL              1
-#define        INV_ASPECT_RATIO        0.625 // 0.75, ideally
-//#define      INV_ASPECT_RATIO        0.567// 0.75, ideally
-
-// Defines suck. C sucks.
-// C++ might sucks for OOP, but it sure is a better C.
-// So there.
-#define SCREENWIDTH  320
-//#define SCREENWIDTH  480
-//SCREEN_MUL*BASE_WIDTH //320
-#define SCREENHEIGHT 200
-//#define SCREENHEIGHT 272
-//(int)(SCREEN_MUL*BASE_WIDTH*INV_ASPECT_RATIO) //200
-
-
-
-
 // The maximum number of players, multiplayer/networking.
-#define MAXPLAYERS             4
-
-// State updates, number of tics / second.
-#define TICRATE                35
+#define MAXPLAYERS 4
 
 // The current state of the game: whether we are
 // playing, gazing at the intermission screen,
@@ -133,9 +52,23 @@ typedef enum
     GS_LEVEL,
     GS_INTERMISSION,
     GS_FINALE,
-    GS_DEMOSCREEN
+    GS_DEMOSCREEN,
 } gamestate_t;
 
+typedef enum
+{
+    ga_nothing,
+    ga_loadlevel,
+    ga_newgame,
+    ga_loadgame,
+    ga_savegame,
+    ga_playdemo,
+    ga_completed,
+    ga_victory,
+    ga_worlddone,
+    ga_screenshot
+} gameaction_t;
+
 //
 // Difficulty/skill settings/filters.
 //
@@ -148,17 +81,6 @@ typedef enum
 // Deaf monsters/do not react to sound.
 #define        MTF_AMBUSH              8
 
-typedef enum
-{
-    sk_baby,
-    sk_easy,
-    sk_medium,
-    sk_hard,
-    sk_nightmare
-} skill_t;
-
-
-
 
 //
 // Key cards.
@@ -243,100 +165,4 @@ typedef enum
     
 } powerduration_t;
 
-
-
-
-//
-// DOOM keyboard definition.
-// This is the stuff configured by Setup.Exe.
-// Most key data are simple ascii (uppercased).
-//
-#define KEY_RIGHTARROW 0xae
-#define KEY_LEFTARROW  0xac
-#define KEY_UPARROW    0xad
-#define KEY_DOWNARROW  0xaf
-#define KEY_ESCAPE     27
-#define KEY_ENTER      13
-#define KEY_TAB                9
-#define KEY_F1         (0x80+0x3b)
-#define KEY_F2         (0x80+0x3c)
-#define KEY_F3         (0x80+0x3d)
-#define KEY_F4         (0x80+0x3e)
-#define KEY_F5         (0x80+0x3f)
-#define KEY_F6         (0x80+0x40)
-#define KEY_F7         (0x80+0x41)
-#define KEY_F8         (0x80+0x42)
-#define KEY_F9         (0x80+0x43)
-#define KEY_F10                (0x80+0x44)
-#define KEY_F11                (0x80+0x57)
-#define KEY_F12                (0x80+0x58)
-
-#define KEY_BACKSPACE  127
-#define KEY_PAUSE      0xff
-
-#define KEY_EQUALS     0x3d
-#define KEY_MINUS      0x2d
-
-#define KEY_RSHIFT     (0x80+0x36)
-#define KEY_RCTRL      (0x80+0x1d)
-#define KEY_RALT       (0x80+0x38)
-
-#define KEY_LALT       KEY_RALT
-
-
-
-// DOOM basic types (boolean),
-//  and max/min values.
-//#include "doomtype.h"
-
-// Fixed point.
-//#include "m_fixed.h"
-
-// Endianess handling.
-//#include "m_swap.h"
-
-
-// Binary Angles, sine/cosine/atan lookups.
-//#include "tables.h"
-
-// Event type.
-//#include "d_event.h"
-
-// Game function, skills.
-//#include "g_game.h"
-
-// All external data is defined here.
-//#include "doomdata.h"
-
-// All important printed strings.
-// Language selection (message strings).
-//#include "dstrings.h"
-
-// Player is a special actor.
-//struct player_s;
-
-
-//#include "d_items.h"
-//#include "d_player.h"
-//#include "p_mobj.h"
-//#include "d_net.h"
-
-// PLAY
-//#include "p_tick.h"
-
-
-
-
-// Header, generated by sound utility.
-// The utility was written by Dave Taylor.
-//#include "sounds.h"
-
-
-
-
 #endif          // __DOOMDEF__
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
diff --git a/frosted-doom/doomfeatures.h b/frosted-doom/doomfeatures.h
new file mode 100644 (file)
index 0000000..f7b15f7
--- /dev/null
@@ -0,0 +1,40 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//     List of features which can be enabled/disabled to slim down the
+//     program.
+//
+
+#ifndef DOOM_FEATURES_H
+#define DOOM_FEATURES_H
+
+// Enables wad merging (the '-merge' command line parameter)
+
+#undef FEATURE_WAD_MERGE
+
+// Enables dehacked support ('-deh')
+
+#undef FEATURE_DEHACKED
+
+// Enables multiplayer support (network games)
+
+#undef FEATURE_MULTIPLAYER
+
+// Enables sound output
+
+#undef FEATURE_SOUND
+
+#endif /* #ifndef DOOM_FEATURES_H */
+
+
diff --git a/frosted-doom/doomkeys.h b/frosted-doom/doomkeys.h
new file mode 100644 (file)
index 0000000..2dfc431
--- /dev/null
@@ -0,0 +1,97 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//       Key definitions
+//
+
+#ifndef __DOOMKEYS__
+#define __DOOMKEYS__
+
+//
+// DOOM keyboard definition.
+// This is the stuff configured by Setup.Exe.
+// Most key data are simple ascii (uppercased).
+//
+#define KEY_RIGHTARROW 0xae
+#define KEY_LEFTARROW  0xac
+#define KEY_UPARROW            0xad
+#define KEY_DOWNARROW  0xaf
+#define KEY_STRAFE_L   0xa0
+#define KEY_STRAFE_R   0xa1
+#define KEY_USE                        0xa2
+#define KEY_FIRE               0xa3
+#define KEY_ESCAPE             27
+#define KEY_ENTER              13
+#define KEY_TAB                        9
+#define KEY_F1                 (0x80+0x3b)
+#define KEY_F2                 (0x80+0x3c)
+#define KEY_F3                 (0x80+0x3d)
+#define KEY_F4                 (0x80+0x3e)
+#define KEY_F5                 (0x80+0x3f)
+#define KEY_F6                 (0x80+0x40)
+#define KEY_F7                 (0x80+0x41)
+#define KEY_F8                 (0x80+0x42)
+#define KEY_F9                 (0x80+0x43)
+#define KEY_F10                        (0x80+0x44)
+#define KEY_F11                        (0x80+0x57)
+#define KEY_F12                        (0x80+0x58)
+
+#define KEY_BACKSPACE  0x7f
+#define KEY_PAUSE      0xff
+
+#define KEY_EQUALS     0x3d
+#define KEY_MINUS      0x2d
+
+#define KEY_RSHIFT     (0x80+0x36)
+#define KEY_RCTRL      (0x80+0x1d)
+#define KEY_RALT       (0x80+0x38)
+
+#define KEY_LALT       KEY_RALT
+
+// new keys:
+
+#define KEY_CAPSLOCK    (0x80+0x3a)
+#define KEY_NUMLOCK     (0x80+0x45)
+#define KEY_SCRLCK      (0x80+0x46)
+#define KEY_PRTSCR      (0x80+0x59)
+
+#define KEY_HOME        (0x80+0x47)
+#define KEY_END         (0x80+0x4f)
+#define KEY_PGUP        (0x80+0x49)
+#define KEY_PGDN        (0x80+0x51)
+#define KEY_INS         (0x80+0x52)
+#define KEY_DEL         (0x80+0x53)
+
+#define KEYP_0          0
+#define KEYP_1          KEY_END
+#define KEYP_2          KEY_DOWNARROW
+#define KEYP_3          KEY_PGDN
+#define KEYP_4          KEY_LEFTARROW
+#define KEYP_5          '5'
+#define KEYP_6          KEY_RIGHTARROW
+#define KEYP_7          KEY_HOME
+#define KEYP_8          KEY_UPARROW
+#define KEYP_9          KEY_PGUP
+
+#define KEYP_DIVIDE     '/'
+#define KEYP_PLUS       '+'
+#define KEYP_MINUS      '-'
+#define KEYP_MULTIPLY   '*'
+#define KEYP_PERIOD     0
+#define KEYP_EQUALS     KEY_EQUALS
+#define KEYP_ENTER      KEY_ENTER
+
+#endif          // __DOOMKEYS__
+
index 8d19aceef5b00e59130455e05793c2e86162134e..ed4c6ccc32404b53c73853b8e6988edb1ea31c7e 100644 (file)
@@ -1,42 +1,31 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Put all global tate variables here.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $";
+#include <stdio.h>
 
-
-#ifdef __GNUG__
-#pragma implementation "doomstat.h"
-#endif
 #include "doomstat.h"
 
 
 // Game Mode - identify IWAD as shareware, retail etc.
 GameMode_t gamemode = indetermined;
 GameMission_t  gamemission = doom;
-
-// Language.
-Language_t   language = english;
+GameVersion_t   gameversion = exe_final2;
+char *gamedescription;
 
 // Set if homebrew PWAD stuff has been added.
 boolean        modifiedgame;
index 65f5225688574cfbba5b0a234751eb7a419b71fd..acd65dccaf80847ba24462c968d3d19754810501 100644 (file)
@@ -1,18 +1,16 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //   All the global variables that store the internal state.
@@ -22,7 +20,6 @@
 //    this header file.
 //   In practice, things are a bit messy.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __D_STATE__
 // We need globally shared data structures,
 //  for defining the global state variables.
 #include "doomdata.h"
-#include "d_net.h"
+#include "d_loop.h"
 
 // We need the playr data structure as well.
 #include "d_player.h"
 
+// Game mode/mission
+#include "d_mode.h"
 
-#ifdef __GNUG__
-#pragma interface
-#endif
+#include "net_defs.h"
 
 
 
@@ -53,20 +50,28 @@ extern  boolean     fastparm;       // checkparm of -fast
 extern  boolean        devparm;        // DEBUG: launched with -devparm
 
 
-
 // -----------------------------------------------------
 // Game Mode - identify IWAD as shareware, retail etc.
 //
 extern GameMode_t      gamemode;
 extern GameMission_t   gamemission;
+extern GameVersion_t    gameversion;
+extern char            *gamedescription;
 
-// Set if homebrew PWAD stuff has been added.
-extern  boolean        modifiedgame;
+// If true, we're using one of the mangled BFG edition IWADs.
+extern boolean bfgedition;
 
+// Convenience macro.
+// 'gamemission' can be equal to pack_chex or pack_hacx, but these are
+// just modified versions of doom and doom2, and should be interpreted
+// as the same most of the time.
 
-// -------------------------------------------
-// Language.
-extern  Language_t   language;
+#define logical_gamemission                             \
+    (gamemission == pack_chex ? doom :                  \
+     gamemission == pack_hacx ? doom2 : gamemission)
+
+// Set if homebrew PWAD stuff has been added.
+extern  boolean        modifiedgame;
 
 
 // -------------------------------------------
@@ -78,6 +83,11 @@ extern  skill_t              startskill;
 extern  int             startepisode;
 extern int             startmap;
 
+// Savegame slot to load on startup.  This is the value provided to
+// the -loadgame option.  If this has not been provided, this is -1.
+
+extern  int             startloadgame;
+
 extern  boolean                autostart;
 
 // Selected by user. 
@@ -85,29 +95,30 @@ extern  skill_t         gameskill;
 extern  int            gameepisode;
 extern  int            gamemap;
 
+// If non-zero, exit the level after this number of minutes
+extern  int             timelimit;
+
 // Nightmare mode flag, single player.
 extern  boolean         respawnmonsters;
 
 // Netgame? Only true if >1 player.
 extern  boolean        netgame;
 
-// Flag: true only if started as net deathmatch.
-// An enum might handle altdeath/cooperative better.
-extern  boolean        deathmatch;     
-       
+// 0=Cooperative; 1=Deathmatch; 2=Altdeath
+extern int deathmatch;
+
 // -------------------------
 // Internal parameters for sound rendering.
 // These have been taken from the DOS version,
 //  but are not (yet) supported with Linux
 //  (e.g. no sound volume adjustment with menu.
 
-// These are not used, but should be (menu).
 // From m_menu.c:
 //  Sound FX volume has default, 0 - 15
 //  Music volume has default, 0 - 15
 // These are multiplied by 8.
-extern int snd_SfxVolume;      // maximum volume for sound
-extern int snd_MusicVolume;    // maximum volume for music
+extern int sfxVolume;
+extern int musicVolume;
 
 // Current music/sfx card - index useless
 //  w/o a reference LUT in a sound module.
@@ -137,15 +148,10 @@ extern  boolean   paused;         // Game Pause?
 extern  boolean                viewactive;
 
 extern  boolean                nodrawers;
-extern  boolean                noblit;
-
-extern int             viewwindowx;
-extern int             viewwindowy;
-extern int             viewheight;
-extern int             viewwidth;
-extern int             scaledviewwidth;
 
 
+extern  boolean         testcontrols;
+extern  int             testcontrols_mousespeed;
 
 
 
@@ -183,6 +189,11 @@ extern  boolean    usergame;
 extern  boolean        demoplayback;
 extern  boolean        demorecording;
 
+// Round angleturn in ticcmds to the nearest 256.  This is used when
+// recording Vanilla demos in netgames.
+
+extern boolean lowres_turn;
+
 // Quit after playing a demo from cmdline.
 extern  boolean                singledemo;     
 
@@ -205,9 +216,6 @@ extern  gamestate_t     gamestate;
 
 
 
-extern int             gametic;
-
-
 // Bookkeeping on players - state.
 extern player_t        players[MAXPLAYERS];
 
@@ -228,9 +236,6 @@ extern  mapthing_t      playerstarts[MAXPLAYERS];
 extern  wbstartstruct_t                wminfo; 
 
 
-// LUT of ammunition limits for each kind.
-// This doubles with BackPack powerup item.
-extern  int            maxammo[NUMAMMO];
 
 
 
@@ -241,8 +246,8 @@ extern  int         maxammo[NUMAMMO];
 //
 
 // File handling stuff.
+extern  char *          savegamedir;
 extern char            basedefault[1024];
-extern  FILE*          debugfile;
 
 // if true, load all graphics at level load
 extern  boolean         precache;
@@ -253,9 +258,6 @@ extern  boolean         precache;
 extern  gamestate_t     wipegamestate;
 
 extern  int             mouseSensitivity;
-//?
-// debug flag to cancel adaptiveness
-extern  boolean         singletics;    
 
 extern  int             bodyqueslot;
 
@@ -270,27 +272,10 @@ extern int                skyflatnum;
 
 // Netgame stuff (buffers and pointers, i.e. indices).
 
-// This is ???
-extern  doomcom_t*     doomcom;
 
-// This points inside doomcom.
-extern  doomdata_t*    netbuffer;      
-
-
-extern  ticcmd_t       localcmds[BACKUPTICS];
 extern int             rndindex;
 
-extern int             maketic;
-extern  int             nettics[MAXNETNODES];
-
-extern  ticcmd_t        netcmds[MAXPLAYERS][BACKUPTICS];
-extern int             ticdup;
-
+extern  ticcmd_t       *netcmds;
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index e89a7a6d23a9b95ebd62aa6b79798e8f229dcbfa..b5298ebaec74541090275c022a194a93649c80ad 100644 (file)
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Simple basic typedefs, isolated here to make it easier
 //      separating modules.
 //    
-//-----------------------------------------------------------------------------
 
 
 #ifndef __DOOMTYPE__
 #define __DOOMTYPE__
 
+// #define macros to provide functions missing in Windows.
+// Outside Windows, we use strings.h for str[n]casecmp.
+
+
+#ifdef _WIN32
+
+#define strcasecmp stricmp
+#define strncasecmp strnicmp
 
-#ifndef __BYTEBOOL__
-#define __BYTEBOOL__
-// Fixed to use builtin bool type with C++.
-#ifdef __cplusplus
-typedef bool boolean;
 #else
-typedef enum {false, true} boolean;
+
+#include <strings.h>
+
 #endif
-typedef unsigned char byte;
+
+
+//
+// The packed attribute forces structures to be packed into the minimum 
+// space necessary.  If this is not done, the compiler may align structure
+// fields differently to optimize memory access, inflating the overall
+// structure size.  It is important to use the packed attribute on certain
+// structures where alignment is important, particularly data read/written
+// to disk.
+//
+
+#ifdef __GNUC__
+#define PACKEDATTR __attribute__((packed))
+#else
+#define PACKEDATTR
 #endif
 
+// C99 integer types; with gcc we just use this.  Other compilers 
+// should add conditional statements that define the C99 types.
+
+// What is really wanted here is stdint.h; however, some old versions
+// of Solaris don't have stdint.h and only have inttypes.h (the 
+// pre-standardisation version).  inttypes.h is also in the C99 
+// standard and defined to include stdint.h, so include this. 
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+
+// Use builtin bool type with C++.
+
+typedef bool boolean;
 
-// Predefined with some OS.
-#ifdef LINUX
-#include <values.h>
 #else
-#define MAXCHAR                ((char)0x7f)
-#define MAXSHORT       ((short)0x7fff)
-
-// Max pos 32-bit int.
-#define MAXINT         ((int)0x7fffffff)       
-#define MAXLONG                ((long)0x7fffffff)
-#define MINCHAR                ((char)0x80)
-#define MINSHORT       ((short)0x8000)
-
-// Max negative 32-bit integer.
-#define MININT         ((int)0x80000000)       
-#define MINLONG                ((long)0x80000000)
+
+typedef enum 
+{
+    false      = 0,
+    true       = 1,
+       undef   = 0xFFFFFFFF
+} boolean;
+
 #endif
 
+typedef uint8_t byte;
+
+#include <limits.h>
+
+#ifdef _WIN32
 
+#define DIR_SEPARATOR '\\'
+#define DIR_SEPARATOR_S "\\"
+#define PATH_SEPARATOR ';'
 
+#else
+
+#define DIR_SEPARATOR '/'
+#define DIR_SEPARATOR_S "/"
+#define PATH_SEPARATOR ':'
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
+
+#define arrlen(array) (sizeof(array) / sizeof(*array))
+
+#endif
+
index e6abe88df9b490fdd6e7588b90d81e14ab2038b9..b87f198b34a3d94d80ac3b704c251457a666da31 100644 (file)
@@ -1,58 +1,58 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Globally defined strings.
 // 
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $";
 
 
-#ifdef __GNUG__
-#pragma implementation "dstrings.h"
-#endif
 #include "dstrings.h"
 
-
-
-char* endmsg[NUM_QUITMESSAGES+1]=
+char *doom1_endmsg[] =
 {
-  // DOOM1
-  QUITMSG,
+  "are you sure you want to\nquit this great game?",
   "please don't leave, there's more\ndemons to toast!",
   "let's beat it -- this is turning\ninto a bloodbath!",
   "i wouldn't leave if i were you.\ndos is much worse.",
   "you're trying to say you like dos\nbetter than me, right?",
   "don't leave yet -- there's a\ndemon around that corner!",
   "ya know, next time you come in here\ni'm gonna toast ya.",
-  "go ahead and leave. see if i care."
+  "go ahead and leave. see if i care.",
+};
 
+char *doom2_endmsg[] =
+{
   // QuitDOOM II messages
+  "are you sure you want to\nquit this great game?",
   "you want to quit?\nthen, thou hast lost an eighth!",
   "don't go now, there's a \ndimensional shambler waiting\nat the dos prompt!",
   "get outta here and go back\nto your boring programs.",
   "if i were your boss, i'd \n deathmatch ya in a minute!",
   "look, bud. you leave now\nand you forfeit your body count!",
   "just leave. when you come\nback, i'll be waiting with a bat.",
-  "you're lucky i don't smack\nyou for thinking about leaving."
+  "you're lucky i don't smack\nyou for thinking about leaving.",
+};
+
+#if 0
+
+// UNUSED messages included in the source release
 
+char* endmsg[] =
+{
+  // DOOM1
+  QUITMSG,
   // FinalDOOM?
   "fuck you, pussy!\nget the fuck out!",
   "you quit and i'll jizz\nin your cystholes!",
@@ -66,6 +66,7 @@ char* endmsg[NUM_QUITMESSAGES+1]=
   "THIS IS NO MESSAGE!\nPage intentionally left blank."
 };
 
+#endif
 
   
 
index 291767bc30f399b06545225b6c73bfff571f4f67..d3240b499146c4babf76d2cc0dabe381dc11c601 100644 (file)
@@ -1,26 +1,21 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
-// $Log:$
 //
 // DESCRIPTION:
 //     DOOM strings, by language.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __DSTRINGS__
 
 
 // All important printed strings.
-// Language selection (message strings).
-// Use -DFRENCH etc.
 
-#ifdef FRENCH
-#include "d_french.h"
-#else
 #include "d_englsh.h"
-#endif
 
 // Misc. other strings.
 #define SAVEGAMENAME   "doomsav"
 
 
-//
-// File locations,
-//  relative to current position.
-// Path names are OS-sensitive.
-//
-#define DEVMAPS "devmaps"
-#define DEVDATA "devdata"
-
-
-// Not done in french?
-
 // QuitDOOM messages
-#define NUM_QUITMESSAGES   22
+// 8 per each game type
+#define NUM_QUITMESSAGES   8
 
-extern char* endmsg[];
+extern char *doom1_endmsg[];
+extern char *doom2_endmsg[];
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
diff --git a/frosted-doom/dummy.c b/frosted-doom/dummy.c
new file mode 100644 (file)
index 0000000..0068d03
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * dummy.c
+ *
+ *  Created on: 16.02.2015
+ *      Author: Florian
+ */
+
+
+/*---------------------------------------------------------------------*
+ *  include files                                                      *
+ *---------------------------------------------------------------------*/
+
+#include "doomtype.h"
+
+/*---------------------------------------------------------------------*
+ *  local definitions                                                  *
+ *---------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------*
+ *  external declarations                                              *
+ *---------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------*
+ *  public data                                                        *
+ *---------------------------------------------------------------------*/
+
+boolean net_client_connected = false;
+
+boolean drone = false;
+
+/*---------------------------------------------------------------------*
+ *  private data                                                       *
+ *---------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------*
+ *  private functions                                                  *
+ *---------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------*
+ *  public functions                                                   *
+ *---------------------------------------------------------------------*/
+
+void I_InitTimidityConfig(void)
+{
+}
+
+/*---------------------------------------------------------------------*
+ *  eof                                                                *
+ *---------------------------------------------------------------------*/
index a6e74dd4cecc27f61c43cff2716bc3836d94a126..ca6775ef8883c1989794888776c6c56ede955b9d 100644 (file)
@@ -1,86 +1,98 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Game completion, final screen animation.
 //
-//-----------------------------------------------------------------------------
 
 
-static const char
-rcsid[] = "$Id: f_finale.c,v 1.5 1997/02/03 21:26:34 b1 Exp $";
-
+#include <stdio.h>
 #include <ctype.h>
 
 // Functions.
+#include "deh_main.h"
 #include "i_system.h"
-#include "m_swap.h"
+#include "i_swap.h"
 #include "z_zone.h"
 #include "v_video.h"
 #include "w_wad.h"
 #include "s_sound.h"
 
 // Data.
+#include "d_main.h"
 #include "dstrings.h"
 #include "sounds.h"
 
 #include "doomstat.h"
 #include "r_state.h"
 
+typedef enum
+{
+    F_STAGE_TEXT,
+    F_STAGE_ARTSCREEN,
+    F_STAGE_CAST,
+} finalestage_t;
+
 // ?
 //#include "doomstat.h"
 //#include "r_local.h"
 //#include "f_finale.h"
 
 // Stage of animation:
-//  0 = text, 1 = art screen, 2 = character cast
-int            finalestage;
+finalestage_t finalestage;
 
-int            finalecount;
+unsigned int finalecount;
 
 #define        TEXTSPEED       3
 #define        TEXTWAIT        250
 
-char*  e1text = E1TEXT;
-char*  e2text = E2TEXT;
-char*  e3text = E3TEXT;
-char*  e4text = E4TEXT;
-
-char*  c1text = C1TEXT;
-char*  c2text = C2TEXT;
-char*  c3text = C3TEXT;
-char*  c4text = C4TEXT;
-char*  c5text = C5TEXT;
-char*  c6text = C6TEXT;
-
-char*  p1text = P1TEXT;
-char*  p2text = P2TEXT;
-char*  p3text = P3TEXT;
-char*  p4text = P4TEXT;
-char*  p5text = P5TEXT;
-char*  p6text = P6TEXT;
-
-char*  t1text = T1TEXT;
-char*  t2text = T2TEXT;
-char*  t3text = T3TEXT;
-char*  t4text = T4TEXT;
-char*  t5text = T5TEXT;
-char*  t6text = T6TEXT;
+typedef struct
+{
+    GameMission_t mission;
+    int episode, level;
+    char *background;
+    char *text;
+} textscreen_t;
+
+static textscreen_t textscreens[] =
+{
+    { doom,      1, 8,  "FLOOR4_8",  E1TEXT},
+    { doom,      2, 8,  "SFLR6_1",   E2TEXT},
+    { doom,      3, 8,  "MFLR8_4",   E3TEXT},
+    { doom,      4, 8,  "MFLR8_3",   E4TEXT},
+
+    { doom2,     1, 6,  "SLIME16",   C1TEXT},
+    { doom2,     1, 11, "RROCK14",   C2TEXT},
+    { doom2,     1, 20, "RROCK07",   C3TEXT},
+    { doom2,     1, 30, "RROCK17",   C4TEXT},
+    { doom2,     1, 15, "RROCK13",   C5TEXT},
+    { doom2,     1, 31, "RROCK19",   C6TEXT},
+
+    { pack_tnt,  1, 6,  "SLIME16",   T1TEXT},
+    { pack_tnt,  1, 11, "RROCK14",   T2TEXT},
+    { pack_tnt,  1, 20, "RROCK07",   T3TEXT},
+    { pack_tnt,  1, 30, "RROCK17",   T4TEXT},
+    { pack_tnt,  1, 15, "RROCK13",   T5TEXT},
+    { pack_tnt,  1, 31, "RROCK19",   T6TEXT},
+
+    { pack_plut, 1, 6,  "SLIME16",   P1TEXT},
+    { pack_plut, 1, 11, "RROCK14",   P2TEXT},
+    { pack_plut, 1, 20, "RROCK07",   P3TEXT},
+    { pack_plut, 1, 30, "RROCK17",   P4TEXT},
+    { pack_plut, 1, 15, "RROCK13",   P5TEXT},
+    { pack_plut, 1, 31, "RROCK19",   P6TEXT},
+};
 
 char*  finaletext;
 char*  finaleflat;
@@ -95,97 +107,50 @@ void       F_CastDrawer (void);
 //
 void F_StartFinale (void)
 {
+    size_t i;
+
     gameaction = ga_nothing;
     gamestate = GS_FINALE;
     viewactive = false;
     automapactive = false;
 
-    // Okay - IWAD dependend stuff.
-    // This has been changed severly, and
-    //  some stuff might have changed in the process.
-    switch ( gamemode )
+    if (logical_gamemission == doom)
+    {
+        S_ChangeMusic(mus_victor, true);
+    }
+    else
     {
+        S_ChangeMusic(mus_read_m, true);
+    }
 
-      // DOOM 1 - E1, E3 or E4, but each nine missions
-      case shareware:
-      case registered:
-      case retail:
-      {
-       S_ChangeMusic(mus_victor, true);
-       
-       switch (gameepisode)
-       {
-         case 1:
-           finaleflat = "FLOOR4_8";
-           finaletext = e1text;
-           break;
-         case 2:
-           finaleflat = "SFLR6_1";
-           finaletext = e2text;
-           break;
-         case 3:
-           finaleflat = "MFLR8_4";
-           finaletext = e3text;
-           break;
-         case 4:
-           finaleflat = "MFLR8_3";
-           finaletext = e4text;
-           break;
-         default:
-           // Ouch.
-           break;
-       }
-       break;
-      }
-      
-      // DOOM II and missions packs with E1, M34
-      case commercial:
-      {
-         S_ChangeMusic(mus_read_m, true);
-
-         switch (gamemap)
-         {
-           case 6:
-             finaleflat = "SLIME16";
-             finaletext = c1text;
-             break;
-           case 11:
-             finaleflat = "RROCK14";
-             finaletext = c2text;
-             break;
-           case 20:
-             finaleflat = "RROCK07";
-             finaletext = c3text;
-             break;
-           case 30:
-             finaleflat = "RROCK17";
-             finaletext = c4text;
-             break;
-           case 15:
-             finaleflat = "RROCK13";
-             finaletext = c5text;
-             break;
-           case 31:
-             finaleflat = "RROCK19";
-             finaletext = c6text;
-             break;
-           default:
-             // Ouch.
-             break;
-         }
-         break;
-      }        
-
-   
-      // Indeterminate.
-      default:
-       S_ChangeMusic(mus_read_m, true);
-       finaleflat = "F_SKY1"; // Not used anywhere else.
-       finaletext = c1text;  // FIXME - other text, music?
-       break;
+    // Find the right screen and set the text and background
+
+    for (i=0; i<arrlen(textscreens); ++i)
+    {
+        textscreen_t *screen = &textscreens[i];
+
+        // Hack for Chex Quest
+
+        if (gameversion == exe_chex && screen->mission == doom)
+        {
+            screen->level = 5;
+        }
+
+        if (logical_gamemission == screen->mission
+         && (logical_gamemission != doom || gameepisode == screen->episode)
+         && gamemap == screen->level)
+        {
+            finaletext = screen->text;
+            finaleflat = screen->background;
+        }
     }
+
+    // Do dehacked substitutions of strings
+  
+    finaletext = DEH_String(finaletext);
+    finaleflat = DEH_String(finaleflat);
     
-    finalestage = 0;
+    finalestage = F_STAGE_TEXT;
     finalecount = 0;
        
 }
@@ -194,7 +159,7 @@ void F_StartFinale (void)
 
 boolean F_Responder (event_t *event)
 {
-    if (finalestage == 2)
+    if (finalestage == F_STAGE_CAST)
        return F_CastResponder (event);
        
     return false;
@@ -206,7 +171,7 @@ boolean F_Responder (event_t *event)
 //
 void F_Ticker (void)
 {
-    int                i;
+    size_t             i;
     
     // check for skipping
     if ( (gamemode == commercial)
@@ -229,7 +194,7 @@ void F_Ticker (void)
     // advance animation
     finalecount++;
        
-    if (finalestage == 2)
+    if (finalestage == F_STAGE_CAST)
     {
        F_CastTicker ();
        return;
@@ -238,10 +203,11 @@ void F_Ticker (void)
     if ( gamemode == commercial)
        return;
                
-    if (!finalestage && finalecount>strlen (finaletext)*TEXTSPEED + TEXTWAIT)
+    if (finalestage == F_STAGE_TEXT
+     && finalecount>strlen (finaletext)*TEXTSPEED + TEXTWAIT)
     {
        finalecount = 0;
-       finalestage = 1;
+       finalestage = F_STAGE_ARTSCREEN;
        wipegamestate = -1;             // force a wipe
        if (gameepisode == 3)
            S_StartMusic (mus_bunny);
@@ -264,7 +230,7 @@ void F_TextWrite (void)
     byte*      dest;
     
     int                x,y,w;
-    int                count;
+    signed int count;
     char*      ch;
     int                c;
     int                cx;
@@ -272,7 +238,7 @@ void F_TextWrite (void)
     
     // erase the entire screen to a tiled background
     src = W_CacheLumpName ( finaleflat , PU_CACHE);
-    dest = screens[0];
+    dest = I_VideoBuffer;
        
     for (y=0 ; y<SCREENHEIGHT ; y++)
     {
@@ -295,7 +261,7 @@ void F_TextWrite (void)
     cy = 10;
     ch = finaletext;
        
-    count = (finalecount - 10)/TEXTSPEED;
+    count = ((signed int) finalecount - 10) / TEXTSPEED;
     if (count < 0)
        count = 0;
     for ( ; count ; count-- )
@@ -320,7 +286,7 @@ void F_TextWrite (void)
        w = SHORT (hu_font[c]->width);
        if (cx+w > SCREENWIDTH)
            break;
-       V_DrawPatch(cx, cy, 0, hu_font[c]);
+       V_DrawPatch(cx, cy, hu_font[c]);
        cx+=w;
     }
        
@@ -371,9 +337,6 @@ boolean             castattacking;
 //
 // F_StartCast
 //
-extern gamestate_t     wipegamestate;
-
-
 void F_StartCast (void)
 {
     wipegamestate = -1;                // force a screen wipe
@@ -381,7 +344,7 @@ void F_StartCast (void)
     caststate = &states[mobjinfo[castorder[castnum].type].seestate];
     casttics = caststate->tics;
     castdeath = false;
-    finalestage = 2;   
+    finalestage = F_STAGE_CAST;
     castframes = 0;
     castonmelee = 0;
     castattacking = false;
@@ -564,7 +527,7 @@ void F_CastPrint (char* text)
        }
                
        w = SHORT (hu_font[c]->width);
-       V_DrawPatch(cx, 180, 0, hu_font[c]);
+       V_DrawPatch(cx, 180, hu_font[c]);
        cx+=w;
     }
        
@@ -574,7 +537,6 @@ void F_CastPrint (char* text)
 //
 // F_CastDrawer
 //
-void V_DrawPatchFlipped (int x, int y, int scrn, patch_t *patch);
 
 void F_CastDrawer (void)
 {
@@ -585,9 +547,9 @@ void F_CastDrawer (void)
     patch_t*           patch;
     
     // erase the entire screen to a background
-    V_DrawPatch (0,0,0, W_CacheLumpName ("BOSSBACK", PU_CACHE));
+    V_DrawPatch (0, 0, W_CacheLumpName (DEH_String("BOSSBACK"), PU_CACHE));
 
-    F_CastPrint (castorder[castnum].name);
+    F_CastPrint (DEH_String(castorder[castnum].name));
     
     // draw the current frame in the middle of the screen
     sprdef = &sprites[caststate->sprite];
@@ -597,9 +559,9 @@ void F_CastDrawer (void)
                        
     patch = W_CacheLumpNum (lump+firstspritelump, PU_CACHE);
     if (flip)
-       V_DrawPatchFlipped (160,170,0,patch);
+       V_DrawPatchFlipped(160, 170, patch);
     else
-       V_DrawPatch (160,170,0,patch);
+       V_DrawPatch(160, 170, patch);
 }
 
 
@@ -619,7 +581,7 @@ F_DrawPatchCol
     int                count;
        
     column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
-    desttop = screens[0]+x;
+    desttop = I_VideoBuffer + x;
 
     // step through the posts in a column
     while (column->topdelta != 0xff )
@@ -643,7 +605,7 @@ F_DrawPatchCol
 //
 void F_BunnyScroll (void)
 {
-    int                scrolled;
+    signed int  scrolled;
     int                x;
     patch_t*   p1;
     patch_t*   p2;
@@ -651,12 +613,12 @@ void F_BunnyScroll (void)
     int                stage;
     static int laststage;
                
-    p1 = W_CacheLumpName ("PFUB2", PU_LEVEL);
-    p2 = W_CacheLumpName ("PFUB1", PU_LEVEL);
+    p1 = W_CacheLumpName (DEH_String("PFUB2"), PU_LEVEL);
+    p2 = W_CacheLumpName (DEH_String("PFUB1"), PU_LEVEL);
 
     V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
        
-    scrolled = 320 - (finalecount-230)/2;
+    scrolled = (320 - ((signed int) finalecount-230)/2);
     if (scrolled > 320)
        scrolled = 320;
     if (scrolled < 0)
@@ -674,8 +636,9 @@ void F_BunnyScroll (void)
        return;
     if (finalecount < 1180)
     {
-       V_DrawPatch ((SCREENWIDTH-13*8)/2,
-                    (SCREENHEIGHT-8*8)/2,0, W_CacheLumpName ("END0",PU_CACHE));
+        V_DrawPatch((SCREENWIDTH - 13 * 8) / 2,
+                    (SCREENHEIGHT - 8 * 8) / 2, 
+                    W_CacheLumpName(DEH_String("END0"), PU_CACHE));
        laststage = 0;
        return;
     }
@@ -689,50 +652,67 @@ void F_BunnyScroll (void)
        laststage = stage;
     }
        
-    sprintf (name,"END%i",stage);
-    V_DrawPatch ((SCREENWIDTH-13*8)/2, (SCREENHEIGHT-8*8)/2,0, W_CacheLumpName (name,PU_CACHE));
+    DEH_snprintf(name, 10, "END%i", stage);
+    V_DrawPatch((SCREENWIDTH - 13 * 8) / 2, 
+                (SCREENHEIGHT - 8 * 8) / 2, 
+                W_CacheLumpName (name,PU_CACHE));
 }
 
+static void F_ArtScreenDrawer(void)
+{
+    char *lumpname;
+    
+    if (gameepisode == 3)
+    {
+        F_BunnyScroll();
+    }
+    else
+    {
+        switch (gameepisode)
+        {
+            case 1:
+                if (gamemode == retail)
+                {
+                    lumpname = "CREDIT";
+                }
+                else
+                {
+                    lumpname = "HELP2";
+                }
+                break;
+            case 2:
+                lumpname = "VICTORY2";
+                break;
+            case 4:
+                lumpname = "ENDPIC";
+                break;
+            default:
+                return;
+        }
+
+        lumpname = DEH_String(lumpname);
+
+        V_DrawPatch (0, 0, W_CacheLumpName(lumpname, PU_CACHE));
+    }
+}
 
 //
 // F_Drawer
 //
 void F_Drawer (void)
 {
-    if (finalestage == 2)
+    switch (finalestage)
     {
-       F_CastDrawer ();
-       return;
+        case F_STAGE_CAST:
+            F_CastDrawer();
+            break;
+        case F_STAGE_TEXT:
+            F_TextWrite();
+            break;
+        case F_STAGE_ARTSCREEN:
+            F_ArtScreenDrawer();
+            break;
     }
-
-    if (!finalestage)
-       F_TextWrite ();
-    else
-    {
-       switch (gameepisode)
-       {
-         case 1:
-           if ( gamemode == retail )
-             V_DrawPatch (0,0,0,
-                        W_CacheLumpName("CREDIT",PU_CACHE));
-           else
-             V_DrawPatch (0,0,0,
-                        W_CacheLumpName("HELP2",PU_CACHE));
-           break;
-         case 2:
-           V_DrawPatch(0,0,0,
-                       W_CacheLumpName("VICTORY2",PU_CACHE));
-           break;
-         case 3:
-           F_BunnyScroll ();
-           break;
-         case 4:
-           V_DrawPatch (0,0,0,
-                        W_CacheLumpName("ENDPIC",PU_CACHE));
-           break;
-       }
-    }
-                       
 }
 
 
index c4fb5613002c5fb5d8a184eb7e88f37c2ad8439e..daa71c32a3e4a8857624c889fa4b4d90427719c4 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //
 //    
-//-----------------------------------------------------------------------------
 
 
 #ifndef __F_FINALE__
@@ -46,8 +43,3 @@ void F_StartFinale (void);
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index e8596f3a7ddd2b99d7f42dcf5bb6da8980922ca1..05852fd20e001f63a3b95830df1659d6a7549897 100644 (file)
@@ -1,37 +1,29 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Mission begin melt/wipe screen special effect.
 //
-//-----------------------------------------------------------------------------
-
-
-static const char rcsid[] = "$Id: f_wipe.c,v 1.2 1997/02/03 22:45:09 b1 Exp $";
-
 
+#include <string.h>
 
 #include "z_zone.h"
 #include "i_video.h"
 #include "v_video.h"
 #include "m_random.h"
 
-#include "doomdef.h"
+#include "doomtype.h"
 
 #include "f_wipe.h"
 
@@ -230,6 +222,8 @@ wipe_exitMelt
   int  ticks )
 {
     Z_Free(y);
+    Z_Free(wipe_scr_start);
+    Z_Free(wipe_scr_end);
     return 0;
 }
 
@@ -240,7 +234,7 @@ wipe_StartScreen
   int  width,
   int  height )
 {
-    wipe_scr_start = screens[2];
+    wipe_scr_start = Z_Malloc(SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL);
     I_ReadScreen(wipe_scr_start);
     return 0;
 }
@@ -252,9 +246,9 @@ wipe_EndScreen
   int  width,
   int  height )
 {
-    wipe_scr_end = screens[3];
+    wipe_scr_end = Z_Malloc(SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL);
     I_ReadScreen(wipe_scr_end);
-    V_DrawBlock(x, y, 0, width, height, wipe_scr_start); // restore start scr.
+    V_DrawBlock(x, y, width, height, wipe_scr_start); // restore start scr.
     return 0;
 }
 
@@ -274,14 +268,12 @@ wipe_ScreenWipe
        wipe_initMelt, wipe_doMelt, wipe_exitMelt
     };
 
-    void V_MarkRect(int, int, int, int);
-
     // initial stuff
     if (!go)
     {
        go = 1;
        // wipe_scr = (byte *) Z_Malloc(width*height, PU_STATIC, 0); // DEBUG
-       wipe_scr = screens[0];
+       wipe_scr = I_VideoBuffer;
        (*wipes[wipeno*3])(width, height, ticks);
     }
 
@@ -298,5 +290,5 @@ wipe_ScreenWipe
     }
 
     return !go;
-
 }
+
index 4a9927da378396493c60720e2336bb65635f369f..f48a9ca6515f412bd17a5ea5bc58afc67fea6e6c 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Mission start screen wipe/melt, special effects.
 //     
-//-----------------------------------------------------------------------------
 
 
 #ifndef __F_WIPE_H__
@@ -64,8 +61,3 @@ wipe_ScreenWipe
   int          ticks );
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index eb76b02d9f21d2e1c19d5e3066ad05763ae22eba..30fcd48cf2f81d2d7afeb7c96366db11efe36462 100644 (file)
@@ -1,42 +1,43 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:  none
 //
-//-----------------------------------------------------------------------------
 
 
-static const char
-rcsid[] = "$Id: g_game.c,v 1.8 1997/02/03 22:45:09 b1 Exp $";
 
 #include <string.h>
 #include <stdlib.h>
+#include <math.h>
 
 #include "doomdef.h" 
+#include "doomkeys.h"
 #include "doomstat.h"
 
+#include "deh_main.h"
+#include "deh_misc.h"
+
 #include "z_zone.h"
 #include "f_finale.h"
 #include "m_argv.h"
+#include "m_controls.h"
 #include "m_misc.h"
 #include "m_menu.h"
 #include "m_random.h"
 #include "i_system.h"
+#include "i_timer.h"
+#include "i_video.h"
 
 #include "p_setup.h"
 #include "p_saveg.h"
@@ -48,6 +49,7 @@ rcsid[] = "$Id: g_game.c,v 1.8 1997/02/03 22:45:09 b1 Exp $";
 #include "hu_stuff.h"
 #include "st_stuff.h"
 #include "am_map.h"
+#include "statdump.h"
 
 // Needs access to LFB.
 #include "v_video.h"
@@ -72,27 +74,24 @@ rcsid[] = "$Id: g_game.c,v 1.8 1997/02/03 22:45:09 b1 Exp $";
 
 
 #define SAVEGAMESIZE   0x2c000
-#define SAVESTRINGSIZE 24
-
 
-
-boolean        G_CheckDemoStatus (void); 
 void   G_ReadDemoTiccmd (ticcmd_t* cmd); 
 void   G_WriteDemoTiccmd (ticcmd_t* cmd); 
 void   G_PlayerReborn (int player); 
-void   G_InitNew (skill_t skill, int episode, int map); 
  
 void   G_DoReborn (int playernum); 
  
 void   G_DoLoadLevel (void); 
 void   G_DoNewGame (void); 
-void   G_DoLoadGame (void); 
 void   G_DoPlayDemo (void); 
 void   G_DoCompleted (void); 
 void   G_DoVictory (void); 
 void   G_DoWorldDone (void); 
 void   G_DoSaveGame (void); 
  
+// Gamestate the last time G_Ticker was called.
+
+gamestate_t     oldgamestate; 
  
 gameaction_t    gameaction; 
 gamestate_t     gamestate; 
@@ -100,7 +99,11 @@ skill_t         gameskill;
 boolean                respawnmonsters;
 int             gameepisode; 
 int             gamemap; 
+
+// If non-zero, exit the level after this number of minutes.
+
+int             timelimit;
+
 boolean         paused; 
 boolean         sendpause;                     // send a pause event next tic 
 boolean         sendsave;              // send a save event next tic 
@@ -108,24 +111,26 @@ boolean         usergame;               // ok to save / end game
  
 boolean         timingdemo;             // if true, exit with report on completion 
 boolean         nodrawers;              // for comparative timing purposes 
-boolean         noblit;                 // for comparative timing purposes 
 int             starttime;             // for comparative timing purposes       
  
 boolean         viewactive; 
  
-boolean         deathmatch;            // only if started as net death 
+int             deathmatch;            // only if started as net death 
 boolean         netgame;                // only true if packets are broadcast 
 boolean         playeringame[MAXPLAYERS]; 
 player_t        players[MAXPLAYERS]; 
+
+boolean         turbodetected[MAXPLAYERS];
  
 int             consoleplayer;          // player taking events and displaying 
 int             displayplayer;          // view being displayed 
-int             gametic; 
 int             levelstarttic;          // gametic at level start 
 int             totalkills, totalitems, totalsecret;    // for intermission 
  
-char            demoname[32]; 
+char           *demoname;
 boolean         demorecording; 
+boolean         longtics;               // cph's doom 1.91 longtics hack
+boolean         lowres_turn;            // low resolution turning for longtics
 boolean         demoplayback; 
 boolean                netdemo; 
 byte*          demobuffer;
@@ -134,91 +139,100 @@ byte*            demoend;
 boolean         singledemo;                    // quit after playing a demo from cmdline 
  
 boolean         precache = true;        // if true, load all graphics at start 
-wbstartstruct_t wminfo;                // parms for world map / intermission 
-short          consistancy[MAXPLAYERS][BACKUPTICS]; 
-byte*          savebuffer;
-// 
-// controls (have defaults) 
-// 
-int             key_right;
-int            key_left;
 
-int            key_up;
-int            key_down; 
-int             key_strafeleft;
-int            key_straferight; 
-int             key_fire;
-int            key_use;
-int            key_strafe;
-int            key_speed; 
+boolean         testcontrols = false;    // Invoked by setup to test controls
+int             testcontrols_mousespeed;
  
-int             mousebfire; 
-int             mousebstrafe; 
-int             mousebforward; 
-int             joybfire; 
-int             joybstrafe; 
-int             joybuse; 
-int             joybspeed; 
+
  
+wbstartstruct_t wminfo;                // parms for world map / intermission 
  
+byte           consistancy[MAXPLAYERS][BACKUPTICS]; 
  
 #define MAXPLMOVE              (forwardmove[1]) 
  
 #define TURBOTHRESHOLD 0x32
 
-fixed_t                forwardmove[2] = {0x19, 0x32}; 
-fixed_t                sidemove[2] = {0x18, 0x28}; 
-fixed_t                angleturn[3] = {640, 1280, 320};        // + slow turn 
+fixed_t         forwardmove[2] = {0x19, 0x32}; 
+fixed_t         sidemove[2] = {0x18, 0x28}; 
+fixed_t         angleturn[3] = {640, 1280, 320};    // + slow turn 
+
+static int *weapon_keys[] = {
+    &key_weapon1,
+    &key_weapon2,
+    &key_weapon3,
+    &key_weapon4,
+    &key_weapon5,
+    &key_weapon6,
+    &key_weapon7,
+    &key_weapon8
+};
+
+// Set to -1 or +1 to switch to the previous or next weapon.
+
+static int next_weapon = 0;
+
+// Used for prev/next weapon keys.
+
+static const struct
+{
+    weapontype_t weapon;
+    weapontype_t weapon_num;
+} weapon_order_table[] = {
+    { wp_fist,            wp_fist },
+    { wp_chainsaw,        wp_fist },
+    { wp_pistol,          wp_pistol },
+    { wp_shotgun,         wp_shotgun },
+    { wp_supershotgun,    wp_shotgun },
+    { wp_chaingun,        wp_chaingun },
+    { wp_missile,         wp_missile },
+    { wp_plasma,          wp_plasma },
+    { wp_bfg,             wp_bfg }
+};
 
 #define SLOWTURNTICS   6 
  
 #define NUMKEYS                256 
+#define MAX_JOY_BUTTONS 20
 
-boolean         gamekeydown[NUMKEYS]; 
-int             turnheld;                              // for accelerative turning 
+static boolean  gamekeydown[NUMKEYS]; 
+static int      turnheld;              // for accelerative turning 
  
-boolean                mousearray[4]; 
-boolean*       mousebuttons = &mousearray[1];          // allow [-1]
+static boolean  mousearray[MAX_MOUSE_BUTTONS + 1];
+static boolean *mousebuttons = &mousearray[1];  // allow [-1]
 
 // mouse values are used once 
 int             mousex;
-int            mousey;         
+int             mousey;         
 
-int             dclicktime;
-int            dclickstate;
-int            dclicks; 
-int             dclicktime2;
-int            dclickstate2;
-int            dclicks2;
+static int      dclicktime;
+static boolean  dclickstate;
+static int      dclicks; 
+static int      dclicktime2;
+static boolean  dclickstate2;
+static int      dclicks2;
 
 // joystick values are repeated 
-int             joyxmove;
-int            joyymove;
-boolean         joyarray[5]; 
-boolean*       joybuttons = &joyarray[1];              // allow [-1] 
-int            savegameslot; 
-char           savedescription[32]; 
+static int      joyxmove;
+static int      joyymove;
+static int      joystrafemove;
+static boolean  joyarray[MAX_JOY_BUTTONS + 1]; 
+static boolean *joybuttons = &joyarray[1];             // allow [-1] 
  
+static int      savegameslot; 
+static char     savedescription[32]; 
  
 #define        BODYQUESIZE     32
 
 mobj_t*                bodyque[BODYQUESIZE]; 
 int            bodyqueslot; 
  
-void*          statcopy;                               // for statistics driver
+int             vanilla_savegame_limit = 1;
+int             vanilla_demo_limit = 1;
  
 int G_CmdChecksum (ticcmd_t* cmd) 
 { 
-    int                i;
+    size_t             i;
     int                sum = 0; 
         
     for (i=0 ; i< sizeof(*cmd)/4 - 1 ; i++) 
@@ -226,7 +240,78 @@ int G_CmdChecksum (ticcmd_t* cmd)
                 
     return sum; 
 } 
+
+static boolean WeaponSelectable(weapontype_t weapon)
+{
+    // Can't select the super shotgun in Doom 1.
+
+    if (weapon == wp_supershotgun && logical_gamemission == doom)
+    {
+        return false;
+    }
+
+    // These weapons aren't available in shareware.
+
+    if ((weapon == wp_plasma || weapon == wp_bfg)
+     && gamemission == doom && gamemode == shareware)
+    {
+        return false;
+    }
+
+    // Can't select a weapon if we don't own it.
+
+    if (!players[consoleplayer].weaponowned[weapon])
+    {
+        return false;
+    }
+
+    // Can't select the fist if we have the chainsaw, unless
+    // we also have the berserk pack.
+
+    if (weapon == wp_fist
+     && players[consoleplayer].weaponowned[wp_chainsaw]
+     && !players[consoleplayer].powers[pw_strength])
+    {
+        return false;
+    }
+
+    return true;
+}
+
+static int G_NextWeapon(int direction)
+{
+    weapontype_t weapon;
+    int start_i, i;
+
+    // Find index in the table.
+
+    if (players[consoleplayer].pendingweapon == wp_nochange)
+    {
+        weapon = players[consoleplayer].readyweapon;
+    }
+    else
+    {
+        weapon = players[consoleplayer].pendingweapon;
+    }
+
+    for (i=0; i<arrlen(weapon_order_table); ++i)
+    {
+        if (weapon_order_table[i].weapon == weapon)
+        {
+            break;
+        }
+    }
+
+    // Switch weapon. Don't loop forever.
+    start_i = i;
+    do
+    {
+        i += direction;
+        i = (i + arrlen(weapon_order_table)) % arrlen(weapon_order_table);
+    } while (i != start_i && !WeaponSelectable(weapon_order_table[i].weapon));
+
+    return weapon_order_table[i].weapon_num;
+}
 
 //
 // G_BuildTiccmd
@@ -234,7 +319,7 @@ int G_CmdChecksum (ticcmd_t* cmd)
 // or reads it from the demo buffer. 
 // If recording a demo, write it out 
 // 
-void G_BuildTiccmd (ticcmd_t* cmd) 
+void G_BuildTiccmd (ticcmd_t* cmd, int maketic
 { 
     int                i; 
     boolean    strafe;
@@ -243,19 +328,22 @@ void G_BuildTiccmd (ticcmd_t* cmd)
     int                tspeed; 
     int                forward;
     int                side;
-    
-    ticcmd_t*  base;
 
-    base = I_BaseTiccmd ();            // empty, or external driver
-    memcpy (cmd,base,sizeof(*cmd)); 
-       
+    memset(cmd, 0, sizeof(ticcmd_t));
+
     cmd->consistancy = 
        consistancy[consoleplayer][maketic%BACKUPTICS]; 
-
  
     strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe] 
        || joybuttons[joybstrafe]; 
-    speed = gamekeydown[key_speed] || joybuttons[joybspeed];
+
+    // fraggle: support the old "joyb_speed = 31" hack which
+    // allowed an autorun effect
+
+    speed = key_speed >= NUMKEYS
+         || joybspeed >= MAX_JOY_BUTTONS
+         || gamekeydown[key_speed] 
+         || joybuttons[joybspeed];
  
     forward = side = 0;
     
@@ -315,15 +403,28 @@ void G_BuildTiccmd (ticcmd_t* cmd)
        // fprintf(stderr, "down\n");
        forward -= forwardmove[speed]; 
     }
+
     if (joyymove < 0) 
-       forward += forwardmove[speed]; 
+        forward += forwardmove[speed]; 
     if (joyymove > 0) 
-       forward -= forwardmove[speed]; 
-    if (gamekeydown[key_straferight]) 
-       side += sidemove[speed]; 
-    if (gamekeydown[key_strafeleft]) 
-       side -= sidemove[speed];
-    
+        forward -= forwardmove[speed]; 
+
+    if (gamekeydown[key_strafeleft]
+     || joybuttons[joybstrafeleft]
+     || mousebuttons[mousebstrafeleft]
+     || joystrafemove < 0)
+    {
+        side -= sidemove[speed];
+    }
+
+    if (gamekeydown[key_straferight]
+     || joybuttons[joybstraferight]
+     || mousebuttons[mousebstraferight]
+     || joystrafemove > 0)
+    {
+        side += sidemove[speed]; 
+    }
+
     // buttons
     cmd->chatchar = HU_dequeueChatChar(); 
  
@@ -331,83 +432,122 @@ void G_BuildTiccmd (ticcmd_t* cmd)
        || joybuttons[joybfire]) 
        cmd->buttons |= BT_ATTACK; 
  
-    if (gamekeydown[key_use] || joybuttons[joybuse] ) 
+    if (gamekeydown[key_use]
+     || joybuttons[joybuse]
+     || mousebuttons[mousebuse])
     { 
        cmd->buttons |= BT_USE;
        // clear double clicks if hit use button 
        dclicks = 0;                   
     } 
 
-    // chainsaw overrides 
-    for (i=0 ; i<NUMWEAPONS-1 ; i++)        
-       if (gamekeydown['1'+i]) 
-       { 
-           cmd->buttons |= BT_CHANGE; 
-           cmd->buttons |= i<<BT_WEAPONSHIFT; 
-           break; 
-       }
-    
+    // If the previous or next weapon button is pressed, the
+    // next_weapon variable is set to change weapons when
+    // we generate a ticcmd.  Choose a new weapon.
+
+    if (gamestate == GS_LEVEL && next_weapon != 0)
+    {
+        i = G_NextWeapon(next_weapon);
+        cmd->buttons |= BT_CHANGE;
+        cmd->buttons |= i << BT_WEAPONSHIFT;
+    }
+    else
+    {
+        // Check weapon keys.
+
+        for (i=0; i<arrlen(weapon_keys); ++i)
+        {
+            int key = *weapon_keys[i];
+
+            if (gamekeydown[key])
+            {
+                cmd->buttons |= BT_CHANGE;
+                cmd->buttons |= i<<BT_WEAPONSHIFT;
+                break;
+            }
+        }
+    }
+
+    next_weapon = 0;
+
     // mouse
     if (mousebuttons[mousebforward]) 
+    {
        forward += forwardmove[speed];
-    
-    // forward double click
-    if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1 ) 
-    { 
-       dclickstate = mousebuttons[mousebforward]; 
-       if (dclickstate) 
-           dclicks++; 
-       if (dclicks == 2) 
-       { 
-           cmd->buttons |= BT_USE; 
-           dclicks = 0; 
-       } 
-       else 
-           dclicktime = 0; 
-    } 
-    else 
-    { 
-       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) 
-       { 
-           cmd->buttons |= BT_USE; 
-           dclicks2 = 0; 
-       } 
-       else 
-           dclicktime2 = 0; 
-    } 
-    else 
-    { 
-       dclicktime2 += ticdup; 
-       if (dclicktime2 > 20) 
-       { 
-           dclicks2 = 0; 
-           dclickstate2 = 0; 
-       } 
-    } 
+    if (mousebuttons[mousebbackward])
+    {
+        forward -= forwardmove[speed];
+    }
+
+    if (dclick_use)
+    {
+        // forward double click
+        if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1 ) 
+        { 
+            dclickstate = mousebuttons[mousebforward]; 
+            if (dclickstate) 
+                dclicks++; 
+            if (dclicks == 2) 
+            { 
+                cmd->buttons |= BT_USE; 
+                dclicks = 0; 
+            } 
+            else 
+                dclicktime = 0; 
+        } 
+        else 
+        { 
+            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) 
+            { 
+                cmd->buttons |= BT_USE; 
+                dclicks2 = 0; 
+            } 
+            else 
+                dclicktime2 = 0; 
+        } 
+        else 
+        { 
+            dclicktime2 += ticdup; 
+            if (dclicktime2 > 20) 
+            { 
+                dclicks2 = 0; 
+                dclickstate2 = 0; 
+            } 
+        } 
+    }
+
     forward += mousey; 
+
     if (strafe) 
        side += mousex*2; 
     else 
        cmd->angleturn -= mousex*0x8; 
 
+    if (mousex == 0)
+    {
+        // No movement in the previous frame
+
+        testcontrols_mousespeed = 0;
+    }
+    
     mousex = mousey = 0; 
         
     if (forward > MAXPLMOVE) 
@@ -434,14 +574,32 @@ void G_BuildTiccmd (ticcmd_t* cmd)
        sendsave = false; 
        cmd->buttons = BT_SPECIAL | BTS_SAVEGAME | (savegameslot<<BTS_SAVESHIFT); 
     } 
+
+    // low-res turning
+
+    if (lowres_turn)
+    {
+        static signed short carry = 0;
+        signed short desired_angleturn;
+
+        desired_angleturn = cmd->angleturn + carry;
+
+        // round angleturn to the nearest 256 unit boundary
+        // for recording demos with single byte values for turn
+
+        cmd->angleturn = (desired_angleturn + 128) & 0xff00;
+
+        // Carry forward the error from the reduced resolution to the
+        // next tic, so that successive small movements can accumulate.
+
+        carry = desired_angleturn - cmd->angleturn;
+    }
 } 
  
 
 //
 // G_DoLoadLevel 
 //
-extern  gamestate_t     wipegamestate; 
 void G_DoLoadLevel (void) 
 { 
     int             i; 
@@ -451,20 +609,32 @@ void G_DoLoadLevel (void)
     //  a flat. The data is in the WAD only because
     //  we look for an actual index, instead of simply
     //  setting one.
-    skyflatnum = R_FlatNumForName ( SKYFLATNAME );
 
-    // DOOM determines the sky texture to be used
-    // depending on the current episode, and the game version.
-    if ( (gamemode == commercial)
-        || ( gamemode == pack_tnt )
-        || ( gamemode == pack_plut ) )
+    skyflatnum = R_FlatNumForName(DEH_String(SKYFLATNAME));
+
+    // The "Sky never changes in Doom II" bug was fixed in
+    // the id Anthology version of doom2.exe for Final Doom.
+    if ((gamemode == commercial)
+     && (gameversion == exe_final2 || gameversion == exe_chex))
     {
-       skytexture = R_TextureNumForName ("SKY3");
-       if (gamemap < 12)
-           skytexture = R_TextureNumForName ("SKY1");
-       else
-           if (gamemap < 21)
-               skytexture = R_TextureNumForName ("SKY2");
+        char *skytexturename;
+
+        if (gamemap < 12)
+        {
+            skytexturename = "SKY1";
+        }
+        else if (gamemap < 21)
+        {
+            skytexturename = "SKY2";
+        }
+        else
+        {
+            skytexturename = "SKY3";
+        }
+
+        skytexturename = DEH_String(skytexturename);
+
+        skytexture = R_TextureNumForName(skytexturename);
     }
 
     levelstarttic = gametic;        // for time calculation
@@ -476,6 +646,7 @@ void G_DoLoadLevel (void)
 
     for (i=0 ; i<MAXPLAYERS ; i++) 
     { 
+       turbodetected[i] = false;
        if (playeringame[i] && players[i].playerstate == PST_DEAD) 
            players[i].playerstate = PST_REBORN; 
        memset (players[i].frags,0,sizeof(players[i].frags)); 
@@ -483,20 +654,78 @@ void G_DoLoadLevel (void)
                 
     P_SetupLevel (gameepisode, gamemap, 0, gameskill);    
     displayplayer = consoleplayer;             // view the guy you are playing    
-    starttime = I_GetTime (); 
     gameaction = ga_nothing; 
     Z_CheckHeap ();
     
     // clear cmd building stuff
-    memset (gamekeydown, 0, sizeof(gamekeydown)); 
-    joyxmove = joyymove = 0; 
-    mousex = mousey = 0; 
-    sendpause = sendsave = paused = false; 
-    memset (mousebuttons, 0, sizeof(mousearray)); 
-    memset (joybuttons, 0, sizeof(joyarray)); 
+
+    memset (gamekeydown, 0, sizeof(gamekeydown));
+    joyxmove = joyymove = joystrafemove = 0;
+    mousex = mousey = 0;
+    sendpause = sendsave = paused = false;
+    memset(mousearray, 0, sizeof(mousearray));
+    memset(joyarray, 0, sizeof(joyarray));
+
+    if (testcontrols)
+    {
+        players[consoleplayer].message = "Press escape to quit.";
+    }
 } 
+
+static void SetJoyButtons(unsigned int buttons_mask)
+{
+    int i;
+
+    for (i=0; i<MAX_JOY_BUTTONS; ++i)
+    {
+        int button_on = (buttons_mask & (1 << i)) != 0;
+
+        // Detect button press:
+
+        if (!joybuttons[i] && button_on)
+        {
+            // Weapon cycling:
+
+            if (i == joybprevweapon)
+            {
+                next_weapon = -1;
+            }
+            else if (i == joybnextweapon)
+            {
+                next_weapon = 1;
+            }
+        }
+
+        joybuttons[i] = button_on;
+    }
+}
+
+static void SetMouseButtons(unsigned int buttons_mask)
+{
+    int i;
+
+    for (i=0; i<MAX_MOUSE_BUTTONS; ++i)
+    {
+        unsigned int button_on = (buttons_mask & (1 << i)) != 0;
+
+        // Detect button press:
+
+        if (!mousebuttons[i] && button_on)
+        {
+            if (i == mousebprevweapon)
+            {
+                next_weapon = -1;
+            }
+            else if (i == mousebnextweapon)
+            {
+                next_weapon = 1;
+            }
+        }
+
+       mousebuttons[i] = button_on;
+    }
+}
+
 //
 // G_Responder  
 // Get info needed to make ticcmd_ts for the players.
@@ -505,7 +734,7 @@ boolean G_Responder (event_t* ev)
 { 
     // allow spy mode changes even during the demo
     if (gamestate == GS_LEVEL && ev->type == ev_keydown 
-       && ev->data1 == KEY_F12 && (singledemo || !deathmatch) )
+     && ev->data1 == key_spy && (singledemo || !deathmatch) )
     {
        // spy mode 
        do 
@@ -531,7 +760,7 @@ boolean G_Responder (event_t* ev)
        } 
        return false; 
     } 
+
     if (gamestate == GS_LEVEL) 
     { 
 #if 0 
@@ -554,17 +783,41 @@ boolean G_Responder (event_t* ev)
        if (F_Responder (ev)) 
            return true;        // finale ate the event 
     } 
-        
+
+    if (testcontrols && ev->type == ev_mouse)
+    {
+        // If we are invoked by setup to test the controls, save the 
+        // mouse speed so that we can display it on-screen.
+        // Perform a low pass filter on this so that the thermometer 
+        // appears to move smoothly.
+
+        testcontrols_mousespeed = abs(ev->data2);
+    }
+
+    // If the next/previous weapon keys are pressed, set the next_weapon
+    // variable to change weapons when the next ticcmd is generated.
+
+    if (ev->type == ev_keydown && ev->data1 == key_prevweapon)
+    {
+        next_weapon = -1;
+    }
+    else if (ev->type == ev_keydown && ev->data1 == key_nextweapon)
+    {
+        next_weapon = 1;
+    }
+
     switch (ev->type) 
     { 
       case ev_keydown: 
-       if (ev->data1 == KEY_PAUSE
+       if (ev->data1 == key_pause
        { 
            sendpause = true; 
-           return true; 
-       } 
-       if (ev->data1 <NUMKEYS) 
+       }
+        else if (ev->data1 <NUMKEYS) 
+        {
            gamekeydown[ev->data1] = true; 
+        }
+
        return true;    // eat key down events 
  
       case ev_keyup: 
@@ -573,20 +826,16 @@ boolean G_Responder (event_t* ev)
        return false;   // always let key up events filter down 
                 
       case ev_mouse: 
-       mousebuttons[0] = ev->data1 & 1; 
-       mousebuttons[1] = ev->data1 & 2; 
-       mousebuttons[2] = ev->data1 & 4; 
+        SetMouseButtons(ev->data1);
        mousex = ev->data2*(mouseSensitivity+5)/10; 
        mousey = ev->data3*(mouseSensitivity+5)/10; 
        return true;    // eat events 
  
       case ev_joystick: 
-       joybuttons[0] = ev->data1 & 1; 
-       joybuttons[1] = ev->data1 & 2; 
-       joybuttons[2] = ev->data1 & 4; 
-       joybuttons[3] = ev->data1 & 8; 
+        SetJoyButtons(ev->data1);
        joyxmove = ev->data2; 
        joyymove = ev->data3; 
+        joystrafemove = ev->data4;
        return true;    // eat events 
  
       default: 
@@ -643,7 +892,8 @@ void G_Ticker (void)
            G_DoWorldDone (); 
            break; 
          case ga_screenshot: 
-           M_ScreenShot (); 
+           V_ScreenShot("DOOM%02i.%s"); 
+            players[consoleplayer].message = DEH_String("screen shot");
            gameaction = ga_nothing; 
            break; 
          case ga_nothing: 
@@ -660,24 +910,39 @@ void G_Ticker (void)
        if (playeringame[i]) 
        { 
            cmd = &players[i].cmd; 
-           memcpy (cmd, &netcmds[i][buf], sizeof(ticcmd_t)); 
+
+           memcpy(cmd, &netcmds[i], sizeof(ticcmd_t));
+
            if (demoplayback) 
                G_ReadDemoTiccmd (cmd); 
            if (demorecording) 
                G_WriteDemoTiccmd (cmd);
            
            // check for turbo cheats
-           if (cmd->forwardmove > TURBOTHRESHOLD 
-               && !(gametic&31) && ((gametic>>5)&3) == i )
-           {
-               static char turbomessage[80];
-               extern char *player_names[4];
-               sprintf (turbomessage, "%s is turbo!",player_names[i]);
-               players[consoleplayer].message = turbomessage;
-           }
-                       
+
+            // check ~ 4 seconds whether to display the turbo message. 
+            // store if the turbo threshold was exceeded in any tics
+            // over the past 4 seconds.  offset the checking period
+            // for each player so messages are not displayed at the
+            // same time.
+
+            if (cmd->forwardmove > TURBOTHRESHOLD)
+            {
+                turbodetected[i] = true;
+            }
+
+            if ((gametic & 31) == 0 
+             && ((gametic >> 5) % MAXPLAYERS) == i
+             && turbodetected[i])
+            {
+                static char turbomessage[80];
+                extern char *player_names[4];
+                M_snprintf(turbomessage, sizeof(turbomessage),
+                           "%s is turbo!", player_names[i]);
+                players[consoleplayer].message = turbomessage;
+                turbodetected[i] = false;
+            }
+
            if (netgame && !netdemo && !(gametic%ticdup) ) 
            { 
                if (gametic > BACKUPTICS 
@@ -711,9 +976,13 @@ void G_Ticker (void)
                        S_ResumeSound (); 
                    break; 
                                         
-                 case BTS_SAVEGAME: 
+                 case BTS_SAVEGAME:
                    if (!savedescription[0]) 
-                       strcpy (savedescription, "NET GAME"); 
+                    {
+                        M_StringCopy(savedescription, "NET GAME",
+                                     sizeof(savedescription));
+                    }
+
                    savegameslot =  
                        (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT; 
                    gameaction = ga_savegame; 
@@ -722,6 +991,15 @@ void G_Ticker (void)
            } 
        }
     }
+
+    // Have we just finished displaying an intermission screen?
+
+    if (oldgamestate == GS_INTERMISSION && gamestate != GS_INTERMISSION)
+    {
+        WI_End();
+    }
+
+    oldgamestate = gamestate;
     
     // do main actions
     switch (gamestate) 
@@ -743,7 +1021,7 @@ void G_Ticker (void)
  
       case GS_DEMOSCREEN: 
        D_PageTicker (); 
-       break; 
+       break;
     }        
 } 
  
@@ -759,16 +1037,10 @@ void G_Ticker (void)
 // Called by the game initialization functions.
 //
 void G_InitPlayer (int player) 
-{ 
-    //player_t*        p; 
-    // set up the saved info         
-    //p = &players[player]; 
-        
-    // clear everything else to defaults 
+{
+    // clear everything else to defaults
     G_PlayerReborn (player); 
-        
-} 
+}
  
  
 
@@ -821,11 +1093,11 @@ void G_PlayerReborn (int player)
  
     p->usedown = p->attackdown = true; // don't do anything immediately 
     p->playerstate = PST_LIVE;       
-    p->health = MAXHEALTH; 
+    p->health = deh_initial_health;     // Use dehacked value
     p->readyweapon = p->pendingweapon = wp_pistol; 
     p->weaponowned[wp_fist] = true; 
     p->weaponowned[wp_pistol] = true; 
-    p->ammo[am_clip] = 50
+    p->ammo[am_clip] = deh_initial_bullets
         
     for (i=0 ; i<NUMAMMO ; i++) 
        p->maxammo[i] = maxammo[i]; 
@@ -848,7 +1120,6 @@ G_CheckSpot
     fixed_t            x;
     fixed_t            y; 
     subsector_t*       ss; 
-    unsigned           an; 
     mobj_t*            mo; 
     int                        i;
        
@@ -873,15 +1144,70 @@ G_CheckSpot
        P_RemoveMobj (bodyque[bodyqueslot%BODYQUESIZE]); 
     bodyque[bodyqueslot%BODYQUESIZE] = players[playernum].mo; 
     bodyqueslot++; 
-       
-    // spawn a teleport fog 
-    ss = R_PointInSubsector (x,y); 
-    an = ( ANG45 * (mthing->angle/45) ) >> ANGLETOFINESHIFT; 
-    mo = P_SpawnMobj (x+20*finecosine[an], y+20*finesine[an] 
-                     , ss->sector->floorheight 
-                     , MT_TFOG); 
-        
+
+    // spawn a teleport fog
+    ss = R_PointInSubsector (x,y);
+
+
+    // The code in the released source looks like this:
+    //
+    //    an = ( ANG45 * (((unsigned int) mthing->angle)/45) )
+    //         >> ANGLETOFINESHIFT;
+    //    mo = P_SpawnMobj (x+20*finecosine[an], y+20*finesine[an]
+    //                     , ss->sector->floorheight
+    //                     , MT_TFOG);
+    //
+    // But 'an' can be a signed value in the DOS version. This means that
+    // we get a negative index and the lookups into finecosine/finesine
+    // end up dereferencing values in finetangent[].
+    // A player spawning on a deathmatch start facing directly west spawns
+    // "silently" with no spawn fog. Emulate this.
+    //
+    // This code is imported from PrBoom+.
+
+    {
+        fixed_t xa, ya;
+        signed int an;
+
+        // This calculation overflows in Vanilla Doom, but here we deliberately
+        // avoid integer overflow as it is undefined behavior, so the value of
+        // 'an' will always be positive.
+        an = (ANG45 >> ANGLETOFINESHIFT) * ((signed int) mthing->angle / 45);
+
+        switch (an)
+        {
+            case 4096:  // -4096:
+                xa = finetangent[2048];    // finecosine[-4096]
+                ya = finetangent[0];       // finesine[-4096]
+                break;
+            case 5120:  // -3072:
+                xa = finetangent[3072];    // finecosine[-3072]
+                ya = finetangent[1024];    // finesine[-3072]
+                break;
+            case 6144:  // -2048:
+                xa = finesine[0];          // finecosine[-2048]
+                ya = finetangent[2048];    // finesine[-2048]
+                break;
+            case 7168:  // -1024:
+                xa = finesine[1024];       // finecosine[-1024]
+                ya = finetangent[3072];    // finesine[-1024]
+                break;
+            case 0:
+            case 1024:
+            case 2048:
+            case 3072:
+                xa = finecosine[an];
+                ya = finesine[an];
+                break;
+            default:
+                I_Error("G_CheckSpot: unexpected angle %d\n", an);
+                xa = ya = 0;
+                break;
+        }
+        mo = P_SpawnMobj(x + 20 * xa, y + 20 * ya,
+                         ss->sector->floorheight, MT_TFOG);
+    }
+
     if (players[consoleplayer].viewz != 1) 
        S_StartSound (mo, sfx_telept);  // don't start sound on first frame 
  
@@ -1030,18 +1356,33 @@ void G_DoCompleted (void)
     if (automapactive) 
        AM_Stop (); 
        
-    if ( gamemode != commercial)
-       switch(gamemap)
-       {
-         case 8:
-           gameaction = ga_victory;
-           return;
-         case 9: 
-           for (i=0 ; i<MAXPLAYERS ; i++) 
-               players[i].didsecret = true; 
-           break;
-       }
-               
+    if (gamemode != commercial)
+    {
+        // Chex Quest ends after 5 levels, rather than 8.
+
+        if (gameversion == exe_chex)
+        {
+            if (gamemap == 5)
+            {
+                gameaction = ga_victory;
+                return;
+            }
+        }
+        else
+        {
+            switch(gamemap)
+            {
+              case 8:
+                gameaction = ga_victory;
+                return;
+              case 9: 
+                for (i=0 ; i<MAXPLAYERS ; i++) 
+                    players[i].didsecret = true; 
+                break;
+            }
+        }
+    }
+
 //#if 0  Hmmm - why?
     if ( (gamemap == 8)
         && (gamemode != commercial) ) 
@@ -1113,10 +1454,17 @@ void G_DoCompleted (void)
     wminfo.maxitems = totalitems; 
     wminfo.maxsecret = totalsecret; 
     wminfo.maxfrags = 0; 
-    if ( gamemode == commercial )
-       wminfo.partime = 35*cpars[gamemap-1]; 
+
+    // Set par time. Doom episode 4 doesn't have a par time, so this
+    // overflows into the cpars array. It's necessary to emulate this
+    // for statcheck regression testing.
+    if (gamemode == commercial)
+       wminfo.partime = TICRATE*cpars[gamemap-1];
+    else if (gameepisode < 4)
+       wminfo.partime = TICRATE*pars[gameepisode][gamemap];
     else
-       wminfo.partime = 35*pars[gameepisode][gamemap]; 
+        wminfo.partime = TICRATE*cpars[gamemap];
+
     wminfo.pnum = consoleplayer; 
  
     for (i=0 ; i<MAXPLAYERS ; i++) 
@@ -1133,10 +1481,9 @@ void G_DoCompleted (void)
     gamestate = GS_INTERMISSION; 
     viewactive = false; 
     automapactive = false; 
+
+    StatCopy(&wminfo);
  
-    if (statcopy)
-       memcpy (statcopy, &wminfo, sizeof(wminfo));
-       
     WI_Start (&wminfo); 
 } 
 
@@ -1191,7 +1538,7 @@ char      savename[256];
 
 void G_LoadGame (char* name) 
 { 
-    strcpy (savename, name); 
+    M_StringCopy(savename, name, sizeof(savename));
     gameaction = ga_loadgame; 
 } 
  
@@ -1199,57 +1546,49 @@ void G_LoadGame (char* name)
 
 
 void G_DoLoadGame (void) 
-{ 
-    //int              length; 
-    int                i; 
-    int                a,b,c; 
-    char       vcheck[VERSIONSIZE]; 
+{
+    int savedleveltime;
         
     gameaction = ga_nothing; 
         
-    //length = M_ReadFile (savename, &savebuffer); 
-    M_ReadFile (savename, &savebuffer); 
-    save_p = savebuffer + SAVESTRINGSIZE;
-    
-    // skip the description field 
-    memset (vcheck,0,sizeof(vcheck)); 
-    sprintf (vcheck,"version %i",VERSION); 
-    if (strcmp ((const char*)save_p, vcheck)) 
-       return;                         // bad version 
-    save_p += VERSIONSIZE; 
-                        
-    gameskill = *save_p++; 
-    gameepisode = *save_p++; 
-    gamemap = *save_p++; 
-    for (i=0 ; i<MAXPLAYERS ; i++) 
-       playeringame[i] = *save_p++; 
+    save_stream = fopen(savename, "rb");
+
+    if (save_stream == NULL)
+    {
+       return;
+    }
+
+    savegame_error = false;
+
+    if (!P_ReadSaveGameHeader())
+    {
+        fclose(save_stream);
+        return;
+    }
 
+    savedleveltime = leveltime;
+    
     // load a base level 
     G_InitNew (gameskill, gameepisode, gamemap); 
  
-    // get the times 
-    a = *save_p++; 
-    b = *save_p++; 
-    c = *save_p++; 
-    leveltime = (a<<16) + (b<<8) + c; 
-        
+    leveltime = savedleveltime;
+
     // dearchive all the modifications
     P_UnArchivePlayers (); 
     P_UnArchiveWorld (); 
     P_UnArchiveThinkers (); 
     P_UnArchiveSpecials (); 
  
-    if (*save_p != 0x1d) 
+    if (!P_ReadSaveGameEOF())
        I_Error ("Bad savegame");
+
+    fclose(save_stream);
     
-    // done 
-    Z_Free (savebuffer); 
     if (setsizeneeded)
-       R_ExecuteSetViewSize ();
+       R_ExecuteSetViewSize ();
     
     // draw the pattern into the back screen
-    R_FillBackScreen ();   
+    R_FillBackScreen (); 
 } 
  
 
@@ -1261,60 +1600,85 @@ void G_DoLoadGame (void)
 void
 G_SaveGame
 ( int  slot,
-  char*        description ) 
-{ 
-    savegameslot = slot; 
-    strcpy (savedescription, description); 
-    sendsave = true; 
-} 
+  char*        description )
+{
+    savegameslot = slot;
+    M_StringCopy(savedescription, description, sizeof(savedescription));
+    sendsave = true;
+}
+
 void G_DoSaveGame (void) 
 { 
-    char       name[100]; 
-    char       name2[VERSIONSIZE]; 
-    char*      description; 
-    int                length; 
-    int                i; 
-       
-    if (M_CheckParm("-cdrom"))
-       sprintf(name,"c:\\doomdata\\"SAVEGAMENAME"%d.dsg",savegameslot);
-    else
-       sprintf (name,SAVEGAMENAME"%d.dsg",savegameslot); 
-    description = savedescription; 
-        
-    save_p = savebuffer = screens[1]+0x4000; 
-        
-    memcpy (save_p, description, SAVESTRINGSIZE); 
-    save_p += SAVESTRINGSIZE; 
-    memset (name2,0,sizeof(name2)); 
-    sprintf (name2,"version %i",VERSION); 
-    memcpy (save_p, name2, VERSIONSIZE); 
-    save_p += VERSIONSIZE; 
-        
-    *save_p++ = gameskill; 
-    *save_p++ = gameepisode; 
-    *save_p++ = gamemap; 
-    for (i=0 ; i<MAXPLAYERS ; i++) 
-       *save_p++ = playeringame[i]; 
-    *save_p++ = leveltime>>16; 
-    *save_p++ = leveltime>>8; 
-    *save_p++ = leveltime; 
+    char *savegame_file;
+    char *temp_savegame_file;
+    char *recovery_savegame_file;
+
+    recovery_savegame_file = NULL;
+    temp_savegame_file = P_TempSaveGameFile();
+    savegame_file = P_SaveGameFile(savegameslot);
+
+    // Open the savegame file for writing.  We write to a temporary file
+    // and then rename it at the end if it was successfully written.
+    // This prevents an existing savegame from being overwritten by 
+    // a corrupted one, or if a savegame buffer overrun occurs.
+    save_stream = fopen(temp_savegame_file, "wb");
+
+    if (save_stream == NULL)
+    {
+        // Failed to save the game, so we're going to have to abort. But
+        // to be nice, save to somewhere else before we call I_Error().
+        recovery_savegame_file = M_TempFile("recovery.dsg");
+        save_stream = fopen(recovery_savegame_file, "wb");
+        if (save_stream == NULL)
+        {
+            I_Error("Failed to open either '%s' or '%s' to write savegame.",
+                    temp_savegame_file, recovery_savegame_file);
+        }
+    }
+
+    savegame_error = false;
+
+    P_WriteSaveGameHeader(savedescription);
  
     P_ArchivePlayers (); 
     P_ArchiveWorld (); 
     P_ArchiveThinkers (); 
     P_ArchiveSpecials (); 
         
-    *save_p++ = 0x1d;          // consistancy marker 
+    P_WriteSaveGameEOF();
         
-    length = save_p - savebuffer; 
-    if (length > SAVEGAMESIZE) 
-       I_Error ("Savegame buffer overrun"); 
-    M_WriteFile (name, savebuffer, length); 
-    gameaction = ga_nothing; 
-    savedescription[0] = 0;             
-        
-    players[consoleplayer].message = GGSAVED; 
+    // Enforce the same savegame size limit as in Vanilla Doom, 
+    // except if the vanilla_savegame_limit setting is turned off.
+
+    if (vanilla_savegame_limit && ftell(save_stream) > SAVEGAMESIZE)
+    {
+        I_Error ("Savegame buffer overrun");
+    }
+    
+    // Finish up, close the savegame file.
+
+    fclose(save_stream);
+
+    if (recovery_savegame_file != NULL)
+    {
+        // We failed to save to the normal location, but we wrote a
+        // recovery file to the temp directory. Now we can bomb out
+        // with an error.
+        I_Error("Failed to open savegame file '%s' for writing.\n"
+                "But your game has been saved to '%s' for recovery.",
+                temp_savegame_file, recovery_savegame_file);
+    }
+
+    // Now rename the temporary savegame file to the actual savegame
+    // file, overwriting the old savegame if there was one there.
+
+    remove(savegame_file);
+    rename(temp_savegame_file, savegame_file);
+    
+    gameaction = ga_nothing;
+    M_StringCopy(savedescription, "", sizeof(savedescription));
+
+    players[consoleplayer].message = DEH_String(GGSAVED);
 
     // draw the pattern into the back screen
     R_FillBackScreen ();       
@@ -1358,34 +1722,34 @@ void G_DoNewGame (void)
     gameaction = ga_nothing; 
 } 
 
-// The sky texture to be used instead of the F_SKY1 dummy.
-extern  int    skytexture; 
-
 
 void
 G_InitNew
 ( skill_t      skill,
   int          episode,
-  int          map ) 
-{ 
-    int             i; 
-        
-    if (paused) 
-    { 
-       paused = false; 
-       S_ResumeSound (); 
-    } 
-       
+  int          map )
+{
+    char *skytexturename;
+    int             i;
 
-    if (skill > sk_nightmare) 
-       skill = sk_nightmare;
+    if (paused)
+    {
+       paused = false;
+       S_ResumeSound ();
+    }
 
+    /*
+    // Note: This commented-out block of code was added at some point
+    // between the DOS version(s) and the Doom source release. It isn't
+    // found in disassemblies of the DOS version and causes IDCLEV and
+    // the -warp command line parameter to behave differently.
+    // This is left here for posterity.
 
     // This was quite messy with SPECIAL and commented parts.
     // Supposedly hacks to make the latest edition work.
     // It might not work properly.
     if (episode < 1)
-      episode = 1; 
+      episode = 1;
 
     if ( gamemode == retail )
     {
@@ -1394,94 +1758,136 @@ G_InitNew
     }
     else if ( gamemode == shareware )
     {
-      if (episode > 1) 
+      if (episode > 1)
           episode = 1; // only start episode 1 on shareware
-    }  
+    }
     else
     {
       if (episode > 3)
        episode = 3;
     }
-    
+    */
+
+    if (skill > sk_nightmare)
+       skill = sk_nightmare;
 
-  
-    if (map < 1) 
+    if (gameversion >= exe_ultimate)
+    {
+        if (episode == 0)
+        {
+            episode = 4;
+        }
+    }
+    else
+    {
+        if (episode < 1)
+        {
+            episode = 1;
+        }
+        if (episode > 3)
+        {
+            episode = 3;
+        }
+    }
+
+    if (episode > 1 && gamemode == shareware)
+    {
+        episode = 1;
+    }
+
+    if (map < 1)
        map = 1;
-    
+
     if ( (map > 9)
         && ( gamemode != commercial) )
-      map = 9; 
-                
-    M_ClearRandom (); 
-        
+      map = 9;
+
+    M_ClearRandom ();
+
     if (skill == sk_nightmare || respawnparm )
        respawnmonsters = true;
     else
        respawnmonsters = false;
-               
+
     if (fastparm || (skill == sk_nightmare && gameskill != sk_nightmare) )
-    { 
-       for (i=S_SARG_RUN1 ; i<=S_SARG_PAIN2 ; i++) 
-           states[i].tics >>= 1; 
-       mobjinfo[MT_BRUISERSHOT].speed = 20*FRACUNIT; 
-       mobjinfo[MT_HEADSHOT].speed = 20*FRACUNIT; 
-       mobjinfo[MT_TROOPSHOT].speed = 20*FRACUNIT; 
-    } 
-    else if (skill != sk_nightmare && gameskill == sk_nightmare) 
-    { 
-       for (i=S_SARG_RUN1 ; i<=S_SARG_PAIN2 ; i++) 
-           states[i].tics <<= 1; 
-       mobjinfo[MT_BRUISERSHOT].speed = 15*FRACUNIT; 
-       mobjinfo[MT_HEADSHOT].speed = 10*FRACUNIT; 
-       mobjinfo[MT_TROOPSHOT].speed = 10*FRACUNIT; 
-    } 
-        
-                        
-    // force players to be initialized upon first level load         
-    for (i=0 ; i<MAXPLAYERS ; i++) 
-       players[i].playerstate = PST_REBORN; 
-    usergame = true;                // will be set false if a demo 
-    paused = false; 
-    demoplayback = false; 
-    automapactive = false; 
-    viewactive = true; 
-    gameepisode = episode; 
-    gamemap = map; 
-    gameskill = skill; 
+    {
+       for (i=S_SARG_RUN1 ; i<=S_SARG_PAIN2 ; i++)
+           states[i].tics >>= 1;
+       mobjinfo[MT_BRUISERSHOT].speed = 20*FRACUNIT;
+       mobjinfo[MT_HEADSHOT].speed = 20*FRACUNIT;
+       mobjinfo[MT_TROOPSHOT].speed = 20*FRACUNIT;
+    }
+    else if (skill != sk_nightmare && gameskill == sk_nightmare)
+    {
+       for (i=S_SARG_RUN1 ; i<=S_SARG_PAIN2 ; i++)
+           states[i].tics <<= 1;
+       mobjinfo[MT_BRUISERSHOT].speed = 15*FRACUNIT;
+       mobjinfo[MT_HEADSHOT].speed = 10*FRACUNIT;
+       mobjinfo[MT_TROOPSHOT].speed = 10*FRACUNIT;
+    }
+
+    // force players to be initialized upon first level load
+    for (i=0 ; i<MAXPLAYERS ; i++)
+       players[i].playerstate = PST_REBORN;
+
+    usergame = true;                // will be set false if a demo
+    paused = false;
+    demoplayback = false;
+    automapactive = false;
     viewactive = true;
-    
-    // set the sky map for the episode
-    if ( gamemode == commercial)
+    gameepisode = episode;
+    gamemap = map;
+    gameskill = skill;
+
+    viewactive = true;
+
+    // Set the sky to use.
+    //
+    // Note: This IS broken, but it is how Vanilla Doom behaves.
+    // See http://doomwiki.org/wiki/Sky_never_changes_in_Doom_II.
+    //
+    // Because we set the sky here at the start of a game, not at the
+    // start of a level, the sky texture never changes unless we
+    // restore from a saved game.  This was fixed before the Doom
+    // source release, but this IS the way Vanilla DOS Doom behaves.
+
+    if (gamemode == commercial)
     {
-       skytexture = R_TextureNumForName ("SKY3");
-       if (gamemap < 12)
-           skytexture = R_TextureNumForName ("SKY1");
-       else
-           if (gamemap < 21)
-               skytexture = R_TextureNumForName ("SKY2");
+        if (gamemap < 12)
+            skytexturename = "SKY1";
+        else if (gamemap < 21)
+            skytexturename = "SKY2";
+        else
+            skytexturename = "SKY3";
     }
     else
-       switch (episode) 
-       { 
-         case 1: 
-           skytexture = R_TextureNumForName ("SKY1"); 
-           break; 
-         case 2: 
-           skytexture = R_TextureNumForName ("SKY2"); 
-           break; 
-         case 3: 
-           skytexture = R_TextureNumForName ("SKY3"); 
-           break; 
-         case 4:       // Special Edition sky
-           skytexture = R_TextureNumForName ("SKY4");
-           break;
-       } 
-    G_DoLoadLevel (); 
-} 
+    {
+        switch (gameepisode)
+        {
+          default:
+          case 1:
+            skytexturename = "SKY1";
+            break;
+          case 2:
+            skytexturename = "SKY2";
+            break;
+          case 3:
+            skytexturename = "SKY3";
+            break;
+          case 4:        // Special Edition sky
+            skytexturename = "SKY4";
+            break;
+        }
+    }
+
+    skytexturename = DEH_String(skytexturename);
+
+    skytexture = R_TextureNumForName(skytexturename);
+
+
+    G_DoLoadLevel ();
+}
+
 
 //
 // DEMO RECORDING 
@@ -1499,25 +1905,98 @@ void G_ReadDemoTiccmd (ticcmd_t* cmd)
     } 
     cmd->forwardmove = ((signed char)*demo_p++); 
     cmd->sidemove = ((signed char)*demo_p++); 
-    cmd->angleturn = ((unsigned char)*demo_p++)<<8; 
+
+    // If this is a longtics demo, read back in higher resolution
+
+    if (longtics)
+    {
+        cmd->angleturn = *demo_p++;
+        cmd->angleturn |= (*demo_p++) << 8;
+    }
+    else
+    {
+        cmd->angleturn = ((unsigned char) *demo_p++)<<8; 
+    }
+
     cmd->buttons = (unsigned char)*demo_p++; 
 } 
 
+// Increase the size of the demo buffer to allow unlimited demos
+
+static void IncreaseDemoBuffer(void)
+{
+    int current_length;
+    byte *new_demobuffer;
+    byte *new_demop;
+    int new_length;
+
+    // Find the current size
+
+    current_length = demoend - demobuffer;
+    
+    // Generate a new buffer twice the size
+    new_length = current_length * 2;
+    
+    new_demobuffer = Z_Malloc(new_length, PU_STATIC, 0);
+    new_demop = new_demobuffer + (demo_p - demobuffer);
+
+    // Copy over the old data
+
+    memcpy(new_demobuffer, demobuffer, current_length);
+
+    // Free the old buffer and point the demo pointers at the new buffer.
+
+    Z_Free(demobuffer);
+
+    demobuffer = new_demobuffer;
+    demo_p = new_demop;
+    demoend = demobuffer + new_length;
+}
 
 void G_WriteDemoTiccmd (ticcmd_t* cmd) 
 { 
-    if (gamekeydown['q'])           // press q to end demo recording 
+    byte *demo_start;
+
+    if (gamekeydown[key_demo_quit])           // press q to end demo recording 
        G_CheckDemoStatus (); 
+
+    demo_start = demo_p;
+
     *demo_p++ = cmd->forwardmove; 
     *demo_p++ = cmd->sidemove; 
-    *demo_p++ = (cmd->angleturn+128)>>8; 
+
+    // If this is a longtics demo, record in higher resolution
+    if (longtics)
+    {
+        *demo_p++ = (cmd->angleturn & 0xff);
+        *demo_p++ = (cmd->angleturn >> 8) & 0xff;
+    }
+    else
+    {
+        *demo_p++ = cmd->angleturn >> 8; 
+    }
+
     *demo_p++ = cmd->buttons; 
-    demo_p -= 4; 
+
+    // reset demo pointer back
+    demo_p = demo_start;
+
     if (demo_p > demoend - 16)
     {
-       // no more space 
-       G_CheckDemoStatus (); 
-       return; 
+        if (vanilla_demo_limit)
+        {
+            // no more space 
+            G_CheckDemoStatus (); 
+            return; 
+        }
+        else
+        {
+            // Vanilla demo limit disabled: unlimited
+            // demo lengths!
+
+            IncreaseDemoBuffer();
+        }
     } 
        
     G_ReadDemoTiccmd (cmd);         // make SURE it is exactly the same 
@@ -1526,34 +2005,85 @@ void G_WriteDemoTiccmd (ticcmd_t* cmd)
  
  
 //
-// G_RecordDemo 
-// 
-void G_RecordDemo (char* name) 
-{ 
-    int             i; 
-    int                                maxsize;
-       
-    usergame = false; 
-    strcpy (demoname, name); 
-    strcat (demoname, ".lmp"); 
+// G_RecordDemo
+//
+void G_RecordDemo (char *name)
+{
+    size_t demoname_size;
+    int i;
+    int maxsize;
+
+    usergame = false;
+    demoname_size = strlen(name) + 5;
+    demoname = Z_Malloc(demoname_size, PU_STATIC, NULL);
+    M_snprintf(demoname, demoname_size, "%s.lmp", name);
     maxsize = 0x20000;
-    i = M_CheckParm ("-maxdemo");
-    if (i && i<myargc-1)
+
+    //!
+    // @arg <size>
+    // @category demo
+    // @vanilla
+    //
+    // Specify the demo buffer size (KiB)
+    //
+
+    i = M_CheckParmWithArgs("-maxdemo", 1);
+    if (i)
        maxsize = atoi(myargv[i+1])*1024;
     demobuffer = Z_Malloc (maxsize,PU_STATIC,NULL); 
     demoend = demobuffer + maxsize;
        
     demorecording = true; 
 } 
+
+// Get the demo version code appropriate for the version set in gameversion.
+int G_VanillaVersionCode(void)
+{
+    switch (gameversion)
+    {
+        case exe_doom_1_2:
+            I_Error("Doom 1.2 does not have a version code!");
+        case exe_doom_1_666:
+            return 106;
+        case exe_doom_1_7:
+            return 107;
+        case exe_doom_1_8:
+            return 108;
+        case exe_doom_1_9:
+        default:  // All other versions are variants on v1.9:
+            return 109;
+    }
+}
+
 void G_BeginRecording (void) 
 { 
     int             i; 
-               
+
+    //!
+    // @category demo
+    //
+    // Record a high resolution "Doom 1.91" demo.
+    //
+
+    longtics = M_CheckParm("-longtics") != 0;
+
+    // If not recording a longtics demo, record in low res
+
+    lowres_turn = !longtics;
+    
     demo_p = demobuffer;
        
-    *demo_p++ = VERSION;
+    // Save the right version code for this demo
+    if (longtics)
+    {
+        *demo_p++ = DOOM_191_VERSION;
+    }
+    else
+    {
+        *demo_p++ = G_VanillaVersionCode();
+    }
+
     *demo_p++ = gameskill; 
     *demo_p++ = gameepisode; 
     *demo_p++ = gamemap; 
@@ -1579,19 +2109,79 @@ void G_DeferedPlayDemo (char* name)
     defdemoname = name; 
     gameaction = ga_playdemo; 
 } 
+
+// Generate a string describing a demo version
+
+static char *DemoVersionDescription(int version)
+{
+    static char resultbuf[16];
+
+    switch (version)
+    {
+        case 104:
+            return "v1.4";
+        case 105:
+            return "v1.5";
+        case 106:
+            return "v1.6/v1.666";
+        case 107:
+            return "v1.7/v1.7a";
+        case 108:
+            return "v1.8";
+        case 109:
+            return "v1.9";
+        default:
+            break;
+    }
+
+    // Unknown version.  Perhaps this is a pre-v1.4 IWAD?  If the version
+    // byte is in the range 0-4 then it can be a v1.0-v1.2 demo.
+
+    if (version >= 0 && version <= 4)
+    {
+        return "v1.0/v1.1/v1.2";
+    }
+    else
+    {
+        M_snprintf(resultbuf, sizeof(resultbuf),
+                   "%i.%i (unknown)", version / 100, version % 100);
+        return resultbuf;
+    }
+}
+
 void G_DoPlayDemo (void) 
 { 
     skill_t skill; 
     int             i, episode, map; 
+    int demoversion;
         
     gameaction = ga_nothing; 
     demobuffer = demo_p = W_CacheLumpName (defdemoname, PU_STATIC); 
-    if ( *demo_p++ != VERSION)
+
+    demoversion = *demo_p++;
+
+    if (demoversion == G_VanillaVersionCode())
+    {
+        longtics = false;
+    }
+    else if (demoversion == DOOM_191_VERSION)
+    {
+        // demo recorded with cph's modified "v1.91" doom exe
+        longtics = true;
+    }
+    else
     {
-      fprintf( stderr, "Demo is from a different game version! - Trying anyway...\n");
-      //gameaction = ga_nothing;
-      //return;
+        char *message = "Demo is from a different game version!\n"
+                        "(read %i, should be %i)\n"
+                        "\n"
+                        "*** You may need to upgrade your version "
+                            "of Doom to v1.9. ***\n"
+                        "    See: https://www.doomworld.com/classicdoom"
+                                  "/info/patches.php\n"
+                        "    This appears to be %s.";
+
+        I_Error(message, demoversion, G_VanillaVersionCode(),
+                         DemoVersionDescription(demoversion));
     }
     
     skill = *demo_p++; 
@@ -1605,16 +2195,19 @@ void G_DoPlayDemo (void)
        
     for (i=0 ; i<MAXPLAYERS ; i++) 
        playeringame[i] = *demo_p++; 
-    if (playeringame[1]) 
-    { 
-       netgame = true; 
-       netdemo = true; 
+
+    if (playeringame[1] || M_CheckParm("-solo-net") > 0
+                        || M_CheckParm("-netdemo") > 0)
+    {
+       netgame = true;
+       netdemo = true;
     }
 
     // don't spend a lot of time in loadlevel 
     precache = false;
     G_InitNew (skill, episode, map); 
     precache = true; 
+    starttime = I_GetTime (); 
 
     usergame = false; 
     demoplayback = true; 
@@ -1624,9 +2217,15 @@ void G_DoPlayDemo (void)
 // G_TimeDemo 
 //
 void G_TimeDemo (char* name) 
-{       
+{
+    //!
+    // @vanilla 
+    //
+    // Disable rendering the screen entirely.
+    //
+
     nodrawers = M_CheckParm ("-nodraw"); 
-    noblit = M_CheckParm ("-noblit"); 
+
     timingdemo = true; 
     singletics = true; 
 
@@ -1651,17 +2250,24 @@ boolean G_CheckDemoStatus (void)
         
     if (timingdemo) 
     { 
+        float fps;
+        int realtics;
+
        endtime = I_GetTime (); 
-       I_Error ("timed %i gametics in %i realtics",gametic 
-                , endtime-starttime); 
+        realtics = endtime - starttime;
+        fps = ((float) gametic * TICRATE) / realtics;
+
+        // Prevent recursive calls
+        timingdemo = false;
+        demoplayback = false;
+
+       I_Error ("timed %i gametics in %i realtics (%f fps)",
+                 gametic, realtics, fps);
     } 
         
     if (demoplayback) 
     { 
-       if (singledemo) 
-           I_Quit (); 
-                        
-       Z_ChangeTag (demobuffer, PU_CACHE); 
+        W_ReleaseLumpName(defdemoname);
        demoplayback = false; 
        netdemo = false;
        netgame = false;
@@ -1671,7 +2277,12 @@ boolean G_CheckDemoStatus (void)
        fastparm = false;
        nomonsters = false;
        consoleplayer = 0;
-       D_AdvanceDemo (); 
+        
+        if (singledemo) 
+            I_Quit (); 
+        else 
+            D_AdvanceDemo (); 
+
        return true; 
     } 
  
index d84916ce8eaffd3453a4d783f7f4208df196e235..da0df39b147332d9ea0c182c6fb6bde254f00e31 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //   Duh.
 // 
-//-----------------------------------------------------------------------------
 
 
 #ifndef __G_GAME__
@@ -25,7 +22,7 @@
 
 #include "doomdef.h"
 #include "d_event.h"
-
+#include "d_ticcmd.h"
 
 
 //
@@ -65,15 +62,19 @@ void G_SecretExitLevel (void);
 
 void G_WorldDone (void);
 
+// Read current data from inputs and build a player movement command.
+
+void G_BuildTiccmd (ticcmd_t *cmd, int maketic); 
+
 void G_Ticker (void);
 boolean G_Responder (event_t*  ev);
 
 void G_ScreenShot (void);
 
+void G_DrawMouseSpeedBox(void);
+int G_VanillaVersionCode(void);
 
+extern int vanilla_savegame_limit;
+extern int vanilla_demo_limit;
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
+
diff --git a/frosted-doom/gusconf.c b/frosted-doom/gusconf.c
new file mode 100644 (file)
index 0000000..70cdd87
--- /dev/null
@@ -0,0 +1,271 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//     GUS emulation code.
+//
+//     Actually emulating a GUS is far too much work; fortunately
+//     GUS "emulation" already exists in the form of Timidity, which
+//     supports GUS patch files. This code therefore converts Doom's
+//     DMXGUS lump into an equivalent Timidity configuration file.
+//
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "w_wad.h"
+#include "z_zone.h"
+
+#define MAX_INSTRUMENTS 256
+
+typedef struct
+{
+    char *patch_names[MAX_INSTRUMENTS];
+    int mapping[MAX_INSTRUMENTS];
+} gus_config_t;
+
+char *gus_patch_path = "";
+unsigned int gus_ram_kb = 1024;
+
+static unsigned int MappingIndex(void)
+{
+    unsigned int result = gus_ram_kb / 256;
+
+    if (result < 1)
+    {
+        return 1;
+    }
+    else if (result > 4)
+    {
+        return 4;
+    }
+    else
+    {
+        return result;
+    }
+}
+
+static int SplitLine(char *line, char **fields, unsigned int max_fields)
+{
+    unsigned int num_fields;
+    char *p;
+
+    fields[0] = line;
+    num_fields = 1;
+
+    for (p = line; *p != '\0'; ++p)
+    {
+        if (*p == ',')
+        {
+            *p = '\0';
+
+            // Skip spaces following the comma.
+            do
+            {
+                ++p;
+            } while (*p != '\0' && isspace(*p));
+
+            fields[num_fields] = p;
+            ++num_fields;
+            --p;
+
+            if (num_fields >= max_fields)
+            {
+                break;
+            }
+        }
+        else if (*p == '#')
+        {
+            *p = '\0';
+            break;
+        }
+    }
+
+    // Strip off trailing whitespace from the end of the line.
+    p = fields[num_fields - 1] + strlen(fields[num_fields - 1]);
+    while (p > fields[num_fields - 1] && isspace(*(p - 1)))
+    {
+        --p;
+        *p = '\0';
+    }
+
+    return num_fields;
+}
+
+static void ParseLine(gus_config_t *config, char *line)
+{
+    char *fields[6];
+    unsigned int num_fields;
+    unsigned int instr_id, mapped_id;
+
+    num_fields = SplitLine(line, fields, 6);
+
+    if (num_fields < 6)
+    {
+        return;
+    }
+
+    instr_id = atoi(fields[0]);
+    mapped_id = atoi(fields[MappingIndex()]);
+
+    free(config->patch_names[instr_id]);
+    config->patch_names[instr_id] = strdup(fields[5]);
+    config->mapping[instr_id] = mapped_id;
+}
+
+static void ParseDMXConfig(char *dmxconf, gus_config_t *config)
+{
+    char *p, *newline;
+    unsigned int i;
+
+    memset(config, 0, sizeof(gus_config_t));
+
+    for (i = 0; i < MAX_INSTRUMENTS; ++i)
+    {
+        config->mapping[i] = -1;
+    }
+
+    p = dmxconf;
+
+    for (;;)
+    {
+        newline = strchr(p, '\n');
+
+        if (newline != NULL)
+        {
+            *newline = '\0';
+        }
+
+        ParseLine(config, p);
+
+        if (newline == NULL)
+        {
+            break;
+        }
+        else
+        {
+            p = newline + 1;
+        }
+    }
+}
+
+static void FreeDMXConfig(gus_config_t *config)
+{
+    unsigned int i;
+
+    for (i = 0; i < MAX_INSTRUMENTS; ++i)
+    {
+        free(config->patch_names[i]);
+    }
+}
+
+static char *ReadDMXConfig(void)
+{
+    int lumpnum;
+    unsigned int len;
+    char *data;
+
+    // TODO: This should be chosen based on gamemode == commercial:
+
+    lumpnum = W_CheckNumForName("DMXGUS");
+
+    if (lumpnum < 0)
+    {
+        lumpnum = W_GetNumForName("DMXGUSC");
+    }
+
+    len = W_LumpLength(lumpnum);
+    data = Z_Malloc(len + 1, PU_STATIC, NULL);
+    W_ReadLump(lumpnum, data);
+
+    return data;
+}
+
+static boolean WriteTimidityConfig(char *path, gus_config_t *config)
+{
+    FILE *fstream;
+    unsigned int i;
+
+    fstream = fopen(path, "w");
+
+    if (fstream == NULL)
+    {
+        return false;
+    }
+
+    fprintf(fstream, "# Autogenerated Timidity config.\n\n");
+
+    fprintf(fstream, "dir %s\n", gus_patch_path);
+
+    fprintf(fstream, "\nbank 0\n\n");
+
+    for (i = 0; i < 128; ++i)
+    {
+        if (config->mapping[i] >= 0 && config->mapping[i] < MAX_INSTRUMENTS
+         && config->patch_names[config->mapping[i]] != NULL)
+        {
+            fprintf(fstream, "%i %s\n",
+                    i, config->patch_names[config->mapping[i]]);
+        }
+    }
+
+    fprintf(fstream, "\ndrumset 0\n\n");
+
+    for (i = 128 + 25; i < MAX_INSTRUMENTS; ++i)
+    {
+        if (config->mapping[i] >= 0 && config->mapping[i] < MAX_INSTRUMENTS
+         && config->patch_names[config->mapping[i]] != NULL)
+        {
+            fprintf(fstream, "%i %s\n",
+                    i - 128, config->patch_names[config->mapping[i]]);
+        }
+    }
+
+    fprintf(fstream, "\n");
+
+    fclose(fstream);
+
+    return true;
+}
+
+boolean GUS_WriteConfig(char *path)
+{
+    boolean result;
+    char *dmxconf;
+    gus_config_t config;
+
+    if (!strcmp(gus_patch_path, ""))
+    {
+        printf("You haven't configured gus_patch_path.\n");
+        printf("gus_patch_path needs to point to the location of "
+               "your GUS patch set.\n"
+               "To get a copy of the \"standard\" GUS patches, "
+               "download a copy of dgguspat.zip.\n");
+
+        return false;
+    }
+
+    dmxconf = ReadDMXConfig();
+    ParseDMXConfig(dmxconf, &config);
+
+    result = WriteTimidityConfig(path, &config);
+
+    FreeDMXConfig(&config);
+    Z_Free(dmxconf);
+
+    return result;
+}
+
diff --git a/frosted-doom/gusconf.h b/frosted-doom/gusconf.h
new file mode 100644 (file)
index 0000000..e012426
--- /dev/null
@@ -0,0 +1,29 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//     GUS emulation code.
+//
+
+#ifndef __GUSCONF_H__
+#define __GUSCONF_H__
+
+#include "doomtype.h"
+
+extern char *gus_patch_path;
+extern unsigned int gus_ram_kb;
+
+boolean GUS_WriteConfig(char *path);
+
+#endif /* #ifndef __GUSCONF_H__ */
+
index 57fb52e4fe54e97eea6605926b8dff3d193d9541..47038a0439cfba8e3b02de3072476f8ff0516526 100644 (file)
@@ -1,34 +1,28 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:  heads-up text and input code
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: hu_lib.c,v 1.3 1997/01/26 07:44:58 b1 Exp $";
 
 #include <ctype.h>
 
 #include "doomdef.h"
+#include "doomkeys.h"
 
 #include "v_video.h"
-#include "m_swap.h"
+#include "i_swap.h"
 
 #include "hu_lib.h"
 #include "r_local.h"
@@ -111,7 +105,7 @@ HUlib_drawTextLine
     x = l->x;
     for (i=0;i<l->len;i++)
     {
-       c = toupper(l->l[i]);
+       c = toupper((int)l->l[i]);
        if (c != ' '
            && c >= l->sc
            && c <= '_')
@@ -119,7 +113,7 @@ HUlib_drawTextLine
            w = SHORT(l->f[c - l->sc]->width);
            if (x+w > SCREENWIDTH)
                break;
-           V_DrawPatchDirect(x, l->y, FG, l->f[c - l->sc]);
+           V_DrawPatchDirect(x, l->y, l->f[c - l->sc]);
            x += w;
        }
        else
@@ -134,7 +128,7 @@ HUlib_drawTextLine
     if (drawcursor
        && x + SHORT(l->f['_' - l->sc]->width) <= SCREENWIDTH)
     {
-       V_DrawPatchDirect(x, l->y, FG, l->f['_' - l->sc]);
+       V_DrawPatchDirect(x, l->y, l->f['_' - l->sc]);
     }
 }
 
@@ -145,7 +139,6 @@ void HUlib_eraseTextLine(hu_textline_t* l)
     int                        lh;
     int                        y;
     int                        yoffset;
-    //static boolean   lastautomapactive = true;
 
     // Only erases when NOT in automap and the screen is reduced,
     // and the text must either need updating or refreshing
@@ -168,7 +161,6 @@ void HUlib_eraseTextLine(hu_textline_t* l)
        }
     }
 
-    //lastautomapactive = automapactive;
     if (l->needsupdate) l->needsupdate--;
 
 }
@@ -319,6 +311,7 @@ HUlib_keyInIText
 ( hu_itext_t*  it,
   unsigned char ch )
 {
+    ch = toupper(ch);
 
     if (ch >= ' ' && ch <= '_') 
        HUlib_addCharToTextLine(&it->l, (char) ch);
index 8b809dff2ee72157c1257af8b94c67396a1cd43f..8f0994e60e890646457a3c081418fde3a0673b79 100644 (file)
@@ -1,22 +1,19 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:  none
 //
-//-----------------------------------------------------------------------------
 
 #ifndef __HULIB__
 #define __HULIB__
 // We are referring to patches.
 #include "r_defs.h"
 
-
-// background and foreground screen numbers
-// different from other modules.
-#define BG                     1
-#define FG                     0
-
 // font stuff
 #define HU_CHARERASE   KEY_BACKSPACE
 
@@ -189,8 +180,3 @@ void HUlib_drawIText(hu_itext_t* it);
 void HUlib_eraseIText(hu_itext_t* it); 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index efb1396710c86910c31f159b2641c4665267915f..b63cac7659eb92c14c90744fc810057f173225d3 100644 (file)
@@ -1,38 +1,36 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:  Heads-up displays
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: hu_stuff.c,v 1.4 1997/02/03 16:47:52 b1 Exp $";
 
 #include <ctype.h>
 
 #include "doomdef.h"
+#include "doomkeys.h"
 
 #include "z_zone.h"
 
-#include "m_swap.h"
+#include "deh_main.h"
+#include "i_swap.h"
+#include "i_video.h"
 
 #include "hu_stuff.h"
 #include "hu_lib.h"
+#include "m_controls.h"
+#include "m_misc.h"
 #include "w_wad.h"
 
 #include "s_sound.h"
@@ -47,9 +45,10 @@ rcsid[] = "$Id: hu_stuff.c,v 1.4 1997/02/03 16:47:52 b1 Exp $";
 // Locally used constants, shortcuts.
 //
 #define HU_TITLE       (mapnames[(gameepisode-1)*9+gamemap-1])
-#define HU_TITLE2      (mapnames2[gamemap-1])
-#define HU_TITLEP      (mapnamesp[gamemap-1])
-#define HU_TITLET      (mapnamest[gamemap-1])
+#define HU_TITLE2      (mapnames_commercial[gamemap-1])
+#define HU_TITLEP      (mapnames_commercial[gamemap-1 + 32])
+#define HU_TITLET      (mapnames_commercial[gamemap-1 + 64])
+#define HU_TITLE_CHEX   (mapnames[gamemap - 1])
 #define HU_TITLEHEIGHT 1
 #define HU_TITLEX      0
 #define HU_TITLEY      (167 - SHORT(hu_font[0]->height))
@@ -62,7 +61,7 @@ rcsid[] = "$Id: hu_stuff.c,v 1.4 1997/02/03 16:47:52 b1 Exp $";
 
 
 
-char*  chat_macros[] =
+char *chat_macros[10] =
 {
     HUSTR_CHATMACRO0,
     HUSTR_CHATMACRO1,
@@ -84,7 +83,6 @@ char* player_names[] =
     HUSTR_PLRRED
 };
 
-
 char                   chat_char; // remove later.
 static player_t*       plr;
 patch_t*               hu_font[HU_FONTSIZE];
@@ -103,7 +101,6 @@ static hu_stext_t   w_message;
 static int             message_counter;
 
 extern int             showMessages;
-extern boolean         automapactive;
 
 static boolean         headsupactive = false;
 
@@ -166,8 +163,16 @@ char*      mapnames[] =    // DOOM shareware/registered/retail (Ultimate) names.
     "NEWLEVEL"
 };
 
-char*  mapnames2[] =   // DOOM 2 map names.
+// List of names for levels in commercial IWADs
+// (doom2.wad, plutonia.wad, tnt.wad).  These are stored in a
+// single large array; WADs like pl2.wad have a MAP33, and rely on
+// the layout in the Vanilla executable, where it is possible to
+// overflow the end of one array into the next.
+
+char *mapnames_commercial[] =
 {
+    // DOOM 2 map names.
+
     HUSTR_1,
     HUSTR_2,
     HUSTR_3,
@@ -201,12 +206,10 @@ char*     mapnames2[] =   // DOOM 2 map names.
     HUSTR_29,
     HUSTR_30,
     HUSTR_31,
-    HUSTR_32
-};
+    HUSTR_32,
 
+    // Plutonia WAD map names.
 
-char*  mapnamesp[] =   // Plutonia WAD map names.
-{
     PHUSTR_1,
     PHUSTR_2,
     PHUSTR_3,
@@ -240,12 +243,10 @@ char*     mapnamesp[] =   // Plutonia WAD map names.
     PHUSTR_29,
     PHUSTR_30,
     PHUSTR_31,
-    PHUSTR_32
-};
-
+    PHUSTR_32,
+    
+    // TNT WAD map names.
 
-char *mapnamest[] =    // TNT WAD map names.
-{
     THUSTR_1,
     THUSTR_2,
     THUSTR_3,
@@ -282,113 +283,6 @@ char *mapnamest[] =       // TNT WAD map names.
     THUSTR_32
 };
 
-
-const char*    shiftxform;
-
-const char french_shiftxform[] =
-{
-    0,
-    1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
-    11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
-    21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
-    31,
-    ' ', '!', '"', '#', '$', '%', '&',
-    '"', // shift-'
-    '(', ')', '*', '+',
-    '?', // shift-,
-    '_', // shift--
-    '>', // shift-.
-    '?', // shift-/
-    '0', // shift-0
-    '1', // shift-1
-    '2', // shift-2
-    '3', // shift-3
-    '4', // shift-4
-    '5', // shift-5
-    '6', // shift-6
-    '7', // shift-7
-    '8', // shift-8
-    '9', // shift-9
-    '/',
-    '.', // shift-;
-    '<',
-    '+', // shift-=
-    '>', '?', '@',
-    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
-    'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
-    '[', // shift-[
-    '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK
-    ']', // shift-]
-    '"', '_',
-    '\'', // shift-`
-    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
-    'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
-    '{', '|', '}', '~', 127
-
-};
-
-const char english_shiftxform[] =
-{
-
-    0,
-    1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
-    11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
-    21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
-    31,
-    ' ', '!', '"', '#', '$', '%', '&',
-    '"', // shift-'
-    '(', ')', '*', '+',
-    '<', // shift-,
-    '_', // shift--
-    '>', // shift-.
-    '?', // shift-/
-    ')', // shift-0
-    '!', // shift-1
-    '@', // shift-2
-    '#', // shift-3
-    '$', // shift-4
-    '%', // shift-5
-    '^', // shift-6
-    '&', // shift-7
-    '*', // shift-8
-    '(', // shift-9
-    ':',
-    ':', // shift-;
-    '<',
-    '+', // shift-=
-    '>', '?', '@',
-    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
-    'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
-    '[', // shift-[
-    '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK
-    ']', // shift-]
-    '"', '_',
-    '\'', // shift-`
-    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
-    'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
-    '{', '|', '}', '~', 127
-};
-
-char frenchKeyMap[128]=
-{
-    0,
-    1,2,3,4,5,6,7,8,9,10,
-    11,12,13,14,15,16,17,18,19,20,
-    21,22,23,24,25,26,27,28,29,30,
-    31,
-    ' ','!','"','#','$','%','&','%','(',')','*','+',';','-',':','!',
-    '0','1','2','3','4','5','6','7','8','9',':','M','<','=','>','?',
-    '@','Q','B','C','D','E','F','G','H','I','J','K','L',',','N','O',
-    'P','A','R','S','T','U','V','Z','X','Y','W','^','\\','$','^','_',
-    '@','Q','B','C','D','E','F','G','H','I','J','K','L',',','N','O',
-    'P','A','R','S','T','U','V','Z','X','Y','W','^','\\','$','^',127
-};
-
-char ForeignTranslation(unsigned char ch)
-{
-    return ch < 128 ? frenchKeyMap[ch] : ch;
-}
-
 void HU_Init(void)
 {
 
@@ -396,16 +290,11 @@ void HU_Init(void)
     int                j;
     char       buffer[9];
 
-    if (french)
-       shiftxform = french_shiftxform;
-    else
-       shiftxform = english_shiftxform;
-
     // load the heads-up font
     j = HU_FONTSTART;
     for (i=0;i<HU_FONTSIZE;i++)
     {
-       sprintf(buffer, "STCFN%.3d", j++);
+       DEH_snprintf(buffer, 9, "STCFN%.3d", j++);
        hu_font[i] = (patch_t *) W_CacheLumpName(buffer, PU_STATIC);
     }
 
@@ -443,28 +332,36 @@ void HU_Start(void)
                       hu_font,
                       HU_FONTSTART);
     
-    switch ( gamemode )
+    switch ( logical_gamemission )
     {
-      case shareware:
-      case registered:
-      case retail:
+      case doom:
        s = HU_TITLE;
        break;
-
-/* FIXME
+      case doom2:
+        s = HU_TITLE2;
+        break;
       case pack_plut:
        s = HU_TITLEP;
        break;
       case pack_tnt:
        s = HU_TITLET;
        break;
-*/
-       
-      case commercial:
       default:
-        s = HU_TITLE2;
-        break;
+         s = "Unknown level";
+         break;
     }
+
+    // Chex.exe always uses the episode 1 level title
+    // eg. E2M1 gives the title for E1M1
+
+    if (gameversion == exe_chex)
+    {
+        s = HU_TITLE_CHEX;
+    }
+
+    // dehacked substitution to get modified level name
+
+    s = DEH_String(s);
     
     while (*s)
        HUlib_addCharToTextLine(&w_title, *(s++));
@@ -546,8 +443,6 @@ void HU_Ticker(void)
                    chat_dest[i] = c;
                else
                {
-                   if (c >= 'a' && c <= 'z')
-                       c = (char) shiftxform[(unsigned char) c];
                    rc = HUlib_keyInIText(&w_inputbuffer[i], c);
                    if (rc && c == KEY_ENTER)
                    {
@@ -556,7 +451,7 @@ void HU_Ticker(void)
                                || chat_dest[i] == HU_BROADCAST))
                        {
                            HUlib_addMessageToSText(&w_message,
-                                                   player_names[i],
+                                                   DEH_String(player_names[i]),
                                                    w_inputbuffer[i].l.l);
                            
                            message_nottobefuckedwith = true;
@@ -588,7 +483,7 @@ void HU_queueChatChar(char c)
 {
     if (((head + 1) & (QUEUESIZE-1)) == tail)
     {
-       plr->message = HUSTR_MSGU;
+       plr->message = DEH_String(HUSTR_MSGU);
     }
     else
     {
@@ -620,20 +515,11 @@ boolean HU_Responder(event_t *ev)
     static char                lastmessage[HU_MAXLINELENGTH+1];
     char*              macromessage;
     boolean            eatkey = false;
-    static boolean     shiftdown = false;
     static boolean     altdown = false;
     unsigned char      c;
     int                        i;
     int                        numplayers;
     
-    static char                destination_keys[MAXPLAYERS] =
-    {
-       HUSTR_KEYGREEN,
-       HUSTR_KEYINDIGO,
-       HUSTR_KEYBROWN,
-       HUSTR_KEYRED
-    };
-    
     static int         num_nobrainers = 0;
 
     numplayers = 0;
@@ -642,7 +528,6 @@ boolean HU_Responder(event_t *ev)
 
     if (ev->data1 == KEY_RSHIFT)
     {
-       shiftdown = ev->type == ev_keydown;
        return false;
     }
     else if (ev->data1 == KEY_RALT || ev->data1 == KEY_LALT)
@@ -656,13 +541,13 @@ boolean HU_Responder(event_t *ev)
 
     if (!chat_on)
     {
-       if (ev->data1 == HU_MSGREFRESH)
+       if (ev->data1 == key_message_refresh)
        {
            message_on = true;
            message_counter = HU_MSGTIMEOUT;
            eatkey = true;
        }
-       else if (netgame && ev->data1 == HU_INPUTTOGGLE)
+       else if (netgame && ev->data2 == key_multi_msg)
        {
            eatkey = chat_on = true;
            HUlib_resetIText(&w_chat);
@@ -672,7 +557,7 @@ boolean HU_Responder(event_t *ev)
        {
            for (i=0; i<MAXPLAYERS ; i++)
            {
-               if (ev->data1 == destination_keys[i])
+               if (ev->data2 == key_multi_msgplayer[i])
                {
                    if (playeringame[i] && i!=consoleplayer)
                    {
@@ -685,15 +570,15 @@ boolean HU_Responder(event_t *ev)
                    {
                        num_nobrainers++;
                        if (num_nobrainers < 3)
-                           plr->message = HUSTR_TALKTOSELF1;
+                           plr->message = DEH_String(HUSTR_TALKTOSELF1);
                        else if (num_nobrainers < 6)
-                           plr->message = HUSTR_TALKTOSELF2;
+                           plr->message = DEH_String(HUSTR_TALKTOSELF2);
                        else if (num_nobrainers < 9)
-                           plr->message = HUSTR_TALKTOSELF3;
+                           plr->message = DEH_String(HUSTR_TALKTOSELF3);
                        else if (num_nobrainers < 32)
-                           plr->message = HUSTR_TALKTOSELF4;
+                           plr->message = DEH_String(HUSTR_TALKTOSELF4);
                        else
-                           plr->message = HUSTR_TALKTOSELF5;
+                           plr->message = DEH_String(HUSTR_TALKTOSELF5);
                    }
                }
            }
@@ -701,11 +586,10 @@ boolean HU_Responder(event_t *ev)
     }
     else
     {
-       c = ev->data1;
        // send a macro
        if (altdown)
        {
-           c = c - '0';
+           c = ev->data1 - '0';
            if (c > 9)
                return false;
            // fprintf(stderr, "got here\n");
@@ -719,35 +603,33 @@ boolean HU_Responder(event_t *ev)
                HU_queueChatChar(*macromessage++);
            HU_queueChatChar(KEY_ENTER);
            
-           // leave chat mode and notify that it was sent
-           chat_on = false;
-           strcpy(lastmessage, chat_macros[c]);
-           plr->message = lastmessage;
-           eatkey = true;
+            // leave chat mode and notify that it was sent
+            chat_on = false;
+            M_StringCopy(lastmessage, chat_macros[c], sizeof(lastmessage));
+            plr->message = lastmessage;
+            eatkey = true;
        }
        else
        {
-           if (french)
-               c = ForeignTranslation(c);
-           if (shiftdown || (c >= 'a' && c <= 'z'))
-               c = shiftxform[c];
+            c = ev->data2;
+
            eatkey = HUlib_keyInIText(&w_chat, c);
            if (eatkey)
            {
                // static unsigned char buf[20]; // DEBUG
                HU_queueChatChar(c);
                
-               // sprintf(buf, "KEY: %d => %d", ev->data1, c);
-               //      plr->message = buf;
+               // M_snprintf(buf, sizeof(buf), "KEY: %d => %d", ev->data1, c);
+               //        plr->message = buf;
            }
            if (c == KEY_ENTER)
            {
                chat_on = false;
-               if (w_chat.l.len)
-               {
-                   strcpy(lastmessage, w_chat.l.l);
-                   plr->message = lastmessage;
-               }
+                if (w_chat.l.len)
+                {
+                    M_StringCopy(lastmessage, w_chat.l.l, sizeof(lastmessage));
+                    plr->message = lastmessage;
+                }
            }
            else if (c == KEY_ESCAPE)
                chat_on = false;
index 3705028869e6bb3e0d32fbcd4d3d62eebdbaa4c8..a3affc5b969e8723e9a55b9fcfef037b9bba9dab 100644 (file)
@@ -1,22 +1,19 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:  Head up display
 //
-//-----------------------------------------------------------------------------
 
 #ifndef __HU_STUFF_H__
 #define __HU_STUFF_H__
@@ -35,7 +32,6 @@
 
 #define HU_BROADCAST   5
 
-#define HU_MSGREFRESH  KEY_ENTER
 #define HU_MSGX                0
 #define HU_MSGY                0
 #define HU_MSGWIDTH    64      // in characters
@@ -57,10 +53,7 @@ void HU_Drawer(void);
 char HU_dequeueChatChar(void);
 void HU_Erase(void);
 
+extern char *chat_macros[10];
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
+
diff --git a/frosted-doom/i_cdmus.c b/frosted-doom/i_cdmus.c
new file mode 100644 (file)
index 0000000..6a9a9a6
--- /dev/null
@@ -0,0 +1,243 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+//
+// 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.
+//
+//
+// SDL implementation of the Hexen CD interface.
+//
+
+#include <stdio.h>
+
+#ifdef ORIGCODE
+#include "SDL.h"
+#include "SDL_cdrom.h"
+#endif
+
+#include "doomtype.h"
+
+#include "i_cdmus.h"
+
+#ifdef ORIGCODE
+static SDL_CD *cd_handle = NULL;
+static char *startup_error = NULL;
+static const char *cd_name = NULL;
+#endif
+
+int cd_Error;
+
+int I_CDMusInit(void)
+{
+#ifdef ORIGCODE
+    int drive_num = 0;
+
+    // The initialize function is re-invoked when the CD track play cheat
+    // is used, so use the opportunity to call SDL_CDStatus() to update
+    // the status of the drive.
+
+    if (cd_handle == NULL)
+    {
+        if (SDL_Init(SDL_INIT_CDROM) < 0)
+        {
+            startup_error = "Failed to init CD subsystem.";
+            cd_Error = 1;
+            return -1;
+        }
+
+        // TODO: config variable to control CDROM to use.
+
+        cd_handle = SDL_CDOpen(drive_num);
+
+        if (cd_handle == NULL)
+        {
+            startup_error = "Failed to open CD-ROM drive.";
+            cd_Error = 1;
+            return -1;
+        }
+
+        cd_name = SDL_CDName(drive_num);
+    }
+
+    if (SDL_CDStatus(cd_handle) == CD_ERROR)
+    {
+        startup_error = "Failed to read CD status.";
+        cd_Error = 1;
+        return -1;
+    }
+
+    if (!CD_INDRIVE(cd_handle->status))
+    {
+        startup_error = "No CD in drive.";
+        cd_Error = 1;
+        return -1;
+    }
+
+    cd_Error = 0;
+#endif
+    return 0;
+}
+
+// We cannot print status messages inline during startup, they must
+// be deferred until after I_CDMusInit has returned.
+
+void I_CDMusPrintStartup(void)
+{
+#ifdef ORIGCODE
+    if (cd_name != NULL)
+    {
+        printf("I_CDMusInit: Using CD-ROM drive: %s\n", cd_name);
+    }
+
+    if (startup_error != NULL)
+    {
+        fprintf(stderr, "I_CDMusInit: %s\n", startup_error);
+    }
+#endif
+}
+
+int I_CDMusPlay(int track)
+{
+#ifdef ORIGCODE
+    int result;
+
+    if (cd_handle == NULL)
+    {
+        cd_Error = 1;
+        return -1;
+    }
+
+    // Play one track
+    // Track is indexed from 1.
+
+    result = SDL_CDPlayTracks(cd_handle, track - 1, 0, 1, 0);
+
+    cd_Error = 0;
+    return result;
+#else
+       return 0;
+#endif
+}
+
+int I_CDMusStop(void)
+{
+#ifdef ORIGCODE
+    int result;
+
+    result = SDL_CDStop(cd_handle);
+
+    cd_Error = 0;
+
+    return result;
+#else
+       return 0;
+#endif
+}
+
+int I_CDMusResume(void)
+{
+#ifdef ORIGCODE
+    int result;
+
+    result = SDL_CDResume(cd_handle);
+
+    cd_Error = 0;
+
+    return result;
+#else
+       return 0;
+#endif
+}
+
+int I_CDMusSetVolume(int volume)
+{
+    /* Not supported yet */
+
+    cd_Error = 0;
+
+    return 0;
+}
+
+int I_CDMusFirstTrack(void)
+{
+#ifdef ORIGCODE
+    int i;
+
+    if (cd_handle == NULL)
+    {
+        cd_Error = 1;
+        return -1;
+    }
+
+    // Find the first audio track.
+
+    for (i=0; i<cd_handle->numtracks; ++i) 
+    {
+        if (cd_handle->track[i].type == SDL_AUDIO_TRACK)
+        {
+            cd_Error = 0;
+
+            // Tracks are indexed from 1.
+            return i + 1;
+        }
+    }
+
+    // Don't know?
+    cd_Error = 1;
+
+    return -1;
+#else
+       return 0;
+#endif
+}
+
+int I_CDMusLastTrack(void)
+{
+#ifdef ORIGCODE
+    if (cd_handle == NULL)
+    {
+        cd_Error = 1;
+        return -1;
+    }
+
+    cd_Error = 0;
+
+    return cd_handle->numtracks;
+#else
+       return 0;
+#endif
+}
+
+int I_CDMusTrackLength(int track_num)
+{
+#ifdef ORIGCODE
+    SDL_CDtrack *track;
+
+    if (cd_handle == NULL || track_num < 1 || track_num > cd_handle->numtracks)
+    {
+        cd_Error = 1;
+        return -1;
+    }
+
+    // Track number is indexed from 1.
+
+    track = &cd_handle->track[track_num - 1];
+
+    // Round up to the next second
+
+    cd_Error = 0;
+
+    return (track->length + CD_FPS - 1) / CD_FPS;
+#else
+       return 0;
+#endif
+}
+
diff --git a/frosted-doom/i_cdmus.h b/frosted-doom/i_cdmus.h
new file mode 100644 (file)
index 0000000..31db2a6
--- /dev/null
@@ -0,0 +1,41 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+//
+// 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.
+//
+
+// i_cdmus.h
+
+#ifndef __ICDMUS__
+#define __ICDMUS__
+
+#define CDERR_NOTINSTALLED   10 // MSCDEX not installed
+#define CDERR_NOAUDIOSUPPORT 11 // CD-ROM Doesn't support audio
+#define CDERR_NOAUDIOTRACKS  12 // Current CD has no audio tracks
+#define CDERR_BADDRIVE       20 // Bad drive number
+#define CDERR_BADTRACK       21 // Bad track number
+#define CDERR_IOCTLBUFFMEM   22 // Not enough low memory for IOCTL
+#define CDERR_DEVREQBASE     100        // DevReq errors
+
+extern int cd_Error;
+
+int I_CDMusInit(void);
+void I_CDMusPrintStartup(void);
+int I_CDMusPlay(int track);
+int I_CDMusStop(void);
+int I_CDMusResume(void);
+int I_CDMusSetVolume(int volume);
+int I_CDMusFirstTrack(void);
+int I_CDMusLastTrack(void);
+int I_CDMusTrackLength(int track);
+
+#endif
diff --git a/frosted-doom/i_endoom.c b/frosted-doom/i_endoom.c
new file mode 100644 (file)
index 0000000..98b8c87
--- /dev/null
@@ -0,0 +1,81 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//    Exit text-mode ENDOOM screen.
+//
+
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+#include "doomtype.h"
+#include "i_video.h"
+
+#ifdef ORIGCODE
+#include "txt_main.h"
+#endif
+
+#define ENDOOM_W 80
+#define ENDOOM_H 25
+
+// 
+// Displays the text mode ending screen after the game quits
+//
+
+void I_Endoom(byte *endoom_data)
+{
+#ifdef ORIGCODE
+    unsigned char *screendata;
+    int y;
+    int indent;
+
+    // Set up text mode screen
+
+    TXT_Init();
+    I_InitWindowTitle();
+    I_InitWindowIcon();
+
+    // Write the data to the screen memory
+
+    screendata = TXT_GetScreenData();
+
+    indent = (ENDOOM_W - TXT_SCREEN_W) / 2;
+
+    for (y=0; y<TXT_SCREEN_H; ++y)
+    {
+        memcpy(screendata + (y * TXT_SCREEN_W * 2),
+               endoom_data + (y * ENDOOM_W + indent) * 2,
+               TXT_SCREEN_W * 2);
+    }
+
+    // Wait for a keypress
+
+    while (true)
+    {
+        TXT_UpdateScreen();
+
+        if (TXT_GetChar() > 0)
+        {
+            break;
+        }
+
+        TXT_Sleep(0);
+    }
+
+    // Shut down text mode screen
+
+    TXT_Shutdown();
+#endif
+}
+
diff --git a/frosted-doom/i_endoom.h b/frosted-doom/i_endoom.h
new file mode 100644 (file)
index 0000000..8c8ff45
--- /dev/null
@@ -0,0 +1,29 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//    Exit text-mode ENDOOM screen.
+//
+
+
+#ifndef __I_ENDOOM__
+#define __I_ENDOOM__
+
+// Display the Endoom screen on shutdown.  Pass a pointer to the
+// ENDOOM lump.
+
+void I_Endoom(byte *data);
+
+#endif
+
diff --git a/frosted-doom/i_joystick.c b/frosted-doom/i_joystick.c
new file mode 100644 (file)
index 0000000..755aec3
--- /dev/null
@@ -0,0 +1,359 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//       SDL Joystick code.
+//
+
+#ifdef ORIGCODE
+#include "SDL.h"
+#include "SDL_joystick.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "doomtype.h"
+#include "d_event.h"
+#include "i_joystick.h"
+#include "i_system.h"
+
+#include "m_config.h"
+#include "m_misc.h"
+
+// When an axis is within the dead zone, it is set to zero.
+// This is 5% of the full range:
+
+#define DEAD_ZONE (32768 / 3)
+
+#ifdef ORIGCODE
+static SDL_Joystick *joystick = NULL;
+#endif
+
+// Configuration variables:
+
+// Standard default.cfg Joystick enable/disable
+
+static int usejoystick = 0;
+
+// Joystick to use, as an SDL joystick index:
+
+static int joystick_index = -1;
+
+// Which joystick axis to use for horizontal movement, and whether to
+// invert the direction:
+
+static int joystick_x_axis = 0;
+static int joystick_x_invert = 0;
+
+// Which joystick axis to use for vertical movement, and whether to
+// invert the direction:
+
+static int joystick_y_axis = 1;
+static int joystick_y_invert = 0;
+
+// Which joystick axis to use for strafing?
+
+static int joystick_strafe_axis = -1;
+static int joystick_strafe_invert = 0;
+
+// Virtual to physical button joystick button mapping. By default this
+// is a straight mapping.
+static int joystick_physical_buttons[NUM_VIRTUAL_BUTTONS] = {
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9
+};
+
+void I_ShutdownJoystick(void)
+{
+#ifdef ORIGCODE
+    if (joystick != NULL)
+    {
+        SDL_JoystickClose(joystick);
+        joystick = NULL;
+        SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
+    }
+#endif
+}
+
+#ifdef ORIGCODE
+static boolean IsValidAxis(int axis)
+{
+    int num_axes;
+
+    if (axis < 0)
+    {
+        return true;
+    }
+
+    if (IS_BUTTON_AXIS(axis))
+    {
+        return true;
+    }
+
+    if (IS_HAT_AXIS(axis))
+    {
+        return HAT_AXIS_HAT(axis) < SDL_JoystickNumHats(joystick);
+    }
+
+    num_axes = SDL_JoystickNumAxes(joystick);
+
+    return axis < num_axes;
+}
+#endif
+
+void I_InitJoystick(void)
+{
+#ifdef ORIGCODE
+    if (!usejoystick)
+    {
+        return;
+    }
+
+    if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
+    {
+        return;
+    }
+
+    if (joystick_index < 0 || joystick_index >= SDL_NumJoysticks())
+    {
+        printf("I_InitJoystick: Invalid joystick ID: %i\n", joystick_index);
+        SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
+        return;
+    }
+
+    // Open the joystick
+
+    joystick = SDL_JoystickOpen(joystick_index);
+
+    if (joystick == NULL)
+    {
+        printf("I_InitJoystick: Failed to open joystick #%i\n",
+               joystick_index);
+        SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
+        return;
+    }
+
+    if (!IsValidAxis(joystick_x_axis)
+     || !IsValidAxis(joystick_y_axis)
+     || !IsValidAxis(joystick_strafe_axis))
+    {
+        printf("I_InitJoystick: Invalid joystick axis for joystick #%i "
+               "(run joystick setup again)\n",
+               joystick_index);
+
+        SDL_JoystickClose(joystick);
+        joystick = NULL;
+        SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
+    }
+
+    SDL_JoystickEventState(SDL_ENABLE);
+
+    // Initialized okay!
+
+    printf("I_InitJoystick: %s\n", SDL_JoystickName(joystick_index));
+
+    I_AtExit(I_ShutdownJoystick, true);
+#endif
+}
+
+#ifdef ORIGCODE
+static boolean IsAxisButton(int physbutton)
+{
+    if (IS_BUTTON_AXIS(joystick_x_axis))
+    {
+        if (physbutton == BUTTON_AXIS_NEG(joystick_x_axis)
+         || physbutton == BUTTON_AXIS_POS(joystick_x_axis))
+        {
+            return true;
+        }
+    }
+    if (IS_BUTTON_AXIS(joystick_y_axis))
+    {
+        if (physbutton == BUTTON_AXIS_NEG(joystick_y_axis)
+         || physbutton == BUTTON_AXIS_POS(joystick_y_axis))
+        {
+            return true;
+        }
+    }
+    if (IS_BUTTON_AXIS(joystick_strafe_axis))
+    {
+        if (physbutton == BUTTON_AXIS_NEG(joystick_strafe_axis)
+         || physbutton == BUTTON_AXIS_POS(joystick_strafe_axis))
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+// Get the state of the given virtual button.
+
+static int ReadButtonState(int vbutton)
+{
+    int physbutton;
+
+    // Map from virtual button to physical (SDL) button.
+    if (vbutton < NUM_VIRTUAL_BUTTONS)
+    {
+        physbutton = joystick_physical_buttons[vbutton];
+    }
+    else
+    {
+        physbutton = vbutton;
+    }
+
+    // Never read axis buttons as buttons.
+    if (IsAxisButton(physbutton))
+    {
+        return 0;
+    }
+
+    return SDL_JoystickGetButton(joystick, physbutton);
+}
+
+// Get a bitmask of all currently-pressed buttons
+
+static int GetButtonsState(void)
+{
+    int i;
+    int result;
+
+    result = 0;
+
+    for (i = 0; i < 20; ++i)
+    {
+        if (ReadButtonState(i))
+        {
+            result |= 1 << i;
+        }
+    }
+
+    return result;
+}
+
+// Read the state of an axis, inverting if necessary.
+
+static int GetAxisState(int axis, int invert)
+{
+    int result;
+
+    // Axis -1 means disabled.
+
+    if (axis < 0)
+    {
+        return 0;
+    }
+
+    // Is this a button axis, or a hat axis?
+    // If so, we need to handle it specially.
+
+    result = 0;
+
+    if (IS_BUTTON_AXIS(axis))
+    {
+        if (SDL_JoystickGetButton(joystick, BUTTON_AXIS_NEG(axis)))
+        {
+            result -= 32767;
+        }
+        if (SDL_JoystickGetButton(joystick, BUTTON_AXIS_POS(axis)))
+        {
+            result += 32767;
+        }
+    }
+    else if (IS_HAT_AXIS(axis))
+    {
+        int direction = HAT_AXIS_DIRECTION(axis);
+        int hatval = SDL_JoystickGetHat(joystick, HAT_AXIS_HAT(axis));
+
+        if (direction == HAT_AXIS_HORIZONTAL)
+        {
+            if ((hatval & SDL_HAT_LEFT) != 0)
+            {
+                result -= 32767;
+            }
+            else if ((hatval & SDL_HAT_RIGHT) != 0)
+            {
+                result += 32767;
+            }
+        }
+        else if (direction == HAT_AXIS_VERTICAL)
+        {
+            if ((hatval & SDL_HAT_UP) != 0)
+            {
+                result -= 32767;
+            }
+            else if ((hatval & SDL_HAT_DOWN) != 0)
+            {
+                result += 32767;
+            }
+        }
+    }
+    else
+    {
+        result = SDL_JoystickGetAxis(joystick, axis);
+
+        if (result < DEAD_ZONE && result > -DEAD_ZONE)
+        {
+            result = 0;
+        }
+    }
+
+    if (invert)
+    {
+        result = -result;
+    }
+
+    return result;
+}
+#endif
+void I_UpdateJoystick(void)
+{
+#ifdef ORIGCODE
+    if (joystick != NULL)
+    {
+        event_t ev;
+
+        ev.type = ev_joystick;
+        ev.data1 = GetButtonsState();
+        ev.data2 = GetAxisState(joystick_x_axis, joystick_x_invert);
+        ev.data3 = GetAxisState(joystick_y_axis, joystick_y_invert);
+        ev.data4 = GetAxisState(joystick_strafe_axis, joystick_strafe_invert);
+
+        D_PostEvent(&ev);
+    }
+#endif
+}
+
+void I_BindJoystickVariables(void)
+{
+    int i;
+
+    M_BindVariable("use_joystick",          &usejoystick);
+    M_BindVariable("joystick_index",        &joystick_index);
+    M_BindVariable("joystick_x_axis",       &joystick_x_axis);
+    M_BindVariable("joystick_y_axis",       &joystick_y_axis);
+    M_BindVariable("joystick_strafe_axis",  &joystick_strafe_axis);
+    M_BindVariable("joystick_x_invert",     &joystick_x_invert);
+    M_BindVariable("joystick_y_invert",     &joystick_y_invert);
+    M_BindVariable("joystick_strafe_invert",&joystick_strafe_invert);
+
+    for (i = 0; i < NUM_VIRTUAL_BUTTONS; ++i)
+    {
+        char name[32];
+        M_snprintf(name, sizeof(name), "joystick_physical_button%i", i);
+        M_BindVariable(name, &joystick_physical_buttons[i]);
+    }
+}
+
diff --git a/frosted-doom/i_joystick.h b/frosted-doom/i_joystick.h
new file mode 100644 (file)
index 0000000..b8815e2
--- /dev/null
@@ -0,0 +1,70 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//      System-specific joystick interface.
+//
+
+
+#ifndef __I_JOYSTICK__
+#define __I_JOYSTICK__
+
+// Number of "virtual" joystick buttons defined in configuration files.
+// This needs to be at least as large as the number of different key
+// bindings supported by the higher-level game code (joyb* variables).
+#define NUM_VIRTUAL_BUTTONS 10
+
+// If this bit is set in a configuration file axis value, the axis is
+// not actually a joystick axis, but instead is a "button axis". This
+// means that instead of reading an SDL joystick axis, we read the
+// state of two buttons to get the axis value. This is needed for eg.
+// the PS3 SIXAXIS controller, where the D-pad buttons register as
+// buttons, not as two axes.
+#define BUTTON_AXIS 0x10000
+
+// Query whether a given axis value describes a button axis.
+#define IS_BUTTON_AXIS(axis) ((axis) >= 0 && ((axis) & BUTTON_AXIS) != 0)
+
+// Get the individual buttons from a button axis value.
+#define BUTTON_AXIS_NEG(axis)  ((axis) & 0xff)
+#define BUTTON_AXIS_POS(axis)  (((axis) >> 8) & 0xff)
+
+// Create a button axis value from two button values.
+#define CREATE_BUTTON_AXIS(neg, pos) (BUTTON_AXIS | (neg) | ((pos) << 8))
+
+// If this bit is set in an axis value, the axis is not actually a
+// joystick axis, but is a "hat" axis. This means that we read (one of)
+// the hats on the joystick.
+#define HAT_AXIS    0x20000
+
+#define IS_HAT_AXIS(axis) ((axis) >= 0 && ((axis) & HAT_AXIS) != 0)
+
+// Get the hat number from a hat axis value.
+#define HAT_AXIS_HAT(axis)         ((axis) & 0xff)
+// Which axis of the hat? (horizonal or vertical)
+#define HAT_AXIS_DIRECTION(axis)   (((axis) >> 8) & 0xff)
+
+#define CREATE_HAT_AXIS(hat, direction) \
+    (HAT_AXIS | (hat) | ((direction) << 8))
+
+#define HAT_AXIS_HORIZONTAL 1
+#define HAT_AXIS_VERTICAL   2
+
+void I_InitJoystick(void);
+void I_ShutdownJoystick(void);
+void I_UpdateJoystick(void);
+
+void I_BindJoystickVariables(void);
+
+#endif /* #ifndef __I_JOYSTICK__ */
+
index e189e78dcd5af0f610494274de2367b2e3c679e1..bb481eb3471198f27e70026c04b2e9200f0eb761 100644 (file)
@@ -1,45 +1,50 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Main program, simply calls D_DoomMain high level loop.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: i_main.c,v 1.4 1997/02/03 22:45:10 b1 Exp $";
+#include "config.h"
 
+#include <stdio.h>
 
+#include "doomtype.h"
+#include "i_system.h"
+#include "m_argv.h"
 
-#include "doomdef.h"
+//
+// D_DoomMain()
+// Not a globally visible function, just included for source reference,
+// calls all startup code, parses command line options.
+//
 
-#include "m_argv.h"
-#include "d_main.h"
-
-int
-main
-( int          argc,
-  char**       argv ) 
-{ 
-    myargc = argc; 
-    myargv = argv; 
-    D_DoomMain (); 
+void D_DoomMain (void);
+
+int main(int argc, char **argv)
+{
+    // save arguments
+
+    myargc = argc;
+    myargv = argv;
+
+    M_FindResponseFile();
+
+    // start doom
+    printf("Starting D_DoomMain\r\n");
+    D_DoomMain ();
 
     return 0;
-} 
+}
+
diff --git a/frosted-doom/i_net.c b/frosted-doom/i_net.c
deleted file mode 100644 (file)
index e8cb017..0000000
+++ /dev/null
@@ -1,332 +0,0 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
-//
-// $Id:$
-//
-// Copyright (C) 1993-1996 by id Software, Inc.
-//
-// This source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
-//
-// DESCRIPTION:
-//
-//-----------------------------------------------------------------------------
-
-static const char
-rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $";
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-
-#include "i_system.h"
-#include "d_event.h"
-#include "d_net.h"
-#include "m_argv.h"
-
-#include "doomstat.h"
-
-#ifdef __GNUG__
-#pragma implementation "i_net.h"
-#endif
-#include "i_net.h"
-
-
-void   NetSend (void);
-boolean NetListen (void);
-
-
-//
-// NETWORKING
-//
-
-int    DOOMPORT =      (IPPORT_USERRESERVED +0x1d );
-
-int                    sendsocket;
-int                    insocket;
-
-struct sockaddr_in     sendaddress[MAXNETNODES];
-
-void   (*netget) (void);
-void   (*netsend) (void);
-
-
-//
-// UDPsocket
-//
-int UDPsocket (void)
-{
-    int        s;
-       
-    // allocate a socket
-    s = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
-    if (s<0)
-       I_Error ("can't create socket: %s",strerror(errno));
-               
-    return s;
-}
-
-//
-// BindToLocalPort
-//
-void
-BindToLocalPort
-( int  s,
-  int  port )
-{
-    int                        v;
-    struct sockaddr_in address;
-       
-    memset (&address, 0, sizeof(address));
-    address.sin_family = AF_INET;
-    address.sin_addr.s_addr = INADDR_ANY;
-    address.sin_port = port;
-                       
-    v = bind (s, (void *)&address, sizeof(address));
-    if (v == -1)
-       I_Error ("BindToPort: bind: %s", strerror(errno));
-}
-
-
-//
-// PacketSend
-//
-void PacketSend (void)
-{
-    int                c;
-    doomdata_t sw;
-                               
-    // byte swap
-    sw.checksum = htonl(netbuffer->checksum);
-    sw.player = netbuffer->player;
-    sw.retransmitfrom = netbuffer->retransmitfrom;
-    sw.starttic = netbuffer->starttic;
-    sw.numtics = netbuffer->numtics;
-    for (c=0 ; c< netbuffer->numtics ; c++)
-    {
-       sw.cmds[c].forwardmove = netbuffer->cmds[c].forwardmove;
-       sw.cmds[c].sidemove = netbuffer->cmds[c].sidemove;
-       sw.cmds[c].angleturn = htons(netbuffer->cmds[c].angleturn);
-       sw.cmds[c].consistancy = htons(netbuffer->cmds[c].consistancy);
-       sw.cmds[c].chatchar = netbuffer->cmds[c].chatchar;
-       sw.cmds[c].buttons = netbuffer->cmds[c].buttons;
-    }
-               
-    //printf ("sending %i\n",gametic);         
-    c = sendto (sendsocket , &sw, doomcom->datalength
-               ,0,(void *)&sendaddress[doomcom->remotenode]
-               ,sizeof(sendaddress[doomcom->remotenode]));
-       
-    // if (c == -1)
-    //         I_Error ("SendPacket error: %s",strerror(errno));
-}
-
-
-//
-// PacketGet
-//
-void PacketGet (void)
-{
-    int                        i;
-    int                        c;
-    struct sockaddr_in fromaddress;
-    int        fromlen;
-    doomdata_t         sw;
-                               
-    fromlen = sizeof(fromaddress);
-    c = recvfrom (insocket, &sw, sizeof(sw), 0
-                 , (struct sockaddr *)&fromaddress, (socklen_t *)&fromlen );
-    if (c == -1 )
-    {
-       if (errno != EWOULDBLOCK)
-           I_Error ("GetPacket: %s",strerror(errno));
-       doomcom->remotenode = -1;               // no packet
-       return;
-    }
-
-    {
-       static int first=1;
-       if (first)
-           printf("len=%d:p=[0x%x 0x%x] \n", c, *(int*)&sw, *((int*)&sw+1));
-       first = 0;
-    }
-
-    // find remote node number
-    for (i=0 ; i<doomcom->numnodes ; i++)
-       if ( fromaddress.sin_addr.s_addr == sendaddress[i].sin_addr.s_addr )
-           break;
-
-    if (i == doomcom->numnodes)
-    {
-       // packet is not from one of the players (new game broadcast)
-       doomcom->remotenode = -1;               // no packet
-       return;
-    }
-       
-    doomcom->remotenode = i;                   // good packet from a game player
-    doomcom->datalength = c;
-       
-    // byte swap
-    netbuffer->checksum = ntohl(sw.checksum);
-    netbuffer->player = sw.player;
-    netbuffer->retransmitfrom = sw.retransmitfrom;
-    netbuffer->starttic = sw.starttic;
-    netbuffer->numtics = sw.numtics;
-
-    for (c=0 ; c< netbuffer->numtics ; c++)
-    {
-       netbuffer->cmds[c].forwardmove = sw.cmds[c].forwardmove;
-       netbuffer->cmds[c].sidemove = sw.cmds[c].sidemove;
-       netbuffer->cmds[c].angleturn = ntohs(sw.cmds[c].angleturn);
-       netbuffer->cmds[c].consistancy = ntohs(sw.cmds[c].consistancy);
-       netbuffer->cmds[c].chatchar = sw.cmds[c].chatchar;
-       netbuffer->cmds[c].buttons = sw.cmds[c].buttons;
-    }
-}
-
-
-int GetLocalAddress (void)
-{
-    struct hostent*    hostentry;      // host information entry
-    int                        v;
-    static char                hostname[512];
-
-    // get local address
-    v = gethostname (hostname, sizeof(hostname));
-    if (v == -1)
-       I_Error ("GetLocalAddress : gethostname: errno %d",errno);
-       
-    hostentry = gethostbyname (hostname);
-    if (!hostentry)
-       I_Error ("GetLocalAddress : gethostbyname: couldn't get local host");
-               
-    return *(int *)hostentry->h_addr_list[0];
-}
-
-
-//
-// I_InitNetwork
-//
-void I_InitNetwork (void)
-{
-    //boolean          trueval = true;
-    int                        i;
-    int                        p;
-    struct hostent*    hostentry;      // host information entry
-       
-    doomcom = malloc (sizeof (*doomcom) );
-    memset (doomcom, 0, sizeof(*doomcom) );
-    
-    // set up for network
-    i = M_CheckParm ("-dup");
-    if (i && i< myargc-1)
-    {
-       doomcom->ticdup = myargv[i+1][0]-'0';
-       if (doomcom->ticdup < 1)
-           doomcom->ticdup = 1;
-       if (doomcom->ticdup > 9)
-           doomcom->ticdup = 9;
-    }
-    else
-       doomcom-> ticdup = 1;
-       
-    if (M_CheckParm ("-extratic"))
-       doomcom-> extratics = 1;
-    else
-       doomcom-> extratics = 0;
-               
-    p = M_CheckParm ("-port");
-    if (p && p<myargc-1)
-    {
-       DOOMPORT = atoi (myargv[p+1]);
-       printf ("using alternate port %i\n",DOOMPORT);
-    }
-    
-    // parse network game options,
-    //  -net <consoleplayer> <host> <host> ...
-    i = M_CheckParm ("-net");
-    if (!i)
-    {
-       // single player game
-       netgame = false;
-       doomcom->id = DOOMCOM_ID;
-       doomcom->numplayers = doomcom->numnodes = 1;
-       doomcom->deathmatch = false;
-       doomcom->consoleplayer = 0;
-       return;
-    }
-
-    netsend = PacketSend;
-    netget = PacketGet;
-    netgame = true;
-
-    // parse player number and host list
-    doomcom->consoleplayer = myargv[i+1][0]-'1';
-
-    doomcom->numnodes = 1;     // this node for sure
-       
-    i++;
-    while (++i < myargc && myargv[i][0] != '-')
-    {
-       sendaddress[doomcom->numnodes].sin_family = AF_INET;
-       sendaddress[doomcom->numnodes].sin_port = htons(DOOMPORT);
-       if (myargv[i][0] == '.')
-       {
-           sendaddress[doomcom->numnodes].sin_addr.s_addr 
-               = inet_addr (myargv[i]+1);
-       }
-       else
-       {
-           hostentry = gethostbyname (myargv[i]);
-           if (!hostentry)
-               I_Error ("gethostbyname: couldn't find %s", myargv[i]);
-           sendaddress[doomcom->numnodes].sin_addr.s_addr 
-               = *(int *)hostentry->h_addr_list[0];
-       }
-       doomcom->numnodes++;
-    }
-       
-    doomcom->id = DOOMCOM_ID;
-    doomcom->numplayers = doomcom->numnodes;
-    
-    // build message to receive
-    insocket = UDPsocket ();
-    BindToLocalPort (insocket,htons(DOOMPORT));
-    //XXX ioctl (insocket, FIONBIO, &trueval);
-    fcntl (insocket,F_SETFL, O_NONBLOCK);
-
-    sendsocket = UDPsocket ();
-}
-
-
-void I_NetCmd (void)
-{
-    if (doomcom->command == CMD_SEND)
-    {
-       netsend ();
-    }
-    else if (doomcom->command == CMD_GET)
-    {
-       netget ();
-    }
-    else
-       I_Error ("Bad net cmd: %i\n",doomcom->command);
-}
-
diff --git a/frosted-doom/i_net.h b/frosted-doom/i_net.h
deleted file mode 100644 (file)
index 6345447..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
-//
-// $Id:$
-//
-// Copyright (C) 1993-1996 by id Software, Inc.
-//
-// This source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// DESCRIPTION:
-//     System specific network interface stuff.
-//
-//-----------------------------------------------------------------------------
-
-
-#ifndef __I_NET__
-#define __I_NET__
-
-
-#ifdef __GNUG__
-#pragma interface
-#endif
-
-
-
-// Called by D_DoomMain.
-
-
-void I_InitNetwork (void);
-void I_NetCmd (void);
-
-
-#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
diff --git a/frosted-doom/i_oplmusic.c b/frosted-doom/i_oplmusic.c
new file mode 100644 (file)
index 0000000..a1e9050
--- /dev/null
@@ -0,0 +1,1616 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//     System interface for music.
+//
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "memio.h"
+#include "mus2mid.h"
+
+#include "deh_main.h"
+#include "i_sound.h"
+#include "i_swap.h"
+#include "m_misc.h"
+#include "w_wad.h"
+#include "z_zone.h"
+
+#include "opl.h"
+#include "midifile.h"
+
+// #define OPL_MIDI_DEBUG
+
+#define MAXMIDLENGTH (96 * 1024)
+#define GENMIDI_NUM_INSTRS  128
+#define GENMIDI_NUM_PERCUSSION 47
+
+#define GENMIDI_HEADER          "#OPL_II#"
+#define GENMIDI_FLAG_FIXED      0x0001         /* fixed pitch */
+#define GENMIDI_FLAG_2VOICE     0x0004         /* double voice (OPL3) */
+
+#define PERCUSSION_LOG_LEN 16
+
+typedef struct
+{
+    byte tremolo;
+    byte attack;
+    byte sustain;
+    byte waveform;
+    byte scale;
+    byte level;
+} PACKEDATTR genmidi_op_t;
+
+typedef struct
+{
+    genmidi_op_t modulator;
+    byte feedback;
+    genmidi_op_t carrier;
+    byte unused;
+    short base_note_offset;
+} PACKEDATTR genmidi_voice_t;
+
+typedef struct
+{
+    unsigned short flags;
+    byte fine_tuning;
+    byte fixed_note;
+
+    genmidi_voice_t voices[2];
+} PACKEDATTR genmidi_instr_t;
+
+// Data associated with a channel of a track that is currently playing.
+
+typedef struct
+{
+    // The instrument currently used for this track.
+
+    genmidi_instr_t *instrument;
+
+    // Volume level
+
+    int volume;
+
+    // Pitch bend value:
+
+    int bend;
+
+} opl_channel_data_t;
+
+// Data associated with a track that is currently playing.
+
+typedef struct
+{
+    // Data for each channel.
+
+    opl_channel_data_t channels[MIDI_CHANNELS_PER_TRACK];
+
+    // Track iterator used to read new events.
+
+    midi_track_iter_t *iter;
+} opl_track_data_t;
+
+typedef struct opl_voice_s opl_voice_t;
+
+struct opl_voice_s
+{
+    // Index of this voice:
+    int index;
+
+    // The operators used by this voice:
+    int op1, op2;
+
+    // Currently-loaded instrument data
+    genmidi_instr_t *current_instr;
+
+    // The voice number in the instrument to use.
+    // This is normally set to zero; if this is a double voice
+    // instrument, it may be one.
+    unsigned int current_instr_voice;
+
+    // The channel currently using this voice.
+    opl_channel_data_t *channel;
+
+    // The midi key that this voice is playing.
+    unsigned int key;
+
+    // The note being played.  This is normally the same as
+    // the key, but if the instrument is a fixed pitch
+    // instrument, it is different.
+    unsigned int note;
+
+    // The frequency value being used.
+    unsigned int freq;
+
+    // The volume of the note being played on this channel.
+    unsigned int note_volume;
+
+    // The current volume (register value) that has been set for this channel.
+    unsigned int reg_volume;
+
+    // Next in linked list; a voice is always either in the
+    // free list or the allocated list.
+    opl_voice_t *next;
+};
+
+// Operators used by the different voices.
+
+static const int voice_operators[2][OPL_NUM_VOICES] = {
+    { 0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12 },
+    { 0x03, 0x04, 0x05, 0x0b, 0x0c, 0x0d, 0x13, 0x14, 0x15 }
+};
+
+// Frequency values to use for each note.
+
+static const unsigned short frequency_curve[] = {
+
+    0x133, 0x133, 0x134, 0x134, 0x135, 0x136, 0x136, 0x137,   // -1
+    0x137, 0x138, 0x138, 0x139, 0x139, 0x13a, 0x13b, 0x13b,
+    0x13c, 0x13c, 0x13d, 0x13d, 0x13e, 0x13f, 0x13f, 0x140,
+    0x140, 0x141, 0x142, 0x142, 0x143, 0x143, 0x144, 0x144,
+
+    0x145, 0x146, 0x146, 0x147, 0x147, 0x148, 0x149, 0x149,   // -2
+    0x14a, 0x14a, 0x14b, 0x14c, 0x14c, 0x14d, 0x14d, 0x14e,
+    0x14f, 0x14f, 0x150, 0x150, 0x151, 0x152, 0x152, 0x153,
+    0x153, 0x154, 0x155, 0x155, 0x156, 0x157, 0x157, 0x158,
+
+    // These are used for the first seven MIDI note values:
+
+    0x158, 0x159, 0x15a, 0x15a, 0x15b, 0x15b, 0x15c, 0x15d,   // 0
+    0x15d, 0x15e, 0x15f, 0x15f, 0x160, 0x161, 0x161, 0x162,
+    0x162, 0x163, 0x164, 0x164, 0x165, 0x166, 0x166, 0x167,
+    0x168, 0x168, 0x169, 0x16a, 0x16a, 0x16b, 0x16c, 0x16c,
+
+    0x16d, 0x16e, 0x16e, 0x16f, 0x170, 0x170, 0x171, 0x172,   // 1
+    0x172, 0x173, 0x174, 0x174, 0x175, 0x176, 0x176, 0x177,
+    0x178, 0x178, 0x179, 0x17a, 0x17a, 0x17b, 0x17c, 0x17c,
+    0x17d, 0x17e, 0x17e, 0x17f, 0x180, 0x181, 0x181, 0x182,
+
+    0x183, 0x183, 0x184, 0x185, 0x185, 0x186, 0x187, 0x188,   // 2
+    0x188, 0x189, 0x18a, 0x18a, 0x18b, 0x18c, 0x18d, 0x18d,
+    0x18e, 0x18f, 0x18f, 0x190, 0x191, 0x192, 0x192, 0x193,
+    0x194, 0x194, 0x195, 0x196, 0x197, 0x197, 0x198, 0x199,
+
+    0x19a, 0x19a, 0x19b, 0x19c, 0x19d, 0x19d, 0x19e, 0x19f,   // 3
+    0x1a0, 0x1a0, 0x1a1, 0x1a2, 0x1a3, 0x1a3, 0x1a4, 0x1a5,
+    0x1a6, 0x1a6, 0x1a7, 0x1a8, 0x1a9, 0x1a9, 0x1aa, 0x1ab,
+    0x1ac, 0x1ad, 0x1ad, 0x1ae, 0x1af, 0x1b0, 0x1b0, 0x1b1,
+
+    0x1b2, 0x1b3, 0x1b4, 0x1b4, 0x1b5, 0x1b6, 0x1b7, 0x1b8,   // 4
+    0x1b8, 0x1b9, 0x1ba, 0x1bb, 0x1bc, 0x1bc, 0x1bd, 0x1be,
+    0x1bf, 0x1c0, 0x1c0, 0x1c1, 0x1c2, 0x1c3, 0x1c4, 0x1c4,
+    0x1c5, 0x1c6, 0x1c7, 0x1c8, 0x1c9, 0x1c9, 0x1ca, 0x1cb,
+
+    0x1cc, 0x1cd, 0x1ce, 0x1ce, 0x1cf, 0x1d0, 0x1d1, 0x1d2,   // 5
+    0x1d3, 0x1d3, 0x1d4, 0x1d5, 0x1d6, 0x1d7, 0x1d8, 0x1d8,
+    0x1d9, 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1de, 0x1df,
+    0x1e0, 0x1e1, 0x1e2, 0x1e3, 0x1e4, 0x1e5, 0x1e5, 0x1e6,
+
+    0x1e7, 0x1e8, 0x1e9, 0x1ea, 0x1eb, 0x1ec, 0x1ed, 0x1ed,   // 6
+    0x1ee, 0x1ef, 0x1f0, 0x1f1, 0x1f2, 0x1f3, 0x1f4, 0x1f5,
+    0x1f6, 0x1f6, 0x1f7, 0x1f8, 0x1f9, 0x1fa, 0x1fb, 0x1fc,
+    0x1fd, 0x1fe, 0x1ff, 0x200, 0x201, 0x201, 0x202, 0x203,
+
+    // First note of looped range used for all octaves:
+
+    0x204, 0x205, 0x206, 0x207, 0x208, 0x209, 0x20a, 0x20b,   // 7
+    0x20c, 0x20d, 0x20e, 0x20f, 0x210, 0x210, 0x211, 0x212,
+    0x213, 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21a,
+    0x21b, 0x21c, 0x21d, 0x21e, 0x21f, 0x220, 0x221, 0x222,
+
+    0x223, 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22a,   // 8
+    0x22b, 0x22c, 0x22d, 0x22e, 0x22f, 0x230, 0x231, 0x232,
+    0x233, 0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23a,
+    0x23b, 0x23c, 0x23d, 0x23e, 0x23f, 0x240, 0x241, 0x242,
+
+    0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24a, 0x24b,   // 9
+    0x24c, 0x24d, 0x24e, 0x24f, 0x250, 0x251, 0x252, 0x253,
+    0x254, 0x256, 0x257, 0x258, 0x259, 0x25a, 0x25b, 0x25c,
+    0x25d, 0x25e, 0x25f, 0x260, 0x262, 0x263, 0x264, 0x265,
+
+    0x266, 0x267, 0x268, 0x269, 0x26a, 0x26c, 0x26d, 0x26e,   // 10
+    0x26f, 0x270, 0x271, 0x272, 0x273, 0x275, 0x276, 0x277,
+    0x278, 0x279, 0x27a, 0x27b, 0x27d, 0x27e, 0x27f, 0x280,
+    0x281, 0x282, 0x284, 0x285, 0x286, 0x287, 0x288, 0x289,
+
+    0x28b, 0x28c, 0x28d, 0x28e, 0x28f, 0x290, 0x292, 0x293,   // 11
+    0x294, 0x295, 0x296, 0x298, 0x299, 0x29a, 0x29b, 0x29c,
+    0x29e, 0x29f, 0x2a0, 0x2a1, 0x2a2, 0x2a4, 0x2a5, 0x2a6,
+    0x2a7, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ae, 0x2af, 0x2b0,
+
+    0x2b1, 0x2b2, 0x2b4, 0x2b5, 0x2b6, 0x2b7, 0x2b9, 0x2ba,   // 12
+    0x2bb, 0x2bd, 0x2be, 0x2bf, 0x2c0, 0x2c2, 0x2c3, 0x2c4,
+    0x2c5, 0x2c7, 0x2c8, 0x2c9, 0x2cb, 0x2cc, 0x2cd, 0x2ce,
+    0x2d0, 0x2d1, 0x2d2, 0x2d4, 0x2d5, 0x2d6, 0x2d8, 0x2d9,
+
+    0x2da, 0x2dc, 0x2dd, 0x2de, 0x2e0, 0x2e1, 0x2e2, 0x2e4,   // 13
+    0x2e5, 0x2e6, 0x2e8, 0x2e9, 0x2ea, 0x2ec, 0x2ed, 0x2ee,
+    0x2f0, 0x2f1, 0x2f2, 0x2f4, 0x2f5, 0x2f6, 0x2f8, 0x2f9,
+    0x2fb, 0x2fc, 0x2fd, 0x2ff, 0x300, 0x302, 0x303, 0x304,
+
+    0x306, 0x307, 0x309, 0x30a, 0x30b, 0x30d, 0x30e, 0x310,   // 14
+    0x311, 0x312, 0x314, 0x315, 0x317, 0x318, 0x31a, 0x31b,
+    0x31c, 0x31e, 0x31f, 0x321, 0x322, 0x324, 0x325, 0x327,
+    0x328, 0x329, 0x32b, 0x32c, 0x32e, 0x32f, 0x331, 0x332,
+
+    0x334, 0x335, 0x337, 0x338, 0x33a, 0x33b, 0x33d, 0x33e,   // 15
+    0x340, 0x341, 0x343, 0x344, 0x346, 0x347, 0x349, 0x34a,
+    0x34c, 0x34d, 0x34f, 0x350, 0x352, 0x353, 0x355, 0x357,
+    0x358, 0x35a, 0x35b, 0x35d, 0x35e, 0x360, 0x361, 0x363,
+
+    0x365, 0x366, 0x368, 0x369, 0x36b, 0x36c, 0x36e, 0x370,   // 16
+    0x371, 0x373, 0x374, 0x376, 0x378, 0x379, 0x37b, 0x37c,
+    0x37e, 0x380, 0x381, 0x383, 0x384, 0x386, 0x388, 0x389,
+    0x38b, 0x38d, 0x38e, 0x390, 0x392, 0x393, 0x395, 0x397,
+
+    0x398, 0x39a, 0x39c, 0x39d, 0x39f, 0x3a1, 0x3a2, 0x3a4,   // 17
+    0x3a6, 0x3a7, 0x3a9, 0x3ab, 0x3ac, 0x3ae, 0x3b0, 0x3b1,
+    0x3b3, 0x3b5, 0x3b7, 0x3b8, 0x3ba, 0x3bc, 0x3bd, 0x3bf,
+    0x3c1, 0x3c3, 0x3c4, 0x3c6, 0x3c8, 0x3ca, 0x3cb, 0x3cd,
+
+    // The last note has an incomplete range, and loops round back to
+    // the start.  Note that the last value is actually a buffer overrun
+    // and does not fit with the other values.
+
+    0x3cf, 0x3d1, 0x3d2, 0x3d4, 0x3d6, 0x3d8, 0x3da, 0x3db,   // 18
+    0x3dd, 0x3df, 0x3e1, 0x3e3, 0x3e4, 0x3e6, 0x3e8, 0x3ea,
+    0x3ec, 0x3ed, 0x3ef, 0x3f1, 0x3f3, 0x3f5, 0x3f6, 0x3f8,
+    0x3fa, 0x3fc, 0x3fe, 0x36c,
+};
+
+// Mapping from MIDI volume level to OPL level value.
+
+static const unsigned int volume_mapping_table[] = {
+    0, 1, 3, 5, 6, 8, 10, 11,
+    13, 14, 16, 17, 19, 20, 22, 23,
+    25, 26, 27, 29, 30, 32, 33, 34,
+    36, 37, 39, 41, 43, 45, 47, 49,
+    50, 52, 54, 55, 57, 59, 60, 61,
+    63, 64, 66, 67, 68, 69, 71, 72,
+    73, 74, 75, 76, 77, 79, 80, 81,
+    82, 83, 84, 84, 85, 86, 87, 88,
+    89, 90, 91, 92, 92, 93, 94, 95,
+    96, 96, 97, 98, 99, 99, 100, 101,
+    101, 102, 103, 103, 104, 105, 105, 106,
+    107, 107, 108, 109, 109, 110, 110, 111,
+    112, 112, 113, 113, 114, 114, 115, 115,
+    116, 117, 117, 118, 118, 119, 119, 120,
+    120, 121, 121, 122, 122, 123, 123, 123,
+    124, 124, 125, 125, 126, 126, 127, 127
+};
+
+static boolean music_initialized = false;
+
+//static boolean musicpaused = false;
+static int current_music_volume;
+
+// GENMIDI lump instrument data:
+
+static genmidi_instr_t *main_instrs;
+static genmidi_instr_t *percussion_instrs;
+static char (*main_instr_names)[32];
+static char (*percussion_names)[32];
+
+// Voices:
+
+static opl_voice_t voices[OPL_NUM_VOICES];
+static opl_voice_t *voice_free_list;
+static opl_voice_t *voice_alloced_list;
+
+// Track data for playing tracks:
+
+static opl_track_data_t *tracks;
+static unsigned int num_tracks = 0;
+static unsigned int running_tracks = 0;
+static boolean song_looping;
+
+// Tempo control variables
+
+static unsigned int ticks_per_beat;
+static unsigned int us_per_beat;
+
+// Mini-log of recently played percussion instruments:
+
+static uint8_t last_perc[PERCUSSION_LOG_LEN];
+static unsigned int last_perc_count;
+
+// Configuration file variable, containing the port number for the
+// adlib chip.
+
+int opl_io_port = 0x388;
+
+// Load instrument table from GENMIDI lump:
+
+static boolean LoadInstrumentTable(void)
+{
+    byte *lump;
+
+    lump = W_CacheLumpName("GENMIDI", PU_STATIC);
+
+    // Check header
+
+    if (strncmp((char *) lump, GENMIDI_HEADER, strlen(GENMIDI_HEADER)) != 0)
+    {
+        W_ReleaseLumpName("GENMIDI");
+
+        return false;
+    }
+
+    main_instrs = (genmidi_instr_t *) (lump + strlen(GENMIDI_HEADER));
+    percussion_instrs = main_instrs + GENMIDI_NUM_INSTRS;
+    main_instr_names = (char (*)[32]) (percussion_instrs + GENMIDI_NUM_PERCUSSION);
+    percussion_names = main_instr_names + GENMIDI_NUM_INSTRS;
+
+    return true;
+}
+
+// Get the next available voice from the freelist.
+
+static opl_voice_t *GetFreeVoice(void)
+{
+    opl_voice_t *result;
+
+    // None available?
+
+    if (voice_free_list == NULL)
+    {
+        return NULL;
+    }
+
+    // Remove from free list
+
+    result = voice_free_list;
+    voice_free_list = voice_free_list->next;
+
+    // Add to allocated list
+
+    result->next = voice_alloced_list;
+    voice_alloced_list = result;
+
+    return result;
+}
+
+// Remove a voice from the allocated voices list.
+
+static void RemoveVoiceFromAllocedList(opl_voice_t *voice)
+{
+    opl_voice_t **rover;
+
+    rover = &voice_alloced_list;
+
+    // Search the list until we find the voice, then remove it.
+
+    while (*rover != NULL)
+    {
+        if (*rover == voice)
+        {
+            *rover = voice->next;
+            voice->next = NULL;
+            break;
+        }
+
+        rover = &(*rover)->next;
+    }
+}
+
+// Release a voice back to the freelist.
+
+static void ReleaseVoice(opl_voice_t *voice)
+{
+    opl_voice_t **rover;
+
+    voice->channel = NULL;
+    voice->note = 0;
+
+    // Remove from alloced list.
+
+    RemoveVoiceFromAllocedList(voice);
+
+    // Search to the end of the freelist (This is how Doom behaves!)
+
+    rover = &voice_free_list;
+
+    while (*rover != NULL)
+    {
+        rover = &(*rover)->next;
+    }
+
+    *rover = voice;
+    voice->next = NULL;
+}
+
+// Load data to the specified operator
+
+static void LoadOperatorData(int operator, genmidi_op_t *data,
+                             boolean max_level)
+{
+    int level;
+
+    // The scale and level fields must be combined for the level register.
+    // For the carrier wave we always set the maximum level.
+
+    level = (data->scale & 0xc0) | (data->level & 0x3f);
+
+    if (max_level)
+    {
+        level |= 0x3f;
+    }
+
+    OPL_WriteRegister(OPL_REGS_LEVEL + operator, level);
+    OPL_WriteRegister(OPL_REGS_TREMOLO + operator, data->tremolo);
+    OPL_WriteRegister(OPL_REGS_ATTACK + operator, data->attack);
+    OPL_WriteRegister(OPL_REGS_SUSTAIN + operator, data->sustain);
+    OPL_WriteRegister(OPL_REGS_WAVEFORM + operator, data->waveform);
+}
+
+// Set the instrument for a particular voice.
+
+static void SetVoiceInstrument(opl_voice_t *voice,
+                               genmidi_instr_t *instr,
+                               unsigned int instr_voice)
+{
+    genmidi_voice_t *data;
+    unsigned int modulating;
+
+    // Instrument already set for this channel?
+
+    if (voice->current_instr == instr
+     && voice->current_instr_voice == instr_voice)
+    {
+        return;
+    }
+
+    voice->current_instr = instr;
+    voice->current_instr_voice = instr_voice;
+
+    data = &instr->voices[instr_voice];
+
+    // Are we usind modulated feedback mode?
+
+    modulating = (data->feedback & 0x01) == 0;
+
+    // Doom loads the second operator first, then the first.
+    // The carrier is set to minimum volume until the voice volume
+    // is set in SetVoiceVolume (below).  If we are not using
+    // modulating mode, we must set both to minimum volume.
+
+    LoadOperatorData(voice->op2, &data->carrier, true);
+    LoadOperatorData(voice->op1, &data->modulator, !modulating);
+
+    // Set feedback register that control the connection between the
+    // two operators.  Turn on bits in the upper nybble; I think this
+    // is for OPL3, where it turns on channel A/B.
+
+    OPL_WriteRegister(OPL_REGS_FEEDBACK + voice->index,
+                      data->feedback | 0x30);
+
+    // Hack to force a volume update.
+
+    voice->reg_volume = 999;
+}
+
+static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume)
+{
+    genmidi_voice_t *opl_voice;
+    unsigned int full_volume;
+    unsigned int op_volume;
+    unsigned int reg_volume;
+
+    voice->note_volume = volume;
+
+    opl_voice = &voice->current_instr->voices[voice->current_instr_voice];
+
+    // Multiply note volume and channel volume to get the actual volume.
+
+    full_volume = (volume_mapping_table[voice->note_volume]
+                   * volume_mapping_table[voice->channel->volume]
+                   * volume_mapping_table[current_music_volume]) / (127 * 127);
+
+    // The volume of each instrument can be controlled via GENMIDI:
+
+    op_volume = 0x3f - opl_voice->carrier.level;
+
+    // The volume value to use in the register:
+
+    reg_volume = (op_volume * full_volume) / 128;
+    reg_volume = (0x3f - reg_volume) | opl_voice->carrier.scale;
+
+    // Update the volume register(s) if necessary.
+
+    if (reg_volume != voice->reg_volume)
+    {
+        voice->reg_volume = reg_volume;
+
+        OPL_WriteRegister(OPL_REGS_LEVEL + voice->op2, reg_volume);
+
+        // If we are using non-modulated feedback mode, we must set the
+        // volume for both voices.
+        // Note that the same register volume value is written for
+        // both voices, always calculated from the carrier's level
+        // value.
+
+        if ((opl_voice->feedback & 0x01) != 0)
+        {
+            OPL_WriteRegister(OPL_REGS_LEVEL + voice->op1, reg_volume);
+        }
+    }
+}
+
+// Initialize the voice table and freelist
+
+static void InitVoices(void)
+{
+    int i;
+
+    // Start with an empty free list.
+
+    voice_free_list = NULL;
+
+    // Initialize each voice.
+
+    for (i=0; i<OPL_NUM_VOICES; ++i)
+    {
+        voices[i].index = i;
+        voices[i].op1 = voice_operators[0][i];
+        voices[i].op2 = voice_operators[1][i];
+        voices[i].current_instr = NULL;
+
+        // Add this voice to the freelist.
+
+        ReleaseVoice(&voices[i]);
+    }
+}
+
+// Set music volume (0 - 127)
+
+static void I_OPL_SetMusicVolume(int volume)
+{
+    unsigned int i;
+
+    // Internal state variable.
+
+    current_music_volume = volume;
+
+    // Update the volume of all voices.
+
+    for (i=0; i<OPL_NUM_VOICES; ++i)
+    {
+        if (voices[i].channel != NULL)
+        {
+            SetVoiceVolume(&voices[i], voices[i].note_volume);
+        }
+    }
+}
+
+static void VoiceKeyOff(opl_voice_t *voice)
+{
+    OPL_WriteRegister(OPL_REGS_FREQ_2 + voice->index, voice->freq >> 8);
+}
+
+// Get the frequency that we should be using for a voice.
+
+static void KeyOffEvent(opl_track_data_t *track, midi_event_t *event)
+{
+    opl_channel_data_t *channel;
+    unsigned int key;
+    unsigned int i;
+
+/*
+    printf("note off: channel %i, %i, %i\n",
+           event->data.channel.channel,
+           event->data.channel.param1,
+           event->data.channel.param2);
+*/
+
+    channel = &track->channels[event->data.channel.channel];
+    key = event->data.channel.param1;
+
+    // Turn off voices being used to play this key.
+    // If it is a double voice instrument there will be two.
+
+    for (i=0; i<OPL_NUM_VOICES; ++i)
+    {
+        if (voices[i].channel == channel && voices[i].key == key)
+        {
+            VoiceKeyOff(&voices[i]);
+
+            // Finished with this voice now.
+
+            ReleaseVoice(&voices[i]);
+        }
+    }
+}
+
+// Compare the priorities of channels, returning either -1, 0 or 1.
+
+static int CompareChannelPriorities(opl_channel_data_t *chan1,
+                                    opl_channel_data_t *chan2)
+{
+    // TODO ...
+
+    return 1;
+}
+
+// When all voices are in use, we must discard an existing voice to
+// play a new note.  Find and free an existing voice.  The channel
+// passed to the function is the channel for the new note to be
+// played.
+
+static opl_voice_t *ReplaceExistingVoice(opl_channel_data_t *channel)
+{
+    opl_voice_t *rover;
+    opl_voice_t *result;
+
+    // Check the allocated voices, if we find an instrument that is
+    // of a lower priority to the new instrument, discard it.
+    // If a voice is being used to play the second voice of an instrument,
+    // use that, as second voices are non-essential.
+    // Lower numbered MIDI channels implicitly have a higher priority
+    // than higher-numbered channels, eg. MIDI channel 1 is never
+    // discarded for MIDI channel 2.
+
+    result = NULL;
+
+    for (rover = voice_alloced_list; rover != NULL; rover = rover->next)
+    {
+        if (rover->current_instr_voice != 0
+         || (rover->channel > channel
+             && CompareChannelPriorities(channel, rover->channel) > 0))
+        {
+            result = rover;
+            break;
+        }
+    }
+
+    // If we didn't find a voice, find an existing voice being used to
+    // play a note on the same channel, and use that.
+
+    if (result == NULL)
+    {
+        for (rover = voice_alloced_list; rover != NULL; rover = rover->next)
+        {
+            if (rover->channel == channel)
+            {
+                result = rover;
+                break;
+            }
+        }
+    }
+
+    // Still nothing found?  Give up and just use the first voice in
+    // the list.
+
+    if (result == NULL)
+    {
+        result = voice_alloced_list;
+    }
+
+    // Stop playing this voice playing and release it back to the free
+    // list.
+
+    VoiceKeyOff(result);
+    ReleaseVoice(result);
+
+    // Re-allocate the voice again and return it.
+
+    return GetFreeVoice();
+}
+
+
+static unsigned int FrequencyForVoice(opl_voice_t *voice)
+{
+    genmidi_voice_t *gm_voice;
+    unsigned int freq_index;
+    unsigned int octave;
+    unsigned int sub_index;
+    unsigned int note;
+
+    note = voice->note;
+
+    // Apply note offset.
+    // Don't apply offset if the instrument is a fixed note instrument.
+
+    gm_voice = &voice->current_instr->voices[voice->current_instr_voice];
+
+    if ((SHORT(voice->current_instr->flags) & GENMIDI_FLAG_FIXED) == 0)
+    {
+        note += (signed short) SHORT(gm_voice->base_note_offset);
+    }
+
+    // Avoid possible overflow due to base note offset:
+
+    if (note > 0x7f)
+    {
+        note = voice->note;
+    }
+
+    freq_index = 64 + 32 * note + voice->channel->bend;
+
+    // If this is the second voice of a double voice instrument, the
+    // frequency index can be adjusted by the fine tuning field.
+
+    if (voice->current_instr_voice != 0)
+    {
+        freq_index += (voice->current_instr->fine_tuning / 2) - 64;
+    }
+
+    // The first 7 notes use the start of the table, while
+    // consecutive notes loop around the latter part.
+
+    if (freq_index < 284)
+    {
+        return frequency_curve[freq_index];
+    }
+
+    sub_index = (freq_index - 284) % (12 * 32);
+    octave = (freq_index - 284) / (12 * 32);
+
+    // Once the seventh octave is reached, things break down.
+    // We can only go up to octave 7 as a maximum anyway (the OPL
+    // register only has three bits for octave number), but for the
+    // notes in octave 7, the first five bits have octave=7, the
+    // following notes have octave=6.  This 7/6 pattern repeats in
+    // following octaves (which are technically impossible to
+    // represent anyway).
+
+    if (octave >= 7)
+    {
+        if (sub_index < 5)
+        {
+            octave = 7;
+        }
+        else
+        {
+            octave = 6;
+        }
+    }
+
+    // Calculate the resulting register value to use for the frequency.
+
+    return frequency_curve[sub_index + 284] | (octave << 10);
+}
+
+// Update the frequency that a voice is programmed to use.
+
+static void UpdateVoiceFrequency(opl_voice_t *voice)
+{
+    unsigned int freq;
+
+    // Calculate the frequency to use for this voice and update it
+    // if neccessary.
+
+    freq = FrequencyForVoice(voice);
+
+    if (voice->freq != freq)
+    {
+        OPL_WriteRegister(OPL_REGS_FREQ_1 + voice->index, freq & 0xff);
+        OPL_WriteRegister(OPL_REGS_FREQ_2 + voice->index, (freq >> 8) | 0x20);
+
+        voice->freq = freq;
+    }
+}
+
+// Program a single voice for an instrument.  For a double voice 
+// instrument (GENMIDI_FLAG_2VOICE), this is called twice for each
+// key on event.
+
+static void VoiceKeyOn(opl_channel_data_t *channel,
+                       genmidi_instr_t *instrument,
+                       unsigned int instrument_voice,
+                       unsigned int key,
+                       unsigned int volume)
+{
+    opl_voice_t *voice;
+
+    // Find a voice to use for this new note.
+
+    voice = GetFreeVoice();
+
+    // If there are no more voices left, we must decide what to do.
+    // If this is the first voice of the instrument, free an existing
+    // voice and use that.  Otherwise, if this is the second voice,
+    // it isn't as important; just discard it.
+
+    if (voice == NULL)
+    {
+        if (instrument_voice == 0)
+        {
+            voice = ReplaceExistingVoice(channel);
+        }
+        else
+        {
+            return;
+        }
+    }
+
+    voice->channel = channel;
+    voice->key = key;
+
+    // Work out the note to use.  This is normally the same as
+    // the key, unless it is a fixed pitch instrument.
+
+    if ((SHORT(instrument->flags) & GENMIDI_FLAG_FIXED) != 0)
+    {
+        voice->note = instrument->fixed_note;
+    }
+    else
+    {
+        voice->note = key;
+    }
+
+    // Program the voice with the instrument data:
+
+    SetVoiceInstrument(voice, instrument, instrument_voice);
+
+    // Set the volume level.
+
+    SetVoiceVolume(voice, volume);
+
+    // Write the frequency value to turn the note on.
+
+    voice->freq = 0;
+    UpdateVoiceFrequency(voice);
+}
+
+static void KeyOnEvent(opl_track_data_t *track, midi_event_t *event)
+{
+    genmidi_instr_t *instrument;
+    opl_channel_data_t *channel;
+    unsigned int key;
+    unsigned int volume;
+
+/*
+    printf("note on: channel %i, %i, %i\n",
+           event->data.channel.channel,
+           event->data.channel.param1,
+           event->data.channel.param2);
+*/
+
+    key = event->data.channel.param1;
+    volume = event->data.channel.param2;
+
+    // A volume of zero means key off. Some MIDI tracks, eg. the ones
+    // in AV.wad, use a second key on with a volume of zero to mean
+    // key off.
+    if (volume <= 0)
+    {
+        KeyOffEvent(track, event);
+        return;
+    }
+
+    // The channel.
+    channel = &track->channels[event->data.channel.channel];
+
+    // Percussion channel (10) is treated differently.
+
+    if (event->data.channel.channel == 9)
+    {
+        if (key < 35 || key > 81)
+        {
+            return;
+        }
+
+        instrument = &percussion_instrs[key - 35];
+
+        last_perc[last_perc_count] = key;
+        last_perc_count = (last_perc_count + 1) % PERCUSSION_LOG_LEN;
+    }
+    else
+    {
+        instrument = channel->instrument;
+    }
+
+    // Find and program a voice for this instrument.  If this
+    // is a double voice instrument, we must do this twice.
+
+    VoiceKeyOn(channel, instrument, 0, key, volume);
+
+    if ((SHORT(instrument->flags) & GENMIDI_FLAG_2VOICE) != 0)
+    {
+        VoiceKeyOn(channel, instrument, 1, key, volume);
+    }
+}
+
+static void ProgramChangeEvent(opl_track_data_t *track, midi_event_t *event)
+{
+    int channel;
+    int instrument;
+
+    // Set the instrument used on this channel.
+
+    channel = event->data.channel.channel;
+    instrument = event->data.channel.param1;
+    track->channels[channel].instrument = &main_instrs[instrument];
+
+    // TODO: Look through existing voices that are turned on on this
+    // channel, and change the instrument.
+}
+
+static void SetChannelVolume(opl_channel_data_t *channel, unsigned int volume)
+{
+    unsigned int i;
+
+    channel->volume = volume;
+
+    // Update all voices that this channel is using.
+
+    for (i=0; i<OPL_NUM_VOICES; ++i)
+    {
+        if (voices[i].channel == channel)
+        {
+            SetVoiceVolume(&voices[i], voices[i].note_volume);
+        }
+    }
+}
+
+// Handler for the MIDI_CONTROLLER_ALL_NOTES_OFF channel event.
+static void AllNotesOff(opl_channel_data_t *channel, unsigned int param)
+{
+    unsigned int i;
+
+    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    {
+        if (voices[i].channel == channel)
+        {
+            VoiceKeyOff(&voices[i]);
+            ReleaseVoice(&voices[i]);
+        }
+    }
+}
+
+static void ControllerEvent(opl_track_data_t *track, midi_event_t *event)
+{
+    unsigned int controller;
+    unsigned int param;
+    opl_channel_data_t *channel;
+
+/*
+    printf("change controller: channel %i, %i, %i\n",
+           event->data.channel.channel,
+           event->data.channel.param1,
+           event->data.channel.param2);
+*/
+
+    channel = &track->channels[event->data.channel.channel];
+    controller = event->data.channel.param1;
+    param = event->data.channel.param2;
+
+    switch (controller)
+    {
+        case MIDI_CONTROLLER_MAIN_VOLUME:
+            SetChannelVolume(channel, param);
+            break;
+
+        case MIDI_CONTROLLER_ALL_NOTES_OFF:
+            AllNotesOff(channel, param);
+            break;
+
+        default:
+#ifdef OPL_MIDI_DEBUG
+            fprintf(stderr, "Unknown MIDI controller type: %i\n", controller);
+#endif
+            break;
+    }
+}
+
+// Process a pitch bend event.
+
+static void PitchBendEvent(opl_track_data_t *track, midi_event_t *event)
+{
+    opl_channel_data_t *channel;
+    unsigned int i;
+
+    // Update the channel bend value.  Only the MSB of the pitch bend
+    // value is considered: this is what Doom does.
+
+    channel = &track->channels[event->data.channel.channel];
+    channel->bend = event->data.channel.param2 - 64;
+
+    // Update all voices for this channel.
+
+    for (i=0; i<OPL_NUM_VOICES; ++i)
+    {
+        if (voices[i].channel == channel)
+        {
+            UpdateVoiceFrequency(&voices[i]);
+        }
+    }
+}
+
+static void MetaSetTempo(unsigned int tempo)
+{
+    OPL_AdjustCallbacks((float) us_per_beat / tempo);
+    us_per_beat = tempo;
+}
+
+// Process a meta event.
+
+static void MetaEvent(opl_track_data_t *track, midi_event_t *event)
+{
+    byte *data = event->data.meta.data;
+    unsigned int data_len = event->data.meta.length;
+
+    switch (event->data.meta.type)
+    {
+        // Things we can just ignore.
+
+        case MIDI_META_SEQUENCE_NUMBER:
+        case MIDI_META_TEXT:
+        case MIDI_META_COPYRIGHT:
+        case MIDI_META_TRACK_NAME:
+        case MIDI_META_INSTR_NAME:
+        case MIDI_META_LYRICS:
+        case MIDI_META_MARKER:
+        case MIDI_META_CUE_POINT:
+        case MIDI_META_SEQUENCER_SPECIFIC:
+            break;
+
+        case MIDI_META_SET_TEMPO:
+            if (data_len == 3)
+            {
+                MetaSetTempo((data[0] << 16) | (data[1] << 8) | data[2]);
+            }
+            break;
+
+        // End of track - actually handled when we run out of events
+        // in the track, see below.
+
+        case MIDI_META_END_OF_TRACK:
+            break;
+
+        default:
+#ifdef OPL_MIDI_DEBUG
+            fprintf(stderr, "Unknown MIDI meta event type: %i\n",
+                            event->data.meta.type);
+#endif
+            break;
+    }
+}
+
+// Process a MIDI event from a track.
+
+static void ProcessEvent(opl_track_data_t *track, midi_event_t *event)
+{
+    switch (event->event_type)
+    {
+        case MIDI_EVENT_NOTE_OFF:
+            KeyOffEvent(track, event);
+            break;
+
+        case MIDI_EVENT_NOTE_ON:
+            KeyOnEvent(track, event);
+            break;
+
+        case MIDI_EVENT_CONTROLLER:
+            ControllerEvent(track, event);
+            break;
+
+        case MIDI_EVENT_PROGRAM_CHANGE:
+            ProgramChangeEvent(track, event);
+            break;
+
+        case MIDI_EVENT_PITCH_BEND:
+            PitchBendEvent(track, event);
+            break;
+
+        case MIDI_EVENT_META:
+            MetaEvent(track, event);
+            break;
+
+        // SysEx events can be ignored.
+
+        case MIDI_EVENT_SYSEX:
+        case MIDI_EVENT_SYSEX_SPLIT:
+            break;
+
+        default:
+#ifdef OPL_MIDI_DEBUG
+            fprintf(stderr, "Unknown MIDI event type %i\n", event->event_type);
+#endif
+            break;
+    }
+}
+
+static void ScheduleTrack(opl_track_data_t *track);
+
+// Restart a song from the beginning.
+
+static void RestartSong(void *unused)
+{
+    unsigned int i;
+
+    running_tracks = num_tracks;
+
+    for (i=0; i<num_tracks; ++i)
+    {
+        MIDI_RestartIterator(tracks[i].iter);
+        ScheduleTrack(&tracks[i]);
+    }
+}
+
+// Callback function invoked when another event needs to be read from
+// a track.
+
+static void TrackTimerCallback(void *arg)
+{
+    opl_track_data_t *track = arg;
+    midi_event_t *event;
+
+    // Get the next event and process it.
+
+    if (!MIDI_GetNextEvent(track->iter, &event))
+    {
+        return;
+    }
+
+    ProcessEvent(track, event);
+
+    // End of track?
+
+    if (event->event_type == MIDI_EVENT_META
+     && event->data.meta.type == MIDI_META_END_OF_TRACK)
+    {
+        --running_tracks;
+
+        // When all tracks have finished, restart the song.
+        // Don't restart the song immediately, but wait for 5ms
+        // before triggering a restart.  Otherwise it is possible
+        // to construct an empty MIDI file that causes the game
+        // to lock up in an infinite loop. (5ms should be short
+        // enough not to be noticeable by the listener).
+
+        if (running_tracks <= 0 && song_looping)
+        {
+            OPL_SetCallback(5000, RestartSong, NULL);
+        }
+
+        return;
+    }
+
+    // Reschedule the callback for the next event in the track.
+
+    ScheduleTrack(track);
+}
+
+static void ScheduleTrack(opl_track_data_t *track)
+{
+    unsigned int nticks;
+    uint64_t us;
+
+    // Get the number of microseconds until the next event.
+
+    nticks = MIDI_GetDeltaTime(track->iter);
+    us = ((uint64_t) nticks * us_per_beat) / ticks_per_beat;
+
+    // Set a timer to be invoked when the next event is
+    // ready to play.
+
+    OPL_SetCallback(us, TrackTimerCallback, track);
+}
+
+// Initialize a channel.
+
+static void InitChannel(opl_track_data_t *track, opl_channel_data_t *channel)
+{
+    // TODO: Work out sensible defaults?
+
+    channel->instrument = &main_instrs[0];
+    channel->volume = 127;
+    channel->bend = 0;
+}
+
+// Start a MIDI track playing:
+
+static void StartTrack(midi_file_t *file, unsigned int track_num)
+{
+    opl_track_data_t *track;
+    unsigned int i;
+
+    track = &tracks[track_num];
+    track->iter = MIDI_IterateTrack(file, track_num);
+
+    for (i=0; i<MIDI_CHANNELS_PER_TRACK; ++i)
+    {
+        InitChannel(track, &track->channels[i]);
+    }
+
+    // Schedule the first event.
+
+    ScheduleTrack(track);
+}
+
+// Start playing a mid
+
+static void I_OPL_PlaySong(void *handle, boolean looping)
+{
+    midi_file_t *file;
+    unsigned int i;
+
+    if (!music_initialized || handle == NULL)
+    {
+        return;
+    }
+
+    file = handle;
+
+    // Allocate track data.
+
+    tracks = malloc(MIDI_NumTracks(file) * sizeof(opl_track_data_t));
+
+    num_tracks = MIDI_NumTracks(file);
+    running_tracks = num_tracks;
+    song_looping = looping;
+
+    ticks_per_beat = MIDI_GetFileTimeDivision(file);
+
+    // Default is 120 bpm.
+    // TODO: this is wrong
+
+    us_per_beat = 500 * 1000;
+
+    for (i=0; i<num_tracks; ++i)
+    {
+        StartTrack(file, i);
+    }
+}
+
+static void I_OPL_PauseSong(void)
+{
+    unsigned int i;
+
+    if (!music_initialized)
+    {
+        return;
+    }
+
+    // Pause OPL callbacks.
+
+    OPL_SetPaused(1);
+
+    // Turn off all main instrument voices (not percussion).
+    // This is what Vanilla does.
+
+    for (i=0; i<OPL_NUM_VOICES; ++i)
+    {
+        if (voices[i].channel != NULL
+         && voices[i].current_instr < percussion_instrs)
+        {
+            VoiceKeyOff(&voices[i]);
+        }
+    }
+}
+
+static void I_OPL_ResumeSong(void)
+{
+    if (!music_initialized)
+    {
+        return;
+    }
+
+    OPL_SetPaused(0);
+}
+
+static void I_OPL_StopSong(void)
+{
+    unsigned int i;
+
+    if (!music_initialized)
+    {
+        return;
+    }
+
+    OPL_Lock();
+
+    // Stop all playback.
+
+    OPL_ClearCallbacks();
+
+    // Free all voices.
+
+    for (i=0; i<OPL_NUM_VOICES; ++i)
+    {
+        if (voices[i].channel != NULL)
+        {
+            VoiceKeyOff(&voices[i]);
+            ReleaseVoice(&voices[i]);
+        }
+    }
+
+    // Free all track data.
+
+    for (i=0; i<num_tracks; ++i)
+    {
+        MIDI_FreeIterator(tracks[i].iter);
+    }
+
+    free(tracks);
+
+    tracks = NULL;
+    num_tracks = 0;
+
+    OPL_Unlock();
+}
+
+static void I_OPL_UnRegisterSong(void *handle)
+{
+    if (!music_initialized)
+    {
+        return;
+    }
+
+    if (handle != NULL)
+    {
+        MIDI_FreeFile(handle);
+    }
+}
+
+// Determine whether memory block is a .mid file 
+
+static boolean IsMid(byte *mem, int len)
+{
+    return len > 4 && !memcmp(mem, "MThd", 4);
+}
+
+static boolean ConvertMus(byte *musdata, int len, char *filename)
+{
+    MEMFILE *instream;
+    MEMFILE *outstream;
+    void *outbuf;
+    size_t outbuf_len;
+    int result;
+
+    instream = mem_fopen_read(musdata, len);
+    outstream = mem_fopen_write();
+
+    result = mus2mid(instream, outstream);
+
+    if (result == 0)
+    {
+        mem_get_buf(outstream, &outbuf, &outbuf_len);
+
+        M_WriteFile(filename, outbuf, outbuf_len);
+    }
+
+    mem_fclose(instream);
+    mem_fclose(outstream);
+
+    return result;
+}
+
+static void *I_OPL_RegisterSong(void *data, int len)
+{
+    midi_file_t *result;
+    char *filename;
+
+    if (!music_initialized)
+    {
+        return NULL;
+    }
+
+    // MUS files begin with "MUS"
+    // Reject anything which doesnt have this signature
+
+    filename = M_TempFile("doom.mid");
+
+    if (IsMid(data, len) && len < MAXMIDLENGTH)
+    {
+        M_WriteFile(filename, data, len);
+    }
+    else
+    {
+       // Assume a MUS file and try to convert
+
+        ConvertMus(data, len, filename);
+    }
+
+    result = MIDI_LoadFile(filename);
+
+    if (result == NULL)
+    {
+        fprintf(stderr, "I_OPL_RegisterSong: Failed to load MID.\n");
+    }
+
+    // remove file now
+
+    remove(filename);
+    free(filename);
+
+    return result;
+}
+
+// Is the song playing?
+
+static boolean I_OPL_MusicIsPlaying(void)
+{
+    if (!music_initialized)
+    {
+        return false;
+    }
+
+    return num_tracks > 0;
+}
+
+// Shutdown music
+
+static void I_OPL_ShutdownMusic(void)
+{
+    if (music_initialized)
+    {
+        // Stop currently-playing track, if there is one:
+
+        I_OPL_StopSong();
+
+        OPL_Shutdown();
+
+        // Release GENMIDI lump
+
+        W_ReleaseLumpName("GENMIDI");
+
+        music_initialized = false;
+    }
+}
+
+// Initialize music subsystem
+
+static boolean I_OPL_InitMusic(void)
+{
+    OPL_SetSampleRate(snd_samplerate);
+
+    if (!OPL_Init(opl_io_port))
+    {
+        printf("Dude.  The Adlib isn't responding.\n");
+        return false;
+    }
+
+    // Load instruments from GENMIDI lump:
+
+    if (!LoadInstrumentTable())
+    {
+        OPL_Shutdown();
+        return false;
+    }
+
+    InitVoices();
+
+    tracks = NULL;
+    num_tracks = 0;
+    music_initialized = true;
+
+    return true;
+}
+
+static snddevice_t music_opl_devices[] =
+{
+    SNDDEVICE_ADLIB,
+    SNDDEVICE_SB,
+};
+
+music_module_t music_opl_module =
+{
+    music_opl_devices,
+    arrlen(music_opl_devices),
+    I_OPL_InitMusic,
+    I_OPL_ShutdownMusic,
+    I_OPL_SetMusicVolume,
+    I_OPL_PauseSong,
+    I_OPL_ResumeSong,
+    I_OPL_RegisterSong,
+    I_OPL_UnRegisterSong,
+    I_OPL_PlaySong,
+    I_OPL_StopSong,
+    I_OPL_MusicIsPlaying,
+    NULL,  // Poll
+};
+
+//----------------------------------------------------------------------
+//
+// Development / debug message generation, to help developing GENMIDI
+// lumps.
+//
+//----------------------------------------------------------------------
+
+static int NumActiveChannels(void)
+{
+    int i;
+
+    for (i = MIDI_CHANNELS_PER_TRACK - 1; i >= 0; --i)
+    {
+        if (tracks[0].channels[i].instrument != &main_instrs[0])
+        {
+            return i + 1;
+        }
+    }
+
+    return 0;
+}
+
+static int ChannelInUse(opl_channel_data_t *channel)
+{
+    opl_voice_t *voice;
+
+    for (voice = voice_alloced_list; voice != NULL; voice = voice->next)
+    {
+        if (voice->channel == channel)
+        {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+void I_OPL_DevMessages(char *result, size_t result_len)
+{
+    char tmp[80];
+    int instr_num;
+    int lines;
+    int i;
+
+    if (num_tracks == 0)
+    {
+        M_snprintf(result, result_len, "No OPL track!");
+        return;
+    }
+
+    M_snprintf(result, result_len, "Tracks:\n");
+    lines = 1;
+
+    for (i = 0; i < NumActiveChannels(); ++i)
+    {
+        if (tracks[0].channels[i].instrument == NULL)
+        {
+            continue;
+        }
+
+        instr_num = tracks[0].channels[i].instrument - main_instrs;
+
+        M_snprintf(tmp, sizeof(tmp),
+                   "chan %i: %c i#%i (%s)\n",
+                   i,
+                   ChannelInUse(&tracks[0].channels[i]) ? '\'' : ' ',
+                   instr_num + 1,
+                   main_instr_names[instr_num]);
+        M_StringConcat(result, tmp, result_len);
+
+        ++lines;
+    }
+
+    M_snprintf(tmp, sizeof(tmp), "\nLast percussion:\n");
+    M_StringConcat(result, tmp, result_len);
+    lines += 2;
+
+    i = (last_perc_count + PERCUSSION_LOG_LEN - 1) % PERCUSSION_LOG_LEN;
+
+    do {
+        if (last_perc[i] == 0)
+        {
+            break;
+        }
+
+        M_snprintf(tmp, sizeof(tmp),
+                   "%cp#%i (%s)\n",
+                   i == 0 ? '\'' : ' ',
+                   last_perc[i],
+                   percussion_names[last_perc[i] - 35]);
+        M_StringConcat(result, tmp, result_len);
+        ++lines;
+
+        i = (i + PERCUSSION_LOG_LEN - 1) % PERCUSSION_LOG_LEN;
+    } while (lines < 25 && i != last_perc_count);
+}
+
diff --git a/frosted-doom/i_pcsound.c b/frosted-doom/i_pcsound.c
new file mode 100644 (file)
index 0000000..a7a8381
--- /dev/null
@@ -0,0 +1,330 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//     System interface for PC speaker sound.
+//
+
+#include "SDL.h"
+#include <string.h>
+
+#include "doomtype.h"
+
+#include "deh_str.h"
+#include "i_sound.h"
+#include "m_misc.h"
+#include "w_wad.h"
+#include "z_zone.h"
+
+#include "pcsound.h"
+
+#define TIMER_FREQ 1193181 /* hz */
+
+static boolean pcs_initialized = false;
+
+static SDL_mutex *sound_lock;
+static boolean use_sfx_prefix;
+
+static uint8_t *current_sound_lump = NULL;
+static uint8_t *current_sound_pos = NULL;
+static unsigned int current_sound_remaining = 0;
+static int current_sound_handle = 0;
+static int current_sound_lump_num = -1;
+
+static const uint16_t divisors[] = {
+    0,
+    6818, 6628, 6449, 6279, 6087, 5906, 5736, 5575,
+    5423, 5279, 5120, 4971, 4830, 4697, 4554, 4435,
+    4307, 4186, 4058, 3950, 3836, 3728, 3615, 3519,
+    3418, 3323, 3224, 3131, 3043, 2960, 2875, 2794,
+    2711, 2633, 2560, 2485, 2415, 2348, 2281, 2213,
+    2153, 2089, 2032, 1975, 1918, 1864, 1810, 1757,
+    1709, 1659, 1612, 1565, 1521, 1478, 1435, 1395,
+    1355, 1316, 1280, 1242, 1207, 1173, 1140, 1107,
+    1075, 1045, 1015,  986,  959,  931,  905,  879,
+     854,  829,  806,  783,  760,  739,  718,  697,
+     677,  658,  640,  621,  604,  586,  570,  553,
+     538,  522,  507,  493,  479,  465,  452,  439,
+     427,  415,  403,  391,  380,  369,  359,  348,
+     339,  329,  319,  310,  302,  293,  285,  276,
+     269,  261,  253,  246,  239,  232,  226,  219,
+     213,  207,  201,  195,  190,  184,  179,
+};
+
+static void PCSCallbackFunc(int *duration, int *freq)
+{
+    unsigned int tone;
+
+    *duration = 1000 / 140;
+
+    if (SDL_LockMutex(sound_lock) < 0)
+    {
+        *freq = 0;
+        return;
+    }
+
+    if (current_sound_lump != NULL && current_sound_remaining > 0)
+    {
+        // Read the next tone
+
+        tone = *current_sound_pos;
+
+        // Use the tone -> frequency lookup table.  See pcspkr10.zip
+        // for a full discussion of this.
+        // Check we don't overflow the frequency table.
+
+        if (tone < arrlen(divisors) && divisors[tone] != 0)
+        {
+            *freq = (int) (TIMER_FREQ / divisors[tone]);
+        }
+        else
+        {
+            *freq = 0;
+        }
+
+        ++current_sound_pos;
+        --current_sound_remaining;
+    }
+    else
+    {
+        *freq = 0;
+    }
+
+    SDL_UnlockMutex(sound_lock);
+}
+
+static boolean CachePCSLump(sfxinfo_t *sfxinfo)
+{
+    int lumplen;
+    int headerlen;
+
+    // Free the current sound lump back to the cache
+    if (current_sound_lump != NULL)
+    {
+        W_ReleaseLumpNum(current_sound_lump_num);
+        current_sound_lump = NULL;
+    }
+
+    // Load from WAD
+
+    current_sound_lump = W_CacheLumpNum(sfxinfo->lumpnum, PU_STATIC);
+    lumplen = W_LumpLength(sfxinfo->lumpnum);
+
+    // Read header
+  
+    if (current_sound_lump[0] != 0x00 || current_sound_lump[1] != 0x00)
+    {
+        return false;
+    }
+
+    headerlen = (current_sound_lump[3] << 8) | current_sound_lump[2];
+
+    if (headerlen > lumplen - 4)
+    {
+        return false;
+    }
+
+    // Header checks out ok
+
+    current_sound_remaining = headerlen;
+    current_sound_pos = current_sound_lump + 4;
+    current_sound_lump_num = sfxinfo->lumpnum;
+
+    return true;
+}
+
+// These Doom PC speaker sounds are not played - this can be seen in the 
+// Heretic source code, where there are remnants of this left over
+// from Doom.
+
+static boolean IsDisabledSound(sfxinfo_t *sfxinfo)
+{
+    int i;
+    const char *disabled_sounds[] = {
+        "posact",
+        "bgact",
+        "dmact",
+        "dmpain",
+        "popain",
+        "sawidl",
+    };
+
+    for (i=0; i<arrlen(disabled_sounds); ++i)
+    {
+        if (!strcmp(sfxinfo->name, disabled_sounds[i]))
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static int I_PCS_StartSound(sfxinfo_t *sfxinfo,
+                            int channel,
+                            int vol,
+                            int sep)
+{
+    int result;
+
+    if (!pcs_initialized)
+    {
+        return -1;
+    }
+
+    if (IsDisabledSound(sfxinfo))
+    {
+        return -1;
+    }
+
+    if (SDL_LockMutex(sound_lock) < 0)
+    {
+        return -1;
+    }
+
+    result = CachePCSLump(sfxinfo);
+
+    if (result)
+    {
+        current_sound_handle = channel;
+    }
+
+    SDL_UnlockMutex(sound_lock);
+
+    if (result)
+    {
+        return channel;
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+static void I_PCS_StopSound(int handle)
+{
+    if (!pcs_initialized)
+    {
+        return;
+    }
+
+    if (SDL_LockMutex(sound_lock) < 0)
+    {
+        return;
+    }
+
+    // If this is the channel currently playing, immediately end it.
+
+    if (current_sound_handle == handle)
+    {
+        current_sound_remaining = 0;
+    }
+    
+    SDL_UnlockMutex(sound_lock);
+}
+
+//
+// Retrieve the raw data lump index
+//  for a given SFX name.
+//
+
+static int I_PCS_GetSfxLumpNum(sfxinfo_t* sfx)
+{
+    char namebuf[9];
+
+    if (use_sfx_prefix)
+    {
+        M_snprintf(namebuf, sizeof(namebuf), "dp%s", DEH_String(sfx->name));
+    }
+    else
+    {
+        M_StringCopy(namebuf, DEH_String(sfx->name), sizeof(namebuf));
+    }
+
+    return W_GetNumForName(namebuf);
+}
+
+
+static boolean I_PCS_SoundIsPlaying(int handle)
+{
+    if (!pcs_initialized)
+    {
+        return false;
+    }
+
+    if (handle != current_sound_handle)
+    {
+        return false;
+    }
+
+    return current_sound_lump != NULL && current_sound_remaining > 0;
+}
+
+static boolean I_PCS_InitSound(boolean _use_sfx_prefix)
+{
+    use_sfx_prefix = _use_sfx_prefix;
+
+    // Use the sample rate from the configuration file
+
+    PCSound_SetSampleRate(snd_samplerate);
+
+    // Initialize the PC speaker subsystem.
+
+    pcs_initialized = PCSound_Init(PCSCallbackFunc);
+
+    if (pcs_initialized)
+    {
+        sound_lock = SDL_CreateMutex();
+    }
+
+    return pcs_initialized;
+}
+
+static void I_PCS_ShutdownSound(void)
+{
+    if (pcs_initialized)
+    {
+        PCSound_Shutdown();
+    }
+}
+
+static void I_PCS_UpdateSound(void)
+{
+    // no-op.
+}
+
+void I_PCS_UpdateSoundParams(int channel, int vol, int sep)
+{
+    // no-op.
+}
+
+static snddevice_t sound_pcsound_devices[] = 
+{
+    SNDDEVICE_PCSPEAKER,
+};
+
+sound_module_t sound_pcsound_module = 
+{
+    sound_pcsound_devices,
+    arrlen(sound_pcsound_devices),
+    I_PCS_InitSound,
+    I_PCS_ShutdownSound,
+    I_PCS_GetSfxLumpNum,
+    I_PCS_UpdateSound,
+    I_PCS_UpdateSoundParams,
+    I_PCS_StartSound,
+    I_PCS_StopSound,
+    I_PCS_SoundIsPlaying,
+};
+
diff --git a/frosted-doom/i_scale.c b/frosted-doom/i_scale.c
new file mode 100644 (file)
index 0000000..f88c694
--- /dev/null
@@ -0,0 +1,1452 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//     Screen scale-up code: 
+//         1x,2x,3x,4x pixel doubling
+//         Aspect ratio-correcting stretch functions
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomtype.h"
+
+#include "i_video.h"
+#include "m_argv.h"
+#include "z_zone.h"
+
+#if defined(_MSC_VER) && !defined(__cplusplus)
+#define inline __inline
+#endif
+
+// Should be I_VideoBuffer
+
+static byte *src_buffer;
+
+// Destination buffer, ie. screen->pixels.
+
+static byte *dest_buffer;
+
+// Pitch of destination buffer, ie. screen->pitch.
+
+static int dest_pitch;
+
+// Lookup tables used for aspect ratio correction stretching code.
+// stretch_tables[0] : 20% / 80%
+// stretch_tables[1] : 40% / 60%
+// All other combinations can be reached from these two tables.
+
+static byte *stretch_tables[2] = { NULL, NULL };
+
+// 50%/50% stretch table, for 800x600 squash mode
+
+static byte *half_stretch_table = NULL;
+
+// Called to set the source and destination buffers before doing the
+// scale.
+
+void I_InitScale(byte *_src_buffer, byte *_dest_buffer, int _dest_pitch)
+{
+    src_buffer = _src_buffer;
+    dest_buffer = _dest_buffer;
+    dest_pitch = _dest_pitch;
+}
+
+//
+// Pixel doubling scale-up functions.
+//
+
+// 1x scale doesn't really do any scaling: it just copies the buffer
+// a line at a time for when pitch != SCREENWIDTH (!native_surface)
+
+static boolean I_Scale1x(int x1, int y1, int x2, int y2)
+{
+    byte *bufp, *screenp;
+    int y;
+    int w = x2 - x1;
+    
+    // Need to byte-copy from buffer into the screen buffer
+
+    bufp = src_buffer + y1 * SCREENWIDTH + x1;
+    screenp = (byte *) dest_buffer + y1 * dest_pitch + x1;
+
+    for (y=y1; y<y2; ++y)
+    {
+        memcpy(screenp, bufp, w);
+        screenp += dest_pitch;
+        bufp += SCREENWIDTH;
+    }
+
+    return true;
+}
+
+screen_mode_t mode_scale_1x = {
+    SCREENWIDTH, SCREENHEIGHT,
+    NULL,
+    I_Scale1x,
+    false,
+};
+
+// 2x scale (640x400)
+
+static boolean I_Scale2x(int x1, int y1, int x2, int y2)
+{
+    byte *bufp, *screenp, *screenp2;
+    int x, y;
+    int multi_pitch;
+
+    multi_pitch = dest_pitch * 2;
+    bufp = src_buffer + y1 * SCREENWIDTH + x1;
+    screenp = (byte *) dest_buffer + (y1 * dest_pitch + x1) * 2;
+    screenp2 = screenp + dest_pitch;
+
+    for (y=y1; y<y2; ++y)
+    {
+        byte *sp, *sp2, *bp;
+        sp = screenp;
+        sp2 = screenp2;
+        bp = bufp;
+
+        for (x=x1; x<x2; ++x)
+        {
+            *sp++ = *bp;  *sp++ = *bp;
+            *sp2++ = *bp; *sp2++ = *bp;
+            ++bp;
+        }
+        screenp += multi_pitch;
+        screenp2 += multi_pitch;
+        bufp += SCREENWIDTH;
+    }
+
+    return true;
+}
+
+screen_mode_t mode_scale_2x = {
+    SCREENWIDTH * 2, SCREENHEIGHT * 2,
+    NULL,
+    I_Scale2x,
+    false,
+};
+
+// 3x scale (960x600)
+
+static boolean I_Scale3x(int x1, int y1, int x2, int y2)
+{
+    byte *bufp, *screenp, *screenp2, *screenp3;
+    int x, y;
+    int multi_pitch;
+
+    multi_pitch = dest_pitch * 3;
+    bufp = src_buffer + y1 * SCREENWIDTH + x1;
+    screenp = (byte *) dest_buffer + (y1 * dest_pitch + x1) * 3;
+    screenp2 = screenp + dest_pitch;
+    screenp3 = screenp + dest_pitch * 2;
+
+    for (y=y1; y<y2; ++y)
+    {
+        byte *sp, *sp2, *sp3, *bp;
+        sp = screenp;
+        sp2 = screenp2;
+        sp3 = screenp3;
+        bp = bufp;
+
+        for (x=x1; x<x2; ++x)
+        {
+            *sp++ = *bp;  *sp++ = *bp;  *sp++ = *bp;
+            *sp2++ = *bp; *sp2++ = *bp; *sp2++ = *bp;
+            *sp3++ = *bp; *sp3++ = *bp; *sp3++ = *bp;
+            ++bp;
+        }
+        screenp += multi_pitch;
+        screenp2 += multi_pitch;
+        screenp3 += multi_pitch;
+        bufp += SCREENWIDTH;
+    }
+
+    return true;
+}
+
+screen_mode_t mode_scale_3x = {
+    SCREENWIDTH * 3, SCREENHEIGHT * 3,
+    NULL,
+    I_Scale3x,
+    false,
+};
+
+// 4x scale (1280x800)
+
+static boolean I_Scale4x(int x1, int y1, int x2, int y2)
+{
+    byte *bufp, *screenp, *screenp2, *screenp3, *screenp4;
+    int x, y;
+    int multi_pitch;
+
+    multi_pitch = dest_pitch * 4;
+    bufp = src_buffer + y1 * SCREENWIDTH + x1;
+    screenp = (byte *) dest_buffer + (y1 * dest_pitch + x1) * 4;
+    screenp2 = screenp + dest_pitch;
+    screenp3 = screenp + dest_pitch * 2;
+    screenp4 = screenp + dest_pitch * 3;
+
+    for (y=y1; y<y2; ++y)
+    {
+        byte *sp, *sp2, *sp3, *sp4, *bp;
+        sp = screenp;
+        sp2 = screenp2;
+        sp3 = screenp3;
+        sp4 = screenp4;
+        bp = bufp;
+
+        for (x=x1; x<x2; ++x)
+        {
+            *sp++ = *bp;  *sp++ = *bp;  *sp++ = *bp;  *sp++ = *bp;
+            *sp2++ = *bp; *sp2++ = *bp; *sp2++ = *bp; *sp2++ = *bp;
+            *sp3++ = *bp; *sp3++ = *bp; *sp3++ = *bp; *sp3++ = *bp;
+            *sp4++ = *bp; *sp4++ = *bp; *sp4++ = *bp; *sp4++ = *bp;
+            ++bp;
+        }
+        screenp += multi_pitch;
+        screenp2 += multi_pitch;
+        screenp3 += multi_pitch;
+        screenp4 += multi_pitch;
+        bufp += SCREENWIDTH;
+    }
+
+    return true;
+}
+
+screen_mode_t mode_scale_4x = {
+    SCREENWIDTH * 4, SCREENHEIGHT * 4,
+    NULL,
+    I_Scale4x,
+    false,
+};
+
+// 5x scale (1600x1000)
+
+static boolean I_Scale5x(int x1, int y1, int x2, int y2)
+{
+    byte *bufp, *screenp, *screenp2, *screenp3, *screenp4, *screenp5;
+    int x, y;
+    int multi_pitch;
+
+    multi_pitch = dest_pitch * 5;
+    bufp = src_buffer + y1 * SCREENWIDTH + x1;
+    screenp = (byte *) dest_buffer + (y1 * dest_pitch + x1) * 5;
+    screenp2 = screenp + dest_pitch;
+    screenp3 = screenp + dest_pitch * 2;
+    screenp4 = screenp + dest_pitch * 3;
+    screenp5 = screenp + dest_pitch * 4;
+
+    for (y=y1; y<y2; ++y)
+    {
+        byte *sp, *sp2, *sp3, *sp4, *sp5, *bp;
+        sp = screenp;
+        sp2 = screenp2;
+        sp3 = screenp3;
+        sp4 = screenp4;
+        sp5 = screenp5;
+        bp = bufp;
+
+        for (x=x1; x<x2; ++x)
+        {
+            *sp++ = *bp;  *sp++ = *bp;  *sp++ = *bp;  *sp++ = *bp;  *sp++ = *bp;
+            *sp2++ = *bp; *sp2++ = *bp; *sp2++ = *bp; *sp2++ = *bp; *sp2++ = *bp;
+            *sp3++ = *bp; *sp3++ = *bp; *sp3++ = *bp; *sp3++ = *bp; *sp3++ = *bp;
+            *sp4++ = *bp; *sp4++ = *bp; *sp4++ = *bp; *sp4++ = *bp; *sp4++ = *bp;
+            *sp5++ = *bp; *sp5++ = *bp; *sp5++ = *bp; *sp5++ = *bp; *sp5++ = *bp;
+            ++bp;
+        }
+        screenp += multi_pitch;
+        screenp2 += multi_pitch;
+        screenp3 += multi_pitch;
+        screenp4 += multi_pitch;
+        screenp5 += multi_pitch;
+        bufp += SCREENWIDTH;
+    }
+
+    return true;
+}
+
+screen_mode_t mode_scale_5x = {
+    SCREENWIDTH * 5, SCREENHEIGHT * 5,
+    NULL,
+    I_Scale5x,
+    false,
+};
+
+
+// Search through the given palette, finding the nearest color that matches
+// the given color.
+
+static int FindNearestColor(byte *palette, int r, int g, int b)
+{
+    byte *col;
+    int best;
+    int best_diff;
+    int diff;
+    int i;
+
+    best = 0;
+    best_diff = INT_MAX;
+
+    for (i=0; i<256; ++i)
+    {
+        col = palette + i * 3;
+        diff = (r - col[0]) * (r - col[0])
+             + (g - col[1]) * (g - col[1])
+             + (b - col[2]) * (b - col[2]);
+
+        if (diff == 0)
+        {
+            return i;
+        }
+        else if (diff < best_diff)
+        {
+            best = i;
+            best_diff = diff;
+        }
+    }
+
+    return best;
+}
+
+// Create a stretch table.  This is a lookup table for blending colors.
+// pct specifies the bias between the two colors: 0 = all y, 100 = all x.
+// NB: This is identical to the lookup tables used in other ports for
+// translucency.
+
+static byte *GenerateStretchTable(byte *palette, int pct)
+{
+    byte *result;
+    int x, y;
+    int r, g, b;
+    byte *col1;
+    byte *col2;
+
+    result = Z_Malloc(256 * 256, PU_STATIC, NULL);
+
+    for (x=0; x<256; ++x)
+    {
+        for (y=0; y<256; ++y)
+        {
+            col1 = palette + x * 3;
+            col2 = palette + y * 3;
+            r = (((int) col1[0]) * pct + ((int) col2[0]) * (100 - pct)) / 100;
+            g = (((int) col1[1]) * pct + ((int) col2[1]) * (100 - pct)) / 100;
+            b = (((int) col1[2]) * pct + ((int) col2[2]) * (100 - pct)) / 100;
+            result[x * 256 + y] = FindNearestColor(palette, r, g, b);
+        }
+    }
+
+    return result;
+}
+
+// Called at startup to generate the lookup tables for aspect ratio
+// correcting scale up.
+
+static void I_InitStretchTables(byte *palette)
+{
+    if (stretch_tables[0] != NULL)
+    {
+        return;
+    }
+
+    // We only actually need two lookup tables:
+    //
+    // mix 0%   =  just write line 1
+    // mix 20%  =  stretch_tables[0]
+    // mix 40%  =  stretch_tables[1]
+    // mix 60%  =  stretch_tables[1] used backwards
+    // mix 80%  =  stretch_tables[0] used backwards
+    // mix 100% =  just write line 2
+
+    printf("I_InitStretchTables: Generating lookup tables..");
+    fflush(stdout);
+    stretch_tables[0] = GenerateStretchTable(palette, 20);
+    printf(".."); fflush(stdout);
+    stretch_tables[1] = GenerateStretchTable(palette, 40);
+    puts("");
+}
+
+// Create 50%/50% table for 800x600 squash mode
+
+static void I_InitSquashTable(byte *palette)
+{
+    if (half_stretch_table != NULL)
+    {
+        return;
+    }
+
+    printf("I_InitSquashTable: Generating lookup table..");
+    fflush(stdout);
+    half_stretch_table = GenerateStretchTable(palette, 50);
+    puts("");
+}
+
+// Destroy the scaling lookup tables. This should only ever be called
+// if switching to a completely different palette from the normal one
+// (in which case the mappings no longer make any sense).
+
+void I_ResetScaleTables(byte *palette)
+{
+    if (stretch_tables[0] != NULL)
+    {
+        Z_Free(stretch_tables[0]);
+        Z_Free(stretch_tables[1]);
+
+        printf("I_ResetScaleTables: Regenerating lookup tables..\n");
+        stretch_tables[0] = GenerateStretchTable(palette, 20);
+        stretch_tables[1] = GenerateStretchTable(palette, 40);
+    }
+
+    if (half_stretch_table != NULL)
+    {
+        Z_Free(half_stretch_table);
+
+        printf("I_ResetScaleTables: Regenerating lookup table..\n");
+
+        half_stretch_table = GenerateStretchTable(palette, 50);
+    }
+}
+
+
+// 
+// Aspect ratio correcting scale up functions.
+//
+// These double up pixels to stretch the screen when using a 4:3
+// screen mode.
+//
+
+static inline void WriteBlendedLine1x(byte *dest, byte *src1, byte *src2, 
+                               byte *stretch_table)
+{
+    int x;
+
+    for (x=0; x<SCREENWIDTH; ++x)
+    {
+        *dest = stretch_table[*src1 * 256 + *src2];
+        ++dest;
+        ++src1;
+        ++src2;
+    }
+} 
+
+// 1x stretch (320x240)
+
+static boolean I_Stretch1x(int x1, int y1, int x2, int y2)
+{
+    byte *bufp, *screenp;
+    int y;
+
+    // Only works with full screen update
+
+    if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
+    {
+        return false;
+    }    
+
+    // Need to byte-copy from buffer into the screen buffer
+
+    bufp = src_buffer + y1 * SCREENWIDTH + x1;
+    screenp = (byte *) dest_buffer + y1 * dest_pitch + x1;
+
+    // For every 5 lines of src_buffer, 6 lines are written to dest_buffer
+    // (200 -> 240)
+
+    for (y=0; y<SCREENHEIGHT; y += 5)
+    {
+        // 100% line 0
+        memcpy(screenp, bufp, SCREENWIDTH);
+        screenp += dest_pitch;
+
+        // 20% line 0, 80% line 1
+        WriteBlendedLine1x(screenp, bufp, bufp + SCREENWIDTH, stretch_tables[0]);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+
+        // 40% line 1, 60% line 2
+        WriteBlendedLine1x(screenp, bufp, bufp + SCREENWIDTH, stretch_tables[1]);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+
+        // 60% line 2, 40% line 3
+        WriteBlendedLine1x(screenp, bufp + SCREENWIDTH, bufp, stretch_tables[1]);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+
+        // 80% line 3, 20% line 4
+        WriteBlendedLine1x(screenp, bufp + SCREENWIDTH, bufp, stretch_tables[0]);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+
+        // 100% line 4
+        memcpy(screenp, bufp, SCREENWIDTH);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+    }
+
+    return true;
+}
+
+screen_mode_t mode_stretch_1x = {
+    SCREENWIDTH, SCREENHEIGHT_4_3,
+    I_InitStretchTables,
+    I_Stretch1x,
+    true,
+};
+
+static inline void WriteLine2x(byte *dest, byte *src)
+{
+    int x;
+
+    for (x=0; x<SCREENWIDTH; ++x)
+    {
+        dest[0] = *src;
+        dest[1] = *src;
+        dest += 2;
+        ++src;
+    }
+}
+
+static inline void WriteBlendedLine2x(byte *dest, byte *src1, byte *src2, 
+                               byte *stretch_table)
+{
+    int x;
+    int val;
+
+    for (x=0; x<SCREENWIDTH; ++x)
+    {
+        val = stretch_table[*src1 * 256 + *src2];
+        dest[0] = val;
+        dest[1] = val;
+        dest += 2;
+        ++src1;
+        ++src2;
+    }
+} 
+
+// 2x stretch (640x480)
+
+static boolean I_Stretch2x(int x1, int y1, int x2, int y2)
+{
+    byte *bufp, *screenp;
+    int y;
+
+    // Only works with full screen update
+
+    if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
+    {
+        return false;
+    }    
+
+    // Need to byte-copy from buffer into the screen buffer
+
+    bufp = src_buffer + y1 * SCREENWIDTH + x1;
+    screenp = (byte *) dest_buffer + y1 * dest_pitch + x1;
+
+    // For every 5 lines of src_buffer, 12 lines are written to dest_buffer.
+    // (200 -> 480)
+
+    for (y=0; y<SCREENHEIGHT; y += 5)
+    {
+        // 100% line 0
+        WriteLine2x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 0
+        WriteLine2x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 40% line 0, 60% line 1
+        WriteBlendedLine2x(screenp, bufp, bufp + SCREENWIDTH, stretch_tables[1]);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+
+        // 100% line 1
+        WriteLine2x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 80% line 1, 20% line 2
+        WriteBlendedLine2x(screenp, bufp + SCREENWIDTH, bufp, stretch_tables[0]);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+
+        // 100% line 2
+        WriteLine2x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 2
+        WriteLine2x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 20% line 2, 80% line 3
+        WriteBlendedLine2x(screenp, bufp, bufp + SCREENWIDTH, stretch_tables[0]);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+
+        // 100% line 3
+        WriteLine2x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 60% line 3, 40% line 4
+        WriteBlendedLine2x(screenp, bufp + SCREENWIDTH, bufp, stretch_tables[1]);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+
+        // 100% line 4
+        WriteLine2x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 4
+        WriteLine2x(screenp, bufp);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+    }
+
+    return true;
+}
+
+screen_mode_t mode_stretch_2x = {
+    SCREENWIDTH * 2, SCREENHEIGHT_4_3 * 2,
+    I_InitStretchTables,
+    I_Stretch2x,
+    false,
+};
+
+static inline void WriteLine3x(byte *dest, byte *src)
+{
+    int x;
+
+    for (x=0; x<SCREENWIDTH; ++x)
+    {
+        dest[0] = *src;
+        dest[1] = *src;
+        dest[2] = *src;
+        dest += 3;
+        ++src;
+    }
+}
+
+static inline void WriteBlendedLine3x(byte *dest, byte *src1, byte *src2, 
+                               byte *stretch_table)
+{
+    int x;
+    int val;
+
+    for (x=0; x<SCREENWIDTH; ++x)
+    {
+        val = stretch_table[*src1 * 256 + *src2];
+        dest[0] = val;
+        dest[1] = val;
+        dest[2] = val;
+        dest += 3;
+        ++src1;
+        ++src2;
+    }
+} 
+
+// 3x stretch (960x720)
+
+static boolean I_Stretch3x(int x1, int y1, int x2, int y2)
+{
+    byte *bufp, *screenp;
+    int y;
+
+    // Only works with full screen update
+
+    if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
+    {
+        return false;
+    }    
+
+    // Need to byte-copy from buffer into the screen buffer
+
+    bufp = src_buffer + y1 * SCREENWIDTH + x1;
+    screenp = (byte *) dest_buffer + y1 * dest_pitch + x1;
+
+    // For every 5 lines of src_buffer, 18 lines are written to dest_buffer.
+    // (200 -> 720)
+
+    for (y=0; y<SCREENHEIGHT; y += 5)
+    {
+        // 100% line 0
+        WriteLine3x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 0
+        WriteLine3x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 0
+        WriteLine3x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 60% line 0, 40% line 1
+        WriteBlendedLine3x(screenp, bufp + SCREENWIDTH, bufp, stretch_tables[1]);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+
+        // 100% line 1
+        WriteLine3x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 1
+        WriteLine3x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 1
+        WriteLine3x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 20% line 1, 80% line 2
+        WriteBlendedLine3x(screenp, bufp, bufp + SCREENWIDTH, stretch_tables[0]);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+
+        // 100% line 2
+        WriteLine3x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 2
+        WriteLine3x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 80% line 2, 20% line 3
+        WriteBlendedLine3x(screenp, bufp + SCREENWIDTH, bufp, stretch_tables[0]);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+
+        // 100% line 3
+        WriteLine3x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 3
+        WriteLine3x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 3
+        WriteLine3x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 40% line 3, 60% line 4
+        WriteBlendedLine3x(screenp, bufp, bufp + SCREENWIDTH, stretch_tables[1]);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+
+        // 100% line 4
+        WriteLine3x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 4
+        WriteLine3x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 4
+        WriteLine3x(screenp, bufp);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+    }
+
+    return true;
+}
+
+screen_mode_t mode_stretch_3x = {
+    SCREENWIDTH * 3, SCREENHEIGHT_4_3 * 3,
+    I_InitStretchTables,
+    I_Stretch3x,
+    false,
+};
+
+static inline void WriteLine4x(byte *dest, byte *src)
+{
+    int x;
+
+    for (x=0; x<SCREENWIDTH; ++x)
+    {
+        dest[0] = *src;
+        dest[1] = *src;
+        dest[2] = *src;
+        dest[3] = *src;
+        dest += 4;
+        ++src;
+    }
+}
+
+static inline void WriteBlendedLine4x(byte *dest, byte *src1, byte *src2, 
+                               byte *stretch_table)
+{
+    int x;
+    int val;
+
+    for (x=0; x<SCREENWIDTH; ++x)
+    {
+        val = stretch_table[*src1 * 256 + *src2];
+        dest[0] = val;
+        dest[1] = val;
+        dest[2] = val;
+        dest[3] = val;
+        dest += 4;
+        ++src1;
+        ++src2;
+    }
+} 
+
+// 4x stretch (1280x960)
+
+static boolean I_Stretch4x(int x1, int y1, int x2, int y2)
+{
+    byte *bufp, *screenp;
+    int y;
+
+    // Only works with full screen update
+
+    if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
+    {
+        return false;
+    }    
+
+    // Need to byte-copy from buffer into the screen buffer
+
+    bufp = src_buffer + y1 * SCREENWIDTH + x1;
+    screenp = (byte *) dest_buffer + y1 * dest_pitch + x1;
+
+    // For every 5 lines of src_buffer, 24 lines are written to dest_buffer.
+    // (200 -> 960)
+
+    for (y=0; y<SCREENHEIGHT; y += 5)
+    {
+        // 100% line 0
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 0
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 0
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 0
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 90% line 0, 20% line 1
+        WriteBlendedLine4x(screenp, bufp + SCREENWIDTH, bufp, stretch_tables[0]);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+
+        // 100% line 1
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 1
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 1
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 1
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 60% line 1, 40% line 2
+        WriteBlendedLine4x(screenp, bufp + SCREENWIDTH, bufp, stretch_tables[1]);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+
+        // 100% line 2
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 2
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 2
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 2
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 40% line 2, 60% line 3
+        WriteBlendedLine4x(screenp, bufp, bufp + SCREENWIDTH, stretch_tables[1]);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+
+        // 100% line 3
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 3
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 3
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 3
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 20% line 3, 80% line 4
+        WriteBlendedLine4x(screenp, bufp, bufp + SCREENWIDTH, stretch_tables[0]);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+
+        // 100% line 4
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 4
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 4
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 4
+        WriteLine4x(screenp, bufp);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+    }
+
+    return true;
+}
+
+screen_mode_t mode_stretch_4x = {
+    SCREENWIDTH * 4, SCREENHEIGHT_4_3 * 4,
+    I_InitStretchTables,
+    I_Stretch4x,
+    false,
+};
+
+static inline void WriteLine5x(byte *dest, byte *src)
+{
+    int x;
+
+    for (x=0; x<SCREENWIDTH; ++x)
+    {
+        dest[0] = *src;
+        dest[1] = *src;
+        dest[2] = *src;
+        dest[3] = *src;
+        dest[4] = *src;
+        dest += 5;
+        ++src;
+    }
+}
+
+// 5x stretch (1600x1200)
+
+static boolean I_Stretch5x(int x1, int y1, int x2, int y2)
+{
+    byte *bufp, *screenp;
+    int y;
+
+    // Only works with full screen update
+
+    if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
+    {
+        return false;
+    }    
+
+    // Need to byte-copy from buffer into the screen buffer
+
+    bufp = src_buffer + y1 * SCREENWIDTH + x1;
+    screenp = (byte *) dest_buffer + y1 * dest_pitch + x1;
+
+    // For every 1 line of src_buffer, 6 lines are written to dest_buffer.
+    // (200 -> 1200)
+
+    for (y=0; y<SCREENHEIGHT; y += 1)
+    {
+        // 100% line 0
+        WriteLine5x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 0
+        WriteLine5x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 0
+        WriteLine5x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 0
+        WriteLine5x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 0
+        WriteLine5x(screenp, bufp);
+        screenp += dest_pitch;
+
+        // 100% line 0
+        WriteLine5x(screenp, bufp);
+        screenp += dest_pitch; bufp += SCREENWIDTH;
+    }
+
+    // test hack for Porsche Monty... scan line simulation:
+    // See here: http://www.doomworld.com/vb/post/962612
+
+    if (M_CheckParm("-scanline") > 0)
+    {
+        screenp = (byte *) dest_buffer + 2 * dest_pitch;
+
+        for (y=0; y<1198; y += 3)
+        {
+            memset(screenp, 0, 1600);
+
+            screenp += dest_pitch * 3;
+        }
+    }
+
+    return true;
+}
+
+screen_mode_t mode_stretch_5x = {
+    SCREENWIDTH * 5, SCREENHEIGHT_4_3 * 5,
+    I_InitStretchTables,
+    I_Stretch5x,
+    false,
+};
+
+//
+// Aspect ratio correcting "squash" functions. 
+//
+// These do the opposite of the "stretch" functions above: while the
+// stretch functions increase the vertical dimensions, the squash
+// functions decrease the horizontal dimensions for the same result.
+//
+// The same blend tables from the stretch functions are reused; as 
+// a result, the dimensions are *slightly* wrong (eg. 320x200 should
+// squash to 266x200, but actually squashes to 256x200).
+//
+
+// 
+// 1x squashed scale (256x200)
+//
+
+static inline void WriteSquashedLine1x(byte *dest, byte *src)
+{
+    int x;
+
+    for (x=0; x<SCREENWIDTH; )
+    {
+        // Draw in blocks of 5
+
+        // 80% pixel 0,   20% pixel 1
+
+        *dest++ = stretch_tables[0][src[1] * 256 + src[0]];
+
+        // 60% pixel 1,   40% pixel 2
+
+        *dest++ = stretch_tables[1][src[2] * 256 + src[1]];
+
+        // 40% pixel 2,   60% pixel 3
+
+        *dest++ = stretch_tables[1][src[2] * 256 + src[3]];
+
+        // 20% pixel 3,   80% pixel 4
+
+        *dest++ = stretch_tables[0][src[3] * 256 + src[4]];
+
+        x += 5;
+        src += 5;
+    }
+}
+
+// 1x squashed (256x200)
+
+static boolean I_Squash1x(int x1, int y1, int x2, int y2)
+{
+    byte *bufp, *screenp;
+    int y;
+
+    // Only works with full screen update
+
+    if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
+    {
+        return false;
+    }    
+
+    bufp = src_buffer;
+    screenp = (byte *) dest_buffer;
+
+    for (y=0; y<SCREENHEIGHT; ++y) 
+    {
+        WriteSquashedLine1x(screenp, bufp);
+
+        screenp += dest_pitch;
+        bufp += SCREENWIDTH;
+    }
+
+    return true;
+}
+
+screen_mode_t mode_squash_1x = {
+    SCREENWIDTH_4_3, SCREENHEIGHT,
+    I_InitStretchTables,
+    I_Squash1x,
+    true,
+};
+
+
+//
+// 2x squashed scale (512x400)
+//
+
+#define DRAW_PIXEL2 \
+      *dest++ = *dest2++ = c;
+
+static inline void WriteSquashedLine2x(byte *dest, byte *src)
+{
+    byte *dest2;
+    int x, c;
+
+    dest2 = dest + dest_pitch;
+
+    for (x=0; x<SCREENWIDTH; )
+    {
+        // Draw in blocks of 5
+
+        // 100% pixel 0
+
+        c = src[0];
+        DRAW_PIXEL2;
+
+        // 60% pixel 0, 40% pixel 1
+
+        c = stretch_tables[1][src[1] * 256 + src[0]];
+        DRAW_PIXEL2;
+
+        // 100% pixel 1
+
+        c = src[1];
+        DRAW_PIXEL2;
+
+        // 20% pixel 1, 80% pixel 2
+
+        c = stretch_tables[0][src[1] * 256 + src[2]];
+        DRAW_PIXEL2;
+
+        // 80% pixel 2, 20% pixel 3
+
+        c = stretch_tables[0][src[3] * 256 + src[2]];
+        DRAW_PIXEL2;
+
+        // 100% pixel 3
+
+        c = src[3];
+        DRAW_PIXEL2;
+
+        // 40% pixel 3, 60% pixel 4
+
+        c = stretch_tables[1][src[3] * 256 + src[4]];
+        DRAW_PIXEL2;
+
+        // 100% pixel 4
+
+        c = src[4];
+        DRAW_PIXEL2;
+
+        x += 5;
+        src += 5;
+    }
+}
+
+// 2x squash (512x400)
+
+static boolean I_Squash2x(int x1, int y1, int x2, int y2)
+{
+    byte *bufp, *screenp;
+    int y;
+
+    // Only works with full screen update
+
+    if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
+    {
+        return false;
+    }    
+
+    bufp = src_buffer;
+    screenp = (byte *) dest_buffer;
+
+    for (y=0; y<SCREENHEIGHT; ++y) 
+    {
+        WriteSquashedLine2x(screenp, bufp);
+
+        screenp += dest_pitch * 2;
+        bufp += SCREENWIDTH;
+    }
+
+    return true;
+}
+
+screen_mode_t mode_squash_2x = {
+    SCREENWIDTH_4_3 * 2, SCREENHEIGHT * 2,
+    I_InitStretchTables,
+    I_Squash2x,
+    false,
+};
+
+
+#define DRAW_PIXEL3 \
+        *dest++ = *dest2++ = *dest3++ = c
+
+static inline void WriteSquashedLine3x(byte *dest, byte *src)
+{
+    byte *dest2, *dest3;
+    int x, c;
+
+    dest2 = dest + dest_pitch;
+    dest3 = dest + dest_pitch * 2;
+
+    for (x=0; x<SCREENWIDTH; )
+    {
+        // Every 2 pixels is expanded to 5 pixels
+
+        // 100% pixel 0 x2
+
+        c = src[0];
+
+        DRAW_PIXEL3;
+        DRAW_PIXEL3;
+
+        // 50% pixel 0, 50% pixel 1
+
+        c = half_stretch_table[src[0] * 256 + src[1]];
+
+        DRAW_PIXEL3;
+
+        // 100% pixel 1
+
+        c = src[1];
+
+        DRAW_PIXEL3;
+        DRAW_PIXEL3;
+
+        x += 2;
+        src += 2;
+    }
+}
+
+
+//
+// 3x scale squashed (800x600)
+//
+// This is a special case that uses the half_stretch_table (50%) rather
+// than the normal stretch_tables(20,40%), to scale up to 800x600 
+// exactly.
+//
+
+static boolean I_Squash3x(int x1, int y1, int x2, int y2)
+{
+    byte *bufp, *screenp;
+    int y;
+
+    // Only works with full screen update
+
+    if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
+    {
+        return false;
+    }    
+
+    bufp = src_buffer;
+    screenp = (byte *) dest_buffer;
+
+    for (y=0; y<SCREENHEIGHT; ++y) 
+    {
+        WriteSquashedLine3x(screenp, bufp);
+
+        screenp += dest_pitch * 3;
+        bufp += SCREENWIDTH;
+    }
+
+    return true;
+}
+
+screen_mode_t mode_squash_3x = {
+    800, 600,
+    I_InitSquashTable,
+    I_Squash3x,
+    false,
+};
+
+#define DRAW_PIXEL4 \
+        *dest++ = *dest2++ = *dest3++ = *dest4++ = c;
+      
+static inline void WriteSquashedLine4x(byte *dest, byte *src)
+{
+    int x;
+    int c;
+    byte *dest2, *dest3, *dest4;
+
+    dest2 = dest + dest_pitch;
+    dest3 = dest + dest_pitch * 2;
+    dest4 = dest + dest_pitch * 3;
+
+    for (x=0; x<SCREENWIDTH; )
+    {
+        // Draw in blocks of 5
+
+        // 100% pixel 0  x3
+
+        c = src[0];
+        DRAW_PIXEL4;
+        DRAW_PIXEL4;
+        DRAW_PIXEL4;
+
+        // 20% pixel 0,  80% pixel 1
+
+        c = stretch_tables[0][src[0] * 256 + src[1]];
+        DRAW_PIXEL4;
+
+        // 100% pixel 1 x2
+
+        c = src[1];
+        DRAW_PIXEL4;
+        DRAW_PIXEL4;
+
+        // 40% pixel 1, 60% pixel 2
+
+        c = stretch_tables[1][src[1] * 256 + src[2]];
+        DRAW_PIXEL4;
+
+        // 100% pixel 2 x2
+
+        c = src[2];
+        DRAW_PIXEL4;
+        DRAW_PIXEL4;
+
+        // 60% pixel 2, 40% pixel 3
+
+        c = stretch_tables[1][src[3] * 256 + src[2]];
+        DRAW_PIXEL4;
+
+        // 100% pixel 3 x2
+
+        c = src[3];
+        DRAW_PIXEL4;
+        DRAW_PIXEL4;
+
+        // 80% pixel 3, 20% pixel 4
+
+        c = stretch_tables[0][src[4] * 256 + src[3]];
+        DRAW_PIXEL4;
+
+        // 100% pixel 4
+
+        c = src[4];
+        DRAW_PIXEL4;
+        DRAW_PIXEL4;
+        DRAW_PIXEL4;
+
+        x += 5;
+        src += 5;
+    }
+}
+
+//
+// 4x squashed (1024x800)
+//
+
+static boolean I_Squash4x(int x1, int y1, int x2, int y2)
+{
+    byte *bufp, *screenp;
+    int y;
+
+    // Only works with full screen update
+
+    if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
+    {
+        return false;
+    }    
+
+    bufp = src_buffer;
+    screenp = (byte *) dest_buffer;
+
+    for (y=0; y<SCREENHEIGHT; ++y) 
+    {
+        WriteSquashedLine4x(screenp, bufp);
+
+        screenp += dest_pitch * 4;
+        bufp += SCREENWIDTH;
+    }
+
+    return true;
+}
+
+screen_mode_t mode_squash_4x = {
+    SCREENWIDTH_4_3 * 4, SCREENHEIGHT * 4,
+    I_InitStretchTables,
+    I_Squash4x,
+    false,
+};
+
+#define DRAW_PIXEL5 \
+        *dest++ = *dest2++ = *dest3++ = *dest4++ = *dest5++ = c
+
+static inline void WriteSquashedLine5x(byte *dest, byte *src)
+{
+    int x;
+    int c;
+    byte *dest2, *dest3, *dest4, *dest5;
+
+    dest2 = dest + dest_pitch;
+    dest3 = dest + dest_pitch * 2;
+    dest4 = dest + dest_pitch * 3;
+    dest5 = dest + dest_pitch * 4;
+
+    for (x=0; x<SCREENWIDTH; ++x)
+    {
+        // Draw in blocks of 5
+
+        // 100% pixel 0  x4
+
+        c = *src++;
+        DRAW_PIXEL5;
+        DRAW_PIXEL5;
+        DRAW_PIXEL5;
+        DRAW_PIXEL5;
+    }
+}
+
+//
+// 5x squashed (1280x1000)
+//
+
+static boolean I_Squash5x(int x1, int y1, int x2, int y2)
+{
+    byte *bufp, *screenp;
+    int y;
+
+    // Only works with full screen update
+
+    if (x1 != 0 || y1 != 0 || x2 != SCREENWIDTH || y2 != SCREENHEIGHT)
+    {
+        return false;
+    }    
+
+    bufp = src_buffer;
+    screenp = (byte *) dest_buffer;
+
+    for (y=0; y<SCREENHEIGHT; ++y) 
+    {
+        WriteSquashedLine5x(screenp, bufp);
+
+        screenp += dest_pitch * 5;
+        bufp += SCREENWIDTH;
+    }
+
+    return true;
+}
+
+screen_mode_t mode_squash_5x = {
+    SCREENWIDTH_4_3 * 5, SCREENHEIGHT * 5,
+    I_InitStretchTables,
+    I_Squash5x,
+    false,
+};
+
+
diff --git a/frosted-doom/i_scale.h b/frosted-doom/i_scale.h
new file mode 100644 (file)
index 0000000..48231f5
--- /dev/null
@@ -0,0 +1,53 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//      Pixel-doubling scale up functions.
+//
+
+
+#ifndef __I_SCALE__
+#define __I_SCALE__
+
+#include "doomtype.h"
+
+void I_InitScale(byte *_src_buffer, byte *_dest_buffer, int _dest_pitch);
+void I_ResetScaleTables(byte *palette);
+
+// Scaled modes (direct multiples of 320x200)
+
+extern screen_mode_t mode_scale_1x;
+extern screen_mode_t mode_scale_2x;
+extern screen_mode_t mode_scale_3x;
+extern screen_mode_t mode_scale_4x;
+extern screen_mode_t mode_scale_5x;
+
+// Vertically stretched modes (320x200 -> multiples of 320x240)
+
+extern screen_mode_t mode_stretch_1x;
+extern screen_mode_t mode_stretch_2x;
+extern screen_mode_t mode_stretch_3x;
+extern screen_mode_t mode_stretch_4x;
+extern screen_mode_t mode_stretch_5x;
+
+// Horizontally squashed modes (320x200 -> multiples of 256x200)
+
+extern screen_mode_t mode_squash_1x;
+extern screen_mode_t mode_squash_2x;
+extern screen_mode_t mode_squash_3x;
+extern screen_mode_t mode_squash_4x;
+extern screen_mode_t mode_squash_5x;
+
+#endif /* #ifndef __I_SCALE__ */
+
diff --git a/frosted-doom/i_sdlmusic.c b/frosted-doom/i_sdlmusic.c
new file mode 100644 (file)
index 0000000..cca4132
--- /dev/null
@@ -0,0 +1,1322 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//     System interface for music.
+//
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "SDL.h"
+#include "SDL_mixer.h"
+
+#include "config.h"
+#include "doomtype.h"
+#include "memio.h"
+#include "mus2mid.h"
+
+#include "deh_str.h"
+#include "gusconf.h"
+#include "i_sound.h"
+#include "i_system.h"
+#include "i_swap.h"
+#include "m_argv.h"
+#include "m_config.h"
+#include "m_misc.h"
+#include "sha1.h"
+#include "w_wad.h"
+#include "z_zone.h"
+
+#define MAXMIDLENGTH (96 * 1024)
+#define MID_HEADER_MAGIC "MThd"
+#define MUS_HEADER_MAGIC "MUS\x1a"
+
+#define FLAC_HEADER "fLaC"
+#define OGG_HEADER "OggS"
+
+// Looping Vorbis metadata tag names. These have been defined by ZDoom
+// for specifying the start and end positions for looping music tracks
+// in .ogg and .flac files.
+// More information is here: http://zdoom.org/wiki/Audio_loop
+#define LOOP_START_TAG "LOOP_START"
+#define LOOP_END_TAG   "LOOP_END"
+
+// FLAC metadata headers that we care about.
+#define FLAC_STREAMINFO      0
+#define FLAC_VORBIS_COMMENT  4
+
+// Ogg metadata headers that we care about.
+#define OGG_ID_HEADER        1
+#define OGG_COMMENT_HEADER   3
+
+// Structure for music substitution.
+// We store a mapping based on SHA1 checksum -> filename of substitute music
+// file to play, so that substitution occurs based on content rather than
+// lump name. This has some inherent advantages:
+//  * Music for Plutonia (reused from Doom 1) works automatically.
+//  * If a PWAD replaces music, the replacement music is used rather than
+//    the substitute music for the IWAD.
+//  * If a PWAD reuses music from an IWAD (even from a different game), we get
+//    the high quality version of the music automatically (neat!)
+
+typedef struct
+{
+    sha1_digest_t hash;
+    char *filename;
+} subst_music_t;
+
+// Structure containing parsed metadata read from a digital music track:
+typedef struct
+{
+    boolean valid;
+    unsigned int samplerate_hz;
+    int start_time, end_time;
+} file_metadata_t;
+
+static subst_music_t *subst_music = NULL;
+static unsigned int subst_music_len = 0;
+
+static const char *subst_config_filenames[] =
+{
+    "doom1-music.cfg",
+    "doom2-music.cfg",
+    "tnt-music.cfg",
+    "heretic-music.cfg",
+    "hexen-music.cfg",
+    "strife-music.cfg",
+};
+
+static boolean music_initialized = false;
+
+// If this is true, this module initialized SDL sound and has the 
+// responsibility to shut it down
+
+static boolean sdl_was_initialized = false;
+
+static boolean musicpaused = false;
+static int current_music_volume;
+
+char *timidity_cfg_path = "";
+
+static char *temp_timidity_cfg = NULL;
+
+// If true, we are playing a substitute digital track rather than in-WAD
+// MIDI/MUS track, and file_metadata contains loop metadata.
+static boolean playing_substitute = false;
+static file_metadata_t file_metadata;
+
+// Position (in samples) that we have reached in the current track.
+// This is updated by the TrackPositionCallback function.
+static unsigned int current_track_pos;
+
+// Currently playing music track.
+static Mix_Music *current_track_music = NULL;
+
+// If true, the currently playing track is being played on loop.
+static boolean current_track_loop;
+
+// Given a time string (for LOOP_START/LOOP_END), parse it and return
+// the time (in # samples since start of track) it represents.
+static unsigned int ParseVorbisTime(unsigned int samplerate_hz, char *value)
+{
+    char *num_start, *p;
+    unsigned int result = 0;
+    char c;
+
+    if (strchr(value, ':') == NULL)
+    {
+       return atoi(value);
+    }
+
+    result = 0;
+    num_start = value;
+
+    for (p = value; *p != '\0'; ++p)
+    {
+        if (*p == '.' || *p == ':')
+        {
+            c = *p; *p = '\0';
+            result = result * 60 + atoi(num_start);
+            num_start = p + 1;
+            *p = c;
+        }
+
+        if (*p == '.')
+        {
+            return result * samplerate_hz
+                + (unsigned int) (atof(p) * samplerate_hz);
+        }
+    }
+
+    return (result * 60 + atoi(num_start)) * samplerate_hz;
+}
+
+// Given a vorbis comment string (eg. "LOOP_START=12345"), set fields
+// in the metadata structure as appropriate.
+static void ParseVorbisComment(file_metadata_t *metadata, char *comment)
+{
+    char *eq, *key, *value;
+
+    eq = strchr(comment, '=');
+
+    if (eq == NULL)
+    {
+        return;
+    }
+
+    key = comment;
+    *eq = '\0';
+    value = eq + 1;
+
+    if (!strcmp(key, LOOP_START_TAG))
+    {
+        metadata->start_time = ParseVorbisTime(metadata->samplerate_hz, value);
+    }
+    else if (!strcmp(key, LOOP_END_TAG))
+    {
+        metadata->end_time = ParseVorbisTime(metadata->samplerate_hz, value);
+    }
+}
+
+// Parse a vorbis comments structure, reading from the given file.
+static void ParseVorbisComments(file_metadata_t *metadata, FILE *fs)
+{
+    uint32_t buf;
+    unsigned int num_comments, i, comment_len;
+    char *comment;
+
+    // We must have read the sample rate already from an earlier header.
+    if (metadata->samplerate_hz == 0)
+    {
+       return;
+    }
+
+    // Skip the starting part we don't care about.
+    if (fread(&buf, 4, 1, fs) < 1)
+    {
+        return;
+    }
+    if (fseek(fs, LONG(buf), SEEK_CUR) != 0)
+    {
+       return;
+    }
+
+    // Read count field for number of comments.
+    if (fread(&buf, 4, 1, fs) < 1)
+    {
+        return;
+    }
+    num_comments = LONG(buf);
+
+    // Read each individual comment.
+    for (i = 0; i < num_comments; ++i)
+    {
+        // Read length of comment.
+        if (fread(&buf, 4, 1, fs) < 1)
+       {
+            return;
+       }
+
+        comment_len = LONG(buf);
+
+        // Read actual comment data into string buffer.
+        comment = calloc(1, comment_len + 1);
+        if (comment == NULL
+         || fread(comment, 1, comment_len, fs) < comment_len)
+        {
+            free(comment);
+            break;
+        }
+
+        // Parse comment string.
+        ParseVorbisComment(metadata, comment);
+        free(comment);
+    }
+}
+
+static void ParseFlacStreaminfo(file_metadata_t *metadata, FILE *fs)
+{
+    byte buf[34];
+
+    // Read block data.
+    if (fread(buf, sizeof(buf), 1, fs) < 1)
+    {
+        return;
+    }
+
+    // We only care about sample rate and song length.
+    metadata->samplerate_hz = (buf[10] << 12) | (buf[11] << 4)
+                            | (buf[12] >> 4);
+    // Song length is actually a 36 bit field, but 32 bits should be
+    // enough for everybody.
+    //metadata->song_length = (buf[14] << 24) | (buf[15] << 16)
+    //                      | (buf[16] << 8) | buf[17];
+}
+
+static void ParseFlacFile(file_metadata_t *metadata, FILE *fs)
+{
+    byte header[4];
+    unsigned int block_type;
+    size_t block_len;
+    boolean last_block;
+
+    for (;;)
+    {
+        long pos = -1;
+
+        // Read METADATA_BLOCK_HEADER:
+        if (fread(header, 4, 1, fs) < 1)
+        {
+            return;
+        }
+
+        block_type = header[0] & ~0x80;
+        last_block = (header[0] & 0x80) != 0;
+        block_len = (header[1] << 16) | (header[2] << 8) | header[3];
+
+        pos = ftell(fs);
+        if (pos < 0)
+        {
+            return;
+        }
+
+        if (block_type == FLAC_STREAMINFO)
+        {
+            ParseFlacStreaminfo(metadata, fs);
+        }
+        else if (block_type == FLAC_VORBIS_COMMENT)
+        {
+            ParseVorbisComments(metadata, fs);
+        }
+
+        if (last_block)
+        {
+            break;
+        }
+
+        // Seek to start of next block.
+        if (fseek(fs, pos + block_len, SEEK_SET) != 0)
+        {
+            return;
+        }
+    }
+}
+
+static void ParseOggIdHeader(file_metadata_t *metadata, FILE *fs)
+{
+    byte buf[21];
+
+    if (fread(buf, sizeof(buf), 1, fs) < 1)
+    {
+        return;
+    }
+
+    metadata->samplerate_hz = (buf[8] << 24) | (buf[7] << 16)
+                            | (buf[6] << 8) | buf[5];
+}
+
+static void ParseOggFile(file_metadata_t *metadata, FILE *fs)
+{
+    byte buf[7];
+    unsigned int offset;
+
+    // Scan through the start of the file looking for headers. They
+    // begin '[byte]vorbis' where the byte value indicates header type.
+    memset(buf, 0, sizeof(buf));
+
+    for (offset = 0; offset < 100 * 1024; ++offset)
+    {
+       // buf[] is used as a sliding window. Each iteration, we
+       // move the buffer one byte to the left and read an extra
+       // byte onto the end.
+        memmove(buf, buf + 1, sizeof(buf) - 1);
+
+        if (fread(&buf[6], 1, 1, fs) < 1)
+        {
+            return;
+        }
+
+        if (!memcmp(buf + 1, "vorbis", 6))
+        {
+            switch (buf[0])
+            {
+                case OGG_ID_HEADER:
+                    ParseOggIdHeader(metadata, fs);
+                    break;
+                case OGG_COMMENT_HEADER:
+                   ParseVorbisComments(metadata, fs);
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+}
+
+static void ReadLoopPoints(char *filename, file_metadata_t *metadata)
+{
+    FILE *fs;
+    char header[4];
+
+    metadata->valid = false;
+    metadata->samplerate_hz = 0;
+    metadata->start_time = 0;
+    metadata->end_time = -1;
+
+    fs = fopen(filename, "r");
+
+    if (fs == NULL)
+    {
+        return;
+    }
+
+    // Check for a recognized file format; use the first four bytes
+    // of the file.
+
+    if (fread(header, 4, 1, fs) < 1)
+    {
+        fclose(fs);
+        return;
+    }
+
+    if (memcmp(header, FLAC_HEADER, 4) == 0)
+    {
+        ParseFlacFile(metadata, fs);
+    }
+    else if (memcmp(header, OGG_HEADER, 4) == 0)
+    {
+        ParseOggFile(metadata, fs);
+    }
+
+    fclose(fs);
+
+    // Only valid if at the very least we read the sample rate.
+    metadata->valid = metadata->samplerate_hz > 0;
+}
+
+// Given a MUS lump, look up a substitute MUS file to play instead
+// (or NULL to just use normal MIDI playback).
+
+static char *GetSubstituteMusicFile(void *data, size_t data_len)
+{
+    sha1_context_t context;
+    sha1_digest_t hash;
+    char *filename;
+    int i;
+
+    // Don't bother doing a hash if we're never going to find anything.
+    if (subst_music_len == 0)
+    {
+        return NULL;
+    }
+
+    SHA1_Init(&context);
+    SHA1_Update(&context, data, data_len);
+    SHA1_Final(hash, &context);
+
+    // Look for a hash that matches.
+    // The substitute mapping list can (intentionally) contain multiple
+    // filename mappings for the same hash. This allows us to try
+    // different files and fall back if our first choice isn't found.
+
+    filename = NULL;
+
+    for (i = 0; i < subst_music_len; ++i)
+    {
+        if (memcmp(hash, subst_music[i].hash, sizeof(hash)) == 0)
+        {
+            filename = subst_music[i].filename;
+
+            // If the file exists, then use this file in preference to
+            // any fallbacks. But we always return a filename if it's
+            // in the list, even if it's just so we can print an error
+            // message to the user saying it doesn't exist.
+            if (M_FileExists(filename))
+            {
+                break;
+            }
+        }
+    }
+
+    return filename;
+}
+
+// Add a substitute music file to the lookup list.
+
+static void AddSubstituteMusic(subst_music_t *subst)
+{
+    ++subst_music_len;
+    subst_music =
+        realloc(subst_music, sizeof(subst_music_t) * subst_music_len);
+    memcpy(&subst_music[subst_music_len - 1], subst, sizeof(subst_music_t));
+}
+
+static int ParseHexDigit(char c)
+{
+    c = tolower(c);
+
+    if (c >= '0' && c <= '9')
+    {
+        return c - '0';
+    }
+    else if (c >= 'a' && c <= 'f')
+    {
+        return 10 + (c - 'a');
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+static char *GetFullPath(char *base_filename, char *path)
+{
+    char *basedir, *result;
+    char *p;
+
+    // Starting with directory separator means we have an absolute path,
+    // so just return it.
+    if (path[0] == DIR_SEPARATOR)
+    {
+        return strdup(path);
+    }
+
+#ifdef _WIN32
+    // d:\path\...
+    if (isalpha(path[0]) && path[1] == ':' && path[2] == DIR_SEPARATOR)
+    {
+        return strdup(path);
+    }
+#endif
+
+    // Paths in the substitute filenames can contain Unix-style /
+    // path separators, but we should convert this to the separator
+    // for the native platform.
+    path = M_StringReplace(path, "/", DIR_SEPARATOR_S);
+
+    // Copy config filename and cut off the filename to just get the
+    // parent dir.
+    basedir = strdup(base_filename);
+    p = strrchr(basedir, DIR_SEPARATOR);
+    if (p != NULL)
+    {
+        p[1] = '\0';
+        result = M_StringJoin(basedir, path, NULL);
+    }
+    else
+    {
+        result = strdup(path);
+    }
+    free(basedir);
+    free(path);
+
+    return result;
+}
+
+// Parse a line from substitute music configuration file; returns error
+// message or NULL for no error.
+
+static char *ParseSubstituteLine(char *filename, char *line)
+{
+    subst_music_t subst;
+    char *p;
+    int hash_index;
+
+    // Strip out comments if present.
+    p = strchr(line, '#');
+    if (p != NULL)
+    {
+        while (p > line && isspace(*(p - 1)))
+        {
+            --p;
+        }
+        *p = '\0';
+    }
+
+    // Skip leading spaces.
+    for (p = line; *p != '\0' && isspace(*p); ++p);
+
+    // Empty line? This includes comment lines now that comments have
+    // been stripped.
+    if (*p == '\0')
+    {
+        return NULL;
+    }
+
+    // Read hash.
+    hash_index = 0;
+    while (*p != '\0' && *p != '=' && !isspace(*p))
+    {
+        int d1, d2;
+
+        d1 = ParseHexDigit(p[0]);
+        d2 = ParseHexDigit(p[1]);
+
+        if (d1 < 0 || d2 < 0)
+        {
+            return "Invalid hex digit in SHA1 hash";
+        }
+        else if (hash_index >= sizeof(sha1_digest_t))
+        {
+            return "SHA1 hash too long";
+        }
+
+        subst.hash[hash_index] = (d1 << 4) | d2;
+        ++hash_index;
+
+        p += 2;
+    }
+
+    if (hash_index != sizeof(sha1_digest_t))
+    {
+        return "SHA1 hash too short";
+    }
+
+    // Skip spaces.
+    for (; *p != '\0' && isspace(*p); ++p);
+
+    if (*p != '=')
+    {
+        return "Expected '='";
+    }
+
+    ++p;
+
+    // Skip spaces.
+    for (; *p != '\0' && isspace(*p); ++p);
+
+    // We're now at the filename. Cut off trailing space characters.
+    while (strlen(p) > 0 && isspace(p[strlen(p) - 1]))
+    {
+        p[strlen(p) - 1] = '\0';
+    }
+
+    if (strlen(p) == 0)
+    {
+        return "No filename specified for music substitution";
+    }
+
+    // Expand full path and add to our database of substitutes.
+    subst.filename = GetFullPath(filename, p);
+    AddSubstituteMusic(&subst);
+
+    return NULL;
+}
+
+// Read a substitute music configuration file.
+
+static boolean ReadSubstituteConfig(char *filename)
+{
+    char line[128];
+    FILE *fs;
+    char *error;
+    int linenum = 1;
+    int old_subst_music_len;
+
+    fs = fopen(filename, "r");
+
+    if (fs == NULL)
+    {
+        return false;
+    }
+
+    old_subst_music_len = subst_music_len;
+
+    while (!feof(fs))
+    {
+        M_StringCopy(line, "", sizeof(line));
+        fgets(line, sizeof(line), fs);
+
+        error = ParseSubstituteLine(filename, line);
+
+        if (error != NULL)
+        {
+            fprintf(stderr, "%s:%i: Error: %s\n", filename, linenum, error);
+        }
+
+        ++linenum;
+    }
+
+    fclose(fs);
+
+    return true;
+}
+
+// Find substitute configs and try to load them.
+
+static void LoadSubstituteConfigs(void)
+{
+    char *musicdir;
+    char *path;
+    unsigned int i;
+
+    if (!strcmp(configdir, ""))
+    {
+        musicdir = strdup("");
+    }
+    else
+    {
+        musicdir = M_StringJoin(configdir, "music", DIR_SEPARATOR_S, NULL);
+    }
+
+    // Load all music packs. We always load all music substitution packs for
+    // all games. Why? Suppose we have a Doom PWAD that reuses some music from
+    // Heretic. If we have the Heretic music pack loaded, then we get an
+    // automatic substitution.
+    for (i = 0; i < arrlen(subst_config_filenames); ++i)
+    {
+        path = M_StringJoin(musicdir, subst_config_filenames[i], NULL);
+        ReadSubstituteConfig(path);
+        free(path);
+    }
+
+    free(musicdir);
+
+    if (subst_music_len > 0)
+    {
+        printf("Loaded %i music substitutions from config files.\n",
+               subst_music_len);
+    }
+}
+
+// Returns true if the given lump number is a music lump that should
+// be included in substitute configs.
+// Identifying music lumps by name is not feasible; some games (eg.
+// Heretic, Hexen) don't have a common naming pattern for music lumps.
+
+static boolean IsMusicLump(int lumpnum)
+{
+    byte *data;
+    boolean result;
+
+    if (W_LumpLength(lumpnum) < 4)
+    {
+        return false;
+    }
+
+    data = W_CacheLumpNum(lumpnum, PU_STATIC);
+
+    result = memcmp(data, MUS_HEADER_MAGIC, 4) == 0
+          || memcmp(data, MID_HEADER_MAGIC, 4) == 0;
+
+    W_ReleaseLumpNum(lumpnum);
+
+    return result;
+}
+
+// Dump an example config file containing checksums for all MIDI music
+// found in the WAD directory.
+
+static void DumpSubstituteConfig(char *filename)
+{
+    sha1_context_t context;
+    sha1_digest_t digest;
+    char name[9];
+    byte *data;
+    FILE *fs;
+    int lumpnum, h;
+
+    fs = fopen(filename, "w");
+
+    if (fs == NULL)
+    {
+        I_Error("Failed to open %s for writing", filename);
+        return;
+    }
+
+    fprintf(fs, "# Example %s substitute MIDI file.\n\n", PACKAGE_NAME);
+    fprintf(fs, "# SHA1 hash                              = filename\n");
+
+    for (lumpnum = 0; lumpnum < numlumps; ++lumpnum)
+    {
+        strncpy(name, lumpinfo[lumpnum].name, 8);
+        name[8] = '\0';
+
+        if (!IsMusicLump(lumpnum))
+        {
+            continue;
+        }
+
+        // Calculate hash.
+        data = W_CacheLumpNum(lumpnum, PU_STATIC);
+        SHA1_Init(&context);
+        SHA1_Update(&context, data, W_LumpLength(lumpnum));
+        SHA1_Final(digest, &context);
+        W_ReleaseLumpNum(lumpnum);
+
+        // Print line.
+        for (h = 0; h < sizeof(sha1_digest_t); ++h)
+        {
+            fprintf(fs, "%02x", digest[h]);
+        }
+
+        fprintf(fs, " = %s.ogg\n", name);
+    }
+
+    fprintf(fs, "\n");
+    fclose(fs);
+
+    printf("Substitute MIDI config file written to %s.\n", filename);
+    I_Quit();
+}
+
+// If the temp_timidity_cfg config variable is set, generate a "wrapper"
+// config file for Timidity to point to the actual config file. This
+// is needed to inject a "dir" command so that the patches are read
+// relative to the actual config file.
+
+static boolean WriteWrapperTimidityConfig(char *write_path)
+{
+    char *p, *path;
+    FILE *fstream;
+
+    if (!strcmp(timidity_cfg_path, ""))
+    {
+        return false;
+    }
+
+    fstream = fopen(write_path, "w");
+
+    if (fstream == NULL)
+    {
+        return false;
+    }
+
+    p = strrchr(timidity_cfg_path, DIR_SEPARATOR);
+    if (p != NULL)
+    {
+        path = strdup(timidity_cfg_path);
+        path[p - timidity_cfg_path] = '\0';
+        fprintf(fstream, "dir %s\n", path);
+        free(path);
+    }
+
+    fprintf(fstream, "source %s\n", timidity_cfg_path);
+    fclose(fstream);
+
+    return true;
+}
+
+void I_InitTimidityConfig(void)
+{
+    char *env_string;
+    boolean success;
+
+    temp_timidity_cfg = M_TempFile("timidity.cfg");
+
+    if (snd_musicdevice == SNDDEVICE_GUS)
+    {
+        success = GUS_WriteConfig(temp_timidity_cfg);
+    }
+    else
+    {
+        success = WriteWrapperTimidityConfig(temp_timidity_cfg);
+    }
+
+    // Set the TIMIDITY_CFG environment variable to point to the temporary
+    // config file.
+
+    if (success)
+    {
+        env_string = M_StringJoin("TIMIDITY_CFG=", temp_timidity_cfg, NULL);
+        putenv(env_string);
+    }
+    else
+    {
+        free(temp_timidity_cfg);
+        temp_timidity_cfg = NULL;
+    }
+}
+
+// Remove the temporary config file generated by I_InitTimidityConfig().
+
+static void RemoveTimidityConfig(void)
+{
+    if (temp_timidity_cfg != NULL)
+    {
+        remove(temp_timidity_cfg);
+        free(temp_timidity_cfg);
+    }
+}
+
+// Shutdown music
+
+static void I_SDL_ShutdownMusic(void)
+{
+    if (music_initialized)
+    {
+        Mix_HaltMusic();
+        music_initialized = false;
+
+        if (sdl_was_initialized)
+        {
+            Mix_CloseAudio();
+            SDL_QuitSubSystem(SDL_INIT_AUDIO);
+            sdl_was_initialized = false;
+        }
+    }
+}
+
+static boolean SDLIsInitialized(void)
+{
+    int freq, channels;
+    Uint16 format;
+
+    return Mix_QuerySpec(&freq, &format, &channels) != 0;
+}
+
+// Callback function that is invoked to track current track position.
+void TrackPositionCallback(int chan, void *stream, int len, void *udata)
+{
+    // Position is doubled up twice: for 16-bit samples and for stereo.
+    current_track_pos += len / 4;
+}
+
+// Initialize music subsystem
+static boolean I_SDL_InitMusic(void)
+{
+    int i;
+
+    // SDL_mixer prior to v1.2.11 has a bug that causes crashes
+    // with MIDI playback.  Print a warning message if we are
+    // using an old version.
+
+#ifdef __MACOSX__
+    {
+        const SDL_version *v = Mix_Linked_Version();
+
+        if (SDL_VERSIONNUM(v->major, v->minor, v->patch)
+          < SDL_VERSIONNUM(1, 2, 11))
+        {
+            printf("\n"
+               "                   *** WARNING ***\n"
+               "      You are using an old version of SDL_mixer.\n"
+               "      Music playback on this version may cause crashes\n"
+               "      under OS X and is disabled by default.\n"
+               "\n");
+        }
+    }
+#endif
+
+    //!
+    // @arg <output filename>
+    //
+    // Read all MIDI files from loaded WAD files, dump an example substitution
+    // music config file to the specified filename and quit.
+    //
+
+    i = M_CheckParmWithArgs("-dumpsubstconfig", 1);
+
+    if (i > 0)
+    {
+        DumpSubstituteConfig(myargv[i + 1]);
+    }
+
+    // If SDL_mixer is not initialized, we have to initialize it
+    // and have the responsibility to shut it down later on.
+
+    if (SDLIsInitialized())
+    {
+        music_initialized = true;
+    }
+    else
+    {
+        if (SDL_Init(SDL_INIT_AUDIO) < 0)
+        {
+            fprintf(stderr, "Unable to set up sound.\n");
+        }
+        else if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, 1024) < 0)
+        {
+            fprintf(stderr, "Error initializing SDL_mixer: %s\n",
+                    Mix_GetError());
+            SDL_QuitSubSystem(SDL_INIT_AUDIO);
+        }
+        else
+        {
+            SDL_PauseAudio(0);
+
+            sdl_was_initialized = true;
+            music_initialized = true;
+        }
+    }
+
+    // Once initialization is complete, the temporary Timidity config
+    // file can be removed.
+
+    RemoveTimidityConfig();
+
+    // If snd_musiccmd is set, we need to call Mix_SetMusicCMD to
+    // configure an external music playback program.
+
+    if (strlen(snd_musiccmd) > 0)
+    {
+        Mix_SetMusicCMD(snd_musiccmd);
+    }
+
+    // Register an effect function to track the music position.
+    Mix_RegisterEffect(MIX_CHANNEL_POST, TrackPositionCallback, NULL, NULL);
+
+    // If we're in GENMIDI mode, try to load sound packs.
+    if (snd_musicdevice == SNDDEVICE_GENMIDI)
+    {
+        LoadSubstituteConfigs();
+    }
+
+    return music_initialized;
+}
+
+//
+// SDL_mixer's native MIDI music playing does not pause properly.
+// As a workaround, set the volume to 0 when paused.
+//
+
+static void UpdateMusicVolume(void)
+{
+    int vol;
+
+    if (musicpaused)
+    {
+        vol = 0;
+    }
+    else
+    {
+        vol = (current_music_volume * MIX_MAX_VOLUME) / 127;
+    }
+
+    Mix_VolumeMusic(vol);
+}
+
+// Set music volume (0 - 127)
+
+static void I_SDL_SetMusicVolume(int volume)
+{
+    // Internal state variable.
+    current_music_volume = volume;
+
+    UpdateMusicVolume();
+}
+
+// Start playing a mid
+
+static void I_SDL_PlaySong(void *handle, boolean looping)
+{
+    int loops;
+
+    if (!music_initialized)
+    {
+        return;
+    }
+
+    if (handle == NULL)
+    {
+        return;
+    }
+
+    current_track_music = (Mix_Music *) handle;
+    current_track_loop = looping;
+
+    if (looping)
+    {
+        loops = -1;
+    }
+    else
+    {
+        loops = 1;
+    }
+
+    // Don't loop when playing substitute music, as we do it
+    // ourselves instead.
+    if (playing_substitute && file_metadata.valid)
+    {
+        loops = 1;
+        SDL_LockAudio();
+        current_track_pos = 0;  // start of track
+        SDL_UnlockAudio();
+    }
+
+    Mix_PlayMusic(current_track_music, loops);
+}
+
+static void I_SDL_PauseSong(void)
+{
+    if (!music_initialized)
+    {
+        return;
+    }
+
+    musicpaused = true;
+
+    UpdateMusicVolume();
+}
+
+static void I_SDL_ResumeSong(void)
+{
+    if (!music_initialized)
+    {
+        return;
+    }
+
+    musicpaused = false;
+
+    UpdateMusicVolume();
+}
+
+static void I_SDL_StopSong(void)
+{
+    if (!music_initialized)
+    {
+        return;
+    }
+
+    Mix_HaltMusic();
+    playing_substitute = false;
+    current_track_music = NULL;
+}
+
+static void I_SDL_UnRegisterSong(void *handle)
+{
+    Mix_Music *music = (Mix_Music *) handle;
+
+    if (!music_initialized)
+    {
+        return;
+    }
+
+    if (handle == NULL)
+    {
+        return;
+    }
+
+    Mix_FreeMusic(music);
+}
+
+// Determine whether memory block is a .mid file 
+
+static boolean IsMid(byte *mem, int len)
+{
+    return len > 4 && !memcmp(mem, "MThd", 4);
+}
+
+static boolean ConvertMus(byte *musdata, int len, char *filename)
+{
+    MEMFILE *instream;
+    MEMFILE *outstream;
+    void *outbuf;
+    size_t outbuf_len;
+    int result;
+
+    instream = mem_fopen_read(musdata, len);
+    outstream = mem_fopen_write();
+
+    result = mus2mid(instream, outstream);
+
+    if (result == 0)
+    {
+        mem_get_buf(outstream, &outbuf, &outbuf_len);
+
+        M_WriteFile(filename, outbuf, outbuf_len);
+    }
+
+    mem_fclose(instream);
+    mem_fclose(outstream);
+
+    return result;
+}
+
+static void *I_SDL_RegisterSong(void *data, int len)
+{
+    char *filename;
+    Mix_Music *music;
+
+    if (!music_initialized)
+    {
+        return NULL;
+    }
+
+    playing_substitute = false;
+
+    // See if we're substituting this MUS for a high-quality replacement.
+    filename = GetSubstituteMusicFile(data, len);
+
+    if (filename != NULL)
+    {
+        music = Mix_LoadMUS(filename);
+
+        if (music == NULL)
+        {
+            // Fall through and play MIDI normally, but print an error
+            // message.
+            fprintf(stderr, "Failed to load substitute music file: %s: %s\n",
+                    filename, Mix_GetError());
+        }
+        else
+        {
+            // Read loop point metadata from the file so that we know where
+            // to loop the music.
+            playing_substitute = true;
+            ReadLoopPoints(filename, &file_metadata);
+            return music;
+        }
+    }
+
+    // MUS files begin with "MUS"
+    // Reject anything which doesnt have this signature
+
+    filename = M_TempFile("doom.mid");
+
+    if (IsMid(data, len) && len < MAXMIDLENGTH)
+    {
+        M_WriteFile(filename, data, len);
+    }
+    else
+    {
+       // Assume a MUS file and try to convert
+
+        ConvertMus(data, len, filename);
+    }
+
+    // Load the MIDI. In an ideal world we'd be using Mix_LoadMUS_RW()
+    // by now, but Mix_SetMusicCMD() only works with Mix_LoadMUS(), so
+    // we have to generate a temporary file.
+
+    music = Mix_LoadMUS(filename);
+
+    if (music == NULL)
+    {
+        // Failed to load
+
+        fprintf(stderr, "Error loading midi: %s\n", Mix_GetError());
+    }
+
+    // Remove the temporary MIDI file; however, when using an external
+    // MIDI program we can't delete the file. Otherwise, the program
+    // won't find the file to play. This means we leave a mess on
+    // disk :(
+
+    if (strlen(snd_musiccmd) == 0)
+    {
+        remove(filename);
+    }
+
+    free(filename);
+
+    return music;
+}
+
+// Is the song playing?
+static boolean I_SDL_MusicIsPlaying(void)
+{
+    if (!music_initialized)
+    {
+        return false;
+    }
+
+    return Mix_PlayingMusic();
+}
+
+// Get position in substitute music track, in seconds since start of track.
+static double GetMusicPosition(void)
+{
+    unsigned int music_pos;
+    int freq;
+
+    Mix_QuerySpec(&freq, NULL, NULL);
+
+    SDL_LockAudio();
+    music_pos = current_track_pos;
+    SDL_UnlockAudio();
+
+    return (double) music_pos / freq;
+}
+
+static void RestartCurrentTrack(void)
+{
+    double start = (double) file_metadata.start_time
+                 / file_metadata.samplerate_hz;
+
+    // If the track is playing on loop then reset to the start point.
+    // Otherwise we need to stop the track.
+    if (current_track_loop)
+    {
+        // If the track finished we need to restart it.
+        if (current_track_music != NULL)
+        {
+            Mix_PlayMusic(current_track_music, 1);
+        }
+
+        Mix_SetMusicPosition(start);
+        SDL_LockAudio();
+        current_track_pos = file_metadata.start_time;
+        SDL_UnlockAudio();
+    }
+    else
+    {
+        Mix_HaltMusic();
+        current_track_music = NULL;
+        playing_substitute = false;
+    }
+}
+
+// Poll music position; if we have passed the loop point end position
+// then we need to go back.
+static void I_SDL_PollMusic(void)
+{
+    if (playing_substitute && file_metadata.valid)
+    {
+        double end = (double) file_metadata.end_time
+                   / file_metadata.samplerate_hz;
+
+        // If we have reached the loop end point then we have to take action.
+        if (file_metadata.end_time >= 0 && GetMusicPosition() >= end)
+        {
+            RestartCurrentTrack();
+        }
+
+        // Have we reached the actual end of track (not loop end)?
+        if (!Mix_PlayingMusic() && current_track_loop)
+        {
+            RestartCurrentTrack();
+        }
+    }
+}
+
+static snddevice_t music_sdl_devices[] =
+{
+    SNDDEVICE_PAS,
+    SNDDEVICE_GUS,
+    SNDDEVICE_WAVEBLASTER,
+    SNDDEVICE_SOUNDCANVAS,
+    SNDDEVICE_GENMIDI,
+    SNDDEVICE_AWE32,
+};
+
+music_module_t music_sdl_module =
+{
+    music_sdl_devices,
+    arrlen(music_sdl_devices),
+    I_SDL_InitMusic,
+    I_SDL_ShutdownMusic,
+    I_SDL_SetMusicVolume,
+    I_SDL_PauseSong,
+    I_SDL_ResumeSong,
+    I_SDL_RegisterSong,
+    I_SDL_UnRegisterSong,
+    I_SDL_PlaySong,
+    I_SDL_StopSong,
+    I_SDL_MusicIsPlaying,
+    I_SDL_PollMusic,
+};
+
diff --git a/frosted-doom/i_sdlsound.c b/frosted-doom/i_sdlsound.c
new file mode 100644 (file)
index 0000000..7089378
--- /dev/null
@@ -0,0 +1,1092 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
+// Copyright(C) 2008 David Flater
+//
+// 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:
+//     System interface for sound.
+//
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "SDL.h"
+#include "SDL_mixer.h"
+
+#ifdef HAVE_LIBSAMPLERATE
+#include <samplerate.h>
+#endif
+
+#include "deh_str.h"
+#include "i_sound.h"
+#include "i_system.h"
+#include "i_swap.h"
+#include "m_argv.h"
+#include "m_misc.h"
+#include "w_wad.h"
+#include "z_zone.h"
+
+#include "doomtype.h"
+
+#define LOW_PASS_FILTER
+//#define DEBUG_DUMP_WAVS
+#define NUM_CHANNELS 16
+
+typedef struct allocated_sound_s allocated_sound_t;
+
+struct allocated_sound_s
+{
+    sfxinfo_t *sfxinfo;
+    Mix_Chunk chunk;
+    int use_count;
+    allocated_sound_t *prev, *next;
+};
+
+static boolean setpanning_workaround = false;
+
+static boolean sound_initialized = false;
+
+static sfxinfo_t *channels_playing[NUM_CHANNELS];
+
+static int mixer_freq;
+static Uint16 mixer_format;
+static int mixer_channels;
+static boolean use_sfx_prefix;
+static boolean (*ExpandSoundData)(sfxinfo_t *sfxinfo,
+                                  byte *data,
+                                  int samplerate,
+                                  int length) = NULL;
+
+// Doubly-linked list of allocated sounds.
+// When a sound is played, it is moved to the head, so that the oldest
+// sounds not used recently are at the tail.
+
+static allocated_sound_t *allocated_sounds_head = NULL;
+static allocated_sound_t *allocated_sounds_tail = NULL;
+static int allocated_sounds_size = 0;
+
+int use_libsamplerate = 0;
+
+// Scale factor used when converting libsamplerate floating point numbers
+// to integers. Too high means the sounds can clip; too low means they
+// will be too quiet. This is an amount that should avoid clipping most
+// of the time: with all the Doom IWAD sound effects, at least. If a PWAD
+// is used, clipping might occur.
+
+float libsamplerate_scale = 0.65f;
+
+// Hook a sound into the linked list at the head.
+
+static void AllocatedSoundLink(allocated_sound_t *snd)
+{
+    snd->prev = NULL;
+
+    snd->next = allocated_sounds_head;
+    allocated_sounds_head = snd;
+
+    if (allocated_sounds_tail == NULL)
+    {
+        allocated_sounds_tail = snd;
+    }
+    else
+    {
+        snd->next->prev = snd;
+    }
+}
+
+// Unlink a sound from the linked list.
+
+static void AllocatedSoundUnlink(allocated_sound_t *snd)
+{
+    if (snd->prev == NULL)
+    {
+        allocated_sounds_head = snd->next;
+    }
+    else
+    {
+        snd->prev->next = snd->next;
+    }
+
+    if (snd->next == NULL)
+    {
+        allocated_sounds_tail = snd->prev;
+    }
+    else
+    {
+        snd->next->prev = snd->prev;
+    }
+}
+
+static void FreeAllocatedSound(allocated_sound_t *snd)
+{
+    // Unlink from linked list.
+
+    AllocatedSoundUnlink(snd);
+
+    // Unlink from higher-level code.
+
+    snd->sfxinfo->driver_data = NULL;
+
+    // Keep track of the amount of allocated sound data:
+
+    allocated_sounds_size -= snd->chunk.alen;
+
+    free(snd);
+}
+
+// Search from the tail backwards along the allocated sounds list, find
+// and free a sound that is not in use, to free up memory.  Return true
+// for success.
+
+static boolean FindAndFreeSound(void)
+{
+    allocated_sound_t *snd;
+
+    snd = allocated_sounds_tail;
+
+    while (snd != NULL)
+    {
+        if (snd->use_count == 0)
+        {
+            FreeAllocatedSound(snd);
+            return true;
+        }
+
+        snd = snd->prev;
+    }
+
+    // No available sounds to free...
+
+    return false;
+}
+
+// Enforce SFX cache size limit.  We are just about to allocate "len"
+// bytes on the heap for a new sound effect, so free up some space
+// so that we keep allocated_sounds_size < snd_cachesize
+
+static void ReserveCacheSpace(size_t len)
+{
+    if (snd_cachesize <= 0)
+    {
+        return;
+    }
+
+    // Keep freeing sound effects that aren't currently being played,
+    // until there is enough space for the new sound.
+
+    while (allocated_sounds_size + len > snd_cachesize)
+    {
+        // Free a sound.  If there is nothing more to free, stop.
+
+        if (!FindAndFreeSound())
+        {
+            break;
+        }
+    }
+}
+
+// Allocate a block for a new sound effect.
+
+static Mix_Chunk *AllocateSound(sfxinfo_t *sfxinfo, size_t len)
+{
+    allocated_sound_t *snd;
+
+    // Keep allocated sounds within the cache size.
+
+    ReserveCacheSpace(len);
+
+    // Allocate the sound structure and data.  The data will immediately
+    // follow the structure, which acts as a header.
+
+    do
+    {
+        snd = malloc(sizeof(allocated_sound_t) + len);
+
+        // Out of memory?  Try to free an old sound, then loop round
+        // and try again.
+
+        if (snd == NULL && !FindAndFreeSound())
+        {
+            return NULL;
+        }
+
+    } while (snd == NULL);
+
+    // Skip past the chunk structure for the audio buffer
+
+    snd->chunk.abuf = (byte *) (snd + 1);
+    snd->chunk.alen = len;
+    snd->chunk.allocated = 1;
+    snd->chunk.volume = MIX_MAX_VOLUME;
+
+    snd->sfxinfo = sfxinfo;
+    snd->use_count = 0;
+
+    // driver_data pointer points to the allocated_sound structure.
+
+    sfxinfo->driver_data = snd;
+
+    // Keep track of how much memory all these cached sounds are using...
+
+    allocated_sounds_size += len;
+
+    AllocatedSoundLink(snd);
+
+    return &snd->chunk;
+}
+
+// Lock a sound, to indicate that it may not be freed.
+
+static void LockAllocatedSound(allocated_sound_t *snd)
+{
+    // Increase use count, to stop the sound being freed.
+
+    ++snd->use_count;
+
+    //printf("++ %s: Use count=%i\n", snd->sfxinfo->name, snd->use_count);
+
+    // When we use a sound, re-link it into the list at the head, so
+    // that the oldest sounds fall to the end of the list for freeing.
+
+    AllocatedSoundUnlink(snd);
+    AllocatedSoundLink(snd);
+}
+
+// Unlock a sound to indicate that it may now be freed.
+
+static void UnlockAllocatedSound(allocated_sound_t *snd)
+{
+    if (snd->use_count <= 0)
+    {
+        I_Error("Sound effect released more times than it was locked...");
+    }
+
+    --snd->use_count;
+
+    //printf("-- %s: Use count=%i\n", snd->sfxinfo->name, snd->use_count);
+}
+
+// When a sound stops, check if it is still playing.  If it is not, 
+// we can mark the sound data as CACHE to be freed back for other
+// means.
+
+static void ReleaseSoundOnChannel(int channel)
+{
+    sfxinfo_t *sfxinfo = channels_playing[channel];
+
+    if (sfxinfo == NULL)
+    {
+        return;
+    }
+
+    channels_playing[channel] = NULL;
+
+    UnlockAllocatedSound(sfxinfo->driver_data);
+}
+
+#ifdef HAVE_LIBSAMPLERATE
+
+// Returns the conversion mode for libsamplerate to use.
+
+static int SRC_ConversionMode(void)
+{
+    switch (use_libsamplerate)
+    {
+        // 0 = disabled
+
+        default:
+        case 0:
+            return -1;
+
+        // Ascending numbers give higher quality
+
+        case 1:
+            return SRC_LINEAR;
+        case 2:
+            return SRC_ZERO_ORDER_HOLD;
+        case 3:
+            return SRC_SINC_FASTEST;
+        case 4:
+            return SRC_SINC_MEDIUM_QUALITY;
+        case 5:
+            return SRC_SINC_BEST_QUALITY;
+    }
+}
+
+// libsamplerate-based generic sound expansion function for any sample rate
+//   unsigned 8 bits --> signed 16 bits
+//   mono --> stereo
+//   samplerate --> mixer_freq
+// Returns number of clipped samples.
+// DWF 2008-02-10 with cleanups by Simon Howard.
+
+static boolean ExpandSoundData_SRC(sfxinfo_t *sfxinfo,
+                                   byte *data,
+                                   int samplerate,
+                                   int length)
+{
+    SRC_DATA src_data;
+    uint32_t i, abuf_index=0, clipped=0;
+    uint32_t alen;
+    int retn;
+    int16_t *expanded;
+    Mix_Chunk *chunk;
+
+    src_data.input_frames = length;
+    src_data.data_in = malloc(length * sizeof(float));
+    src_data.src_ratio = (double)mixer_freq / samplerate;
+
+    // We include some extra space here in case of rounding-up.
+    src_data.output_frames = src_data.src_ratio * length + (mixer_freq / 4);
+    src_data.data_out = malloc(src_data.output_frames * sizeof(float));
+
+    assert(src_data.data_in != NULL && src_data.data_out != NULL);
+
+    // Convert input data to floats
+
+    for (i=0; i<length; ++i)
+    {
+        // Unclear whether 128 should be interpreted as "zero" or whether a
+        // symmetrical range should be assumed.  The following assumes a
+        // symmetrical range.
+        src_data.data_in[i] = data[i] / 127.5 - 1;
+    }
+
+    // Do the sound conversion
+
+    retn = src_simple(&src_data, SRC_ConversionMode(), 1);
+    assert(retn == 0);
+
+    // Allocate the new chunk.
+
+    alen = src_data.output_frames_gen * 4;
+
+    chunk = AllocateSound(sfxinfo, src_data.output_frames_gen * 4);
+
+    if (chunk == NULL)
+    {
+        return false;
+    }
+
+    expanded = (int16_t *) chunk->abuf;
+
+    // Convert the result back into 16-bit integers.
+
+    for (i=0; i<src_data.output_frames_gen; ++i)
+    {
+        // libsamplerate does not limit itself to the -1.0 .. 1.0 range on
+        // output, so a multiplier less than INT16_MAX (32767) is required
+        // to avoid overflows or clipping.  However, the smaller the
+        // multiplier, the quieter the sound effects get, and the more you
+        // have to turn down the music to keep it in balance.
+
+        // 22265 is the largest multiplier that can be used to resample all
+        // of the Vanilla DOOM sound effects to 48 kHz without clipping
+        // using SRC_SINC_BEST_QUALITY.  It is close enough (only slightly
+        // too conservative) for SRC_SINC_MEDIUM_QUALITY and
+        // SRC_SINC_FASTEST.  PWADs with interestingly different sound
+        // effects or target rates other than 48 kHz might still result in
+        // clipping--I don't know if there's a limit to it.
+
+        // As the number of clipped samples increases, the signal is
+        // gradually overtaken by noise, with the loudest parts going first.
+        // However, a moderate amount of clipping is often tolerated in the
+        // quest for the loudest possible sound overall.  The results of
+        // using INT16_MAX as the multiplier are not all that bad, but
+        // artifacts are noticeable during the loudest parts.
+
+        float cvtval_f =
+            src_data.data_out[i] * libsamplerate_scale * INT16_MAX;
+        int32_t cvtval_i = cvtval_f + (cvtval_f < 0 ? -0.5 : 0.5);
+
+        // Asymmetrical sound worries me, so we won't use -32768.
+        if (cvtval_i < -INT16_MAX)
+        {
+            cvtval_i = -INT16_MAX;
+            ++clipped;
+        }
+        else if (cvtval_i > INT16_MAX)
+        {
+            cvtval_i = INT16_MAX;
+            ++clipped;
+        }
+
+        // Left and right channels
+
+        expanded[abuf_index++] = cvtval_i;
+        expanded[abuf_index++] = cvtval_i;
+    }
+
+    free(src_data.data_in);
+    free(src_data.data_out);
+
+    if (clipped > 0)
+    {
+        fprintf(stderr, "Sound '%s': clipped %u samples (%0.2f %%)\n", 
+                        sfxinfo->name, clipped,
+                        400.0 * clipped / chunk->alen);
+    }
+
+    return true;
+}
+
+#endif
+
+static boolean ConvertibleRatio(int freq1, int freq2)
+{
+    int ratio;
+
+    if (freq1 > freq2)
+    {
+        return ConvertibleRatio(freq2, freq1);
+    }
+    else if ((freq2 % freq1) != 0)
+    {
+        // Not in a direct ratio
+
+        return false;
+    }
+    else
+    {
+        // Check the ratio is a power of 2
+
+        ratio = freq2 / freq1;
+
+        while ((ratio & 1) == 0)
+        {
+            ratio = ratio >> 1;
+        }
+
+        return ratio == 1;
+    }
+}
+
+#ifdef DEBUG_DUMP_WAVS
+
+// Debug code to dump resampled sound effects to WAV files for analysis.
+
+static void WriteWAV(char *filename, byte *data,
+                     uint32_t length, int samplerate)
+{
+    FILE *wav;
+    unsigned int i;
+    unsigned short s;
+
+    wav = fopen(filename, "wb");
+
+    // Header
+
+    fwrite("RIFF", 1, 4, wav);
+    i = LONG(36 + samplerate);
+    fwrite(&i, 4, 1, wav);
+    fwrite("WAVE", 1, 4, wav);
+
+    // Subchunk 1
+
+    fwrite("fmt ", 1, 4, wav);
+    i = LONG(16);
+    fwrite(&i, 4, 1, wav);           // Length
+    s = SHORT(1);
+    fwrite(&s, 2, 1, wav);           // Format (PCM)
+    s = SHORT(2);
+    fwrite(&s, 2, 1, wav);           // Channels (2=stereo)
+    i = LONG(samplerate);
+    fwrite(&i, 4, 1, wav);           // Sample rate
+    i = LONG(samplerate * 2 * 2);
+    fwrite(&i, 4, 1, wav);           // Byte rate (samplerate * stereo * 16 bit)
+    s = SHORT(2 * 2);
+    fwrite(&s, 2, 1, wav);           // Block align (stereo * 16 bit)
+    s = SHORT(16);
+    fwrite(&s, 2, 1, wav);           // Bits per sample (16 bit)
+
+    // Data subchunk
+
+    fwrite("data", 1, 4, wav);
+    i = LONG(length);
+    fwrite(&i, 4, 1, wav);           // Data length
+    fwrite(data, 1, length, wav);    // Data
+
+    fclose(wav);
+}
+
+#endif
+
+// Generic sound expansion function for any sample rate.
+// Returns number of clipped samples (always 0).
+
+static boolean ExpandSoundData_SDL(sfxinfo_t *sfxinfo,
+                                   byte *data,
+                                   int samplerate,
+                                   int length)
+{
+    SDL_AudioCVT convertor;
+    Mix_Chunk *chunk;
+    uint32_t expanded_length;
+    // Calculate the length of the expanded version of the sample.    
+
+    expanded_length = (uint32_t) ((((uint64_t) length) * mixer_freq) / samplerate);
+
+    // Double up twice: 8 -> 16 bit and mono -> stereo
+
+    expanded_length *= 4;
+
+    // Allocate a chunk in which to expand the sound
+
+    chunk = AllocateSound(sfxinfo, expanded_length);
+
+    if (chunk == NULL)
+    {
+        return false;
+    }
+
+    // If we can, use the standard / optimized SDL conversion routines.
+
+    if (samplerate <= mixer_freq
+     && ConvertibleRatio(samplerate, mixer_freq)
+     && SDL_BuildAudioCVT(&convertor,
+                          AUDIO_U8, 1, samplerate,
+                          mixer_format, mixer_channels, mixer_freq))
+    {
+        convertor.buf = chunk->abuf;
+        convertor.len = length;
+        memcpy(convertor.buf, data, length);
+
+        SDL_ConvertAudio(&convertor);
+    }
+    else
+    {
+        Sint16 *expanded = (Sint16 *) chunk->abuf;
+        int expanded_length;
+        int expand_ratio;
+        int i;
+
+        // Generic expansion if conversion does not work:
+        //
+        // SDL's audio conversion only works for rate conversions that are
+        // powers of 2; if the two formats are not in a direct power of 2
+        // ratio, do this naive conversion instead.
+
+        // number of samples in the converted sound
+
+        expanded_length = ((uint64_t) length * mixer_freq) / samplerate;
+        expand_ratio = (length << 8) / expanded_length;
+
+        for (i=0; i<expanded_length; ++i)
+        {
+            Sint16 sample;
+            int src;
+
+            src = (i * expand_ratio) >> 8;
+
+            sample = data[src] | (data[src] << 8);
+            sample -= 32768;
+
+            // expand 8->16 bits, mono->stereo
+
+            expanded[i * 2] = expanded[i * 2 + 1] = sample;
+        }
+
+#ifdef LOW_PASS_FILTER
+        // Perform a low-pass filter on the upscaled sound to filter
+        // out high-frequency noise from the conversion process.
+
+        {
+            float rc, dt, alpha;
+
+            // Low-pass filter for cutoff frequency f:
+            //
+            // For sampling rate r, dt = 1 / r
+            // rc = 1 / 2*pi*f
+            // alpha = dt / (rc + dt)
+
+            // Filter to the half sample rate of the original sound effect
+            // (maximum frequency, by nyquist)
+
+            dt = 1.0f / mixer_freq;
+            rc = 1.0f / (3.14f * samplerate);
+            alpha = dt / (rc + dt);
+
+            // Both channels are processed in parallel, hence [i-2]:
+
+            for (i=2; i<expanded_length * 2; ++i)
+            {
+                expanded[i] = (Sint16) (alpha * expanded[i]
+                                      + (1 - alpha) * expanded[i-2]);
+            }
+        }
+#endif /* #ifdef LOW_PASS_FILTER */
+    }
+
+    return true;
+}
+
+// Load and convert a sound effect
+// Returns true if successful
+
+static boolean CacheSFX(sfxinfo_t *sfxinfo)
+{
+    int lumpnum;
+    unsigned int lumplen;
+    int samplerate;
+    unsigned int length;
+    byte *data;
+
+    // need to load the sound
+
+    lumpnum = sfxinfo->lumpnum;
+    data = W_CacheLumpNum(lumpnum, PU_STATIC);
+    lumplen = W_LumpLength(lumpnum);
+
+    // Check the header, and ensure this is a valid sound
+
+    if (lumplen < 8
+     || data[0] != 0x03 || data[1] != 0x00)
+    {
+        // Invalid sound
+
+        return false;
+    }
+
+    // 16 bit sample rate field, 32 bit length field
+
+    samplerate = (data[3] << 8) | data[2];
+    length = (data[7] << 24) | (data[6] << 16) | (data[5] << 8) | data[4];
+
+    // If the header specifies that the length of the sound is greater than
+    // the length of the lump itself, this is an invalid sound lump
+
+    // We also discard sound lumps that are less than 49 samples long,
+    // as this is how DMX behaves - although the actual cut-off length
+    // seems to vary slightly depending on the sample rate.  This needs
+    // further investigation to better understand the correct
+    // behavior.
+
+    if (length > lumplen - 8 || length <= 48)
+    {
+        return false;
+    }
+
+    // The DMX sound library seems to skip the first 16 and last 16
+    // bytes of the lump - reason unknown.
+
+    data += 16;
+    length -= 32;
+
+    // Sample rate conversion
+
+    if (!ExpandSoundData(sfxinfo, data + 8, samplerate, length))
+    {
+        return false;
+    }
+
+#ifdef DEBUG_DUMP_WAVS
+    {
+        char filename[16];
+
+        M_snprintf(filename, sizeof(filename), "%s.wav",
+                   DEH_String(S_sfx[sound].name));
+        WriteWAV(filename, sound_chunks[sound].abuf,
+                 sound_chunks[sound].alen, mixer_freq);
+    }
+#endif
+
+    // don't need the original lump any more
+  
+    W_ReleaseLumpNum(lumpnum);
+
+    return true;
+}
+
+static void GetSfxLumpName(sfxinfo_t *sfx, char *buf, size_t buf_len)
+{
+    // Linked sfx lumps? Get the lump number for the sound linked to.
+
+    if (sfx->link != NULL)
+    {
+        sfx = sfx->link;
+    }
+
+    // Doom adds a DS* prefix to sound lumps; Heretic and Hexen don't
+    // do this.
+
+    if (use_sfx_prefix)
+    {
+        M_snprintf(buf, buf_len, "ds%s", DEH_String(sfx->name));
+    }
+    else
+    {
+        M_StringCopy(buf, DEH_String(sfx->name), buf_len);
+    }
+}
+
+#ifdef HAVE_LIBSAMPLERATE
+
+// Preload all the sound effects - stops nasty ingame freezes
+
+static void I_SDL_PrecacheSounds(sfxinfo_t *sounds, int num_sounds)
+{
+    char namebuf[9];
+    int i;
+
+    // Don't need to precache the sounds unless we are using libsamplerate.
+
+    if (use_libsamplerate == 0)
+    {
+       return;
+    }
+
+    printf("I_SDL_PrecacheSounds: Precaching all sound effects..");
+
+    for (i=0; i<num_sounds; ++i)
+    {
+        if ((i % 6) == 0)
+        {
+            printf(".");
+            fflush(stdout);
+        }
+
+        GetSfxLumpName(&sounds[i], namebuf, sizeof(namebuf));
+
+        sounds[i].lumpnum = W_CheckNumForName(namebuf);
+
+        if (sounds[i].lumpnum != -1)
+        {
+            CacheSFX(&sounds[i]);
+        }
+    }
+
+    printf("\n");
+}
+
+#else
+
+static void I_SDL_PrecacheSounds(sfxinfo_t *sounds, int num_sounds)
+{
+    // no-op
+}
+
+#endif
+
+// Load a SFX chunk into memory and ensure that it is locked.
+
+static boolean LockSound(sfxinfo_t *sfxinfo)
+{
+    // If the sound isn't loaded, load it now
+
+    if (sfxinfo->driver_data == NULL)
+    {
+        if (!CacheSFX(sfxinfo))
+        {
+            return false;
+        }
+    }
+
+    LockAllocatedSound(sfxinfo->driver_data);
+
+    return true;
+}
+
+//
+// Retrieve the raw data lump index
+//  for a given SFX name.
+//
+
+static int I_SDL_GetSfxLumpNum(sfxinfo_t *sfx)
+{
+    char namebuf[9];
+
+    GetSfxLumpName(sfx, namebuf, sizeof(namebuf));
+
+    return W_GetNumForName(namebuf);
+}
+
+static void I_SDL_UpdateSoundParams(int handle, int vol, int sep)
+{
+    int left, right;
+
+    if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS)
+    {
+        return;
+    }
+
+    left = ((254 - sep) * vol) / 127;
+    right = ((sep) * vol) / 127;
+
+    if (left < 0) left = 0;
+    else if ( left > 255) left = 255;
+    if (right < 0) right = 0;
+    else if (right > 255) right = 255;
+
+    // SDL_mixer version 1.2.8 and earlier has a bug in the Mix_SetPanning
+    // function.  A workaround is to call Mix_UnregisterAllEffects for
+    // the channel before calling it.  This is undesirable as it may lead
+    // to the channel volumes resetting briefly.
+
+    if (setpanning_workaround)
+    {
+        Mix_UnregisterAllEffects(handle);
+    }
+
+    Mix_SetPanning(handle, left, right);
+}
+
+//
+// Starting a sound means adding it
+//  to the current list of active sounds
+//  in the internal channels.
+// As the SFX info struct contains
+//  e.g. a pointer to the raw data,
+//  it is ignored.
+// As our sound handling does not handle
+//  priority, it is ignored.
+// Pitching (that is, increased speed of playback)
+//  is set, but currently not used by mixing.
+//
+
+static int I_SDL_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep)
+{
+    allocated_sound_t *snd;
+
+    if (!sound_initialized || channel < 0 || channel >= NUM_CHANNELS)
+    {
+        return -1;
+    }
+
+    // Release a sound effect if there is already one playing
+    // on this channel
+
+    ReleaseSoundOnChannel(channel);
+
+    // Get the sound data
+
+    if (!LockSound(sfxinfo))
+    {
+       return -1;
+    }
+
+    snd = sfxinfo->driver_data;
+
+    // play sound
+
+    Mix_PlayChannelTimed(channel, &snd->chunk, 0, -1);
+
+    channels_playing[channel] = sfxinfo;
+
+    // set separation, etc.
+    I_SDL_UpdateSoundParams(channel, vol, sep);
+
+    return channel;
+}
+
+static void I_SDL_StopSound(int handle)
+{
+    if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS)
+    {
+        return;
+    }
+
+    Mix_HaltChannel(handle);
+
+    // Sound data is no longer needed; release the
+    // sound data being used for this channel
+
+    ReleaseSoundOnChannel(handle);
+}
+
+
+static boolean I_SDL_SoundIsPlaying(int handle)
+{
+    if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS)
+    {
+        return false;
+    }
+
+    return Mix_Playing(handle);
+}
+
+// 
+// Periodically called to update the sound system
+//
+
+static void I_SDL_UpdateSound(void)
+{
+    int i;
+
+    // Check all channels to see if a sound has finished
+
+    for (i=0; i<NUM_CHANNELS; ++i)
+    {
+        if (channels_playing[i] && !I_SDL_SoundIsPlaying(i))
+        {
+            // Sound has finished playing on this channel,
+            // but sound data has not been released to cache
+            
+            ReleaseSoundOnChannel(i);
+        }
+    }
+}
+
+static void I_SDL_ShutdownSound(void)
+{    
+    if (!sound_initialized)
+    {
+        return;
+    }
+
+    Mix_CloseAudio();
+    SDL_QuitSubSystem(SDL_INIT_AUDIO);
+
+    sound_initialized = false;
+}
+
+// Calculate slice size, based on snd_maxslicetime_ms.
+// The result must be a power of two.
+
+static int GetSliceSize(void)
+{
+    int limit;
+    int n;
+
+    limit = (snd_samplerate * snd_maxslicetime_ms) / 1000;
+
+    // Try all powers of two, not exceeding the limit.
+
+    for (n=0;; ++n)
+    {
+        // 2^n <= limit < 2^n+1 ?
+
+        if ((1 << (n + 1)) > limit)
+        {
+            return (1 << n);
+        }
+    }
+
+    // Should never happen?
+
+    return 1024;
+}
+
+static boolean I_SDL_InitSound(boolean _use_sfx_prefix)
+{
+    int i;
+
+    use_sfx_prefix = _use_sfx_prefix;
+
+    // No sounds yet
+
+    for (i=0; i<NUM_CHANNELS; ++i)
+    {
+        channels_playing[i] = NULL;
+    }
+
+    if (SDL_Init(SDL_INIT_AUDIO) < 0)
+    {
+        fprintf(stderr, "Unable to set up sound.\n");
+        return false;
+    }
+
+    if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, GetSliceSize()) < 0)
+    {
+        fprintf(stderr, "Error initialising SDL_mixer: %s\n", Mix_GetError());
+        return false;
+    }
+
+    ExpandSoundData = ExpandSoundData_SDL;
+
+    Mix_QuerySpec(&mixer_freq, &mixer_format, &mixer_channels);
+
+#ifdef HAVE_LIBSAMPLERATE
+    if (use_libsamplerate != 0)
+    {
+        if (SRC_ConversionMode() < 0)
+        {
+            I_Error("I_SDL_InitSound: Invalid value for use_libsamplerate: %i",
+                    use_libsamplerate);
+        }
+
+        ExpandSoundData = ExpandSoundData_SRC;
+    }
+#else
+    if (use_libsamplerate != 0)
+    {
+        fprintf(stderr, "I_SDL_InitSound: use_libsamplerate=%i, but "
+                        "libsamplerate support not compiled in.\n",
+                        use_libsamplerate);
+    }
+#endif
+
+    // SDL_mixer version 1.2.8 and earlier has a bug in the Mix_SetPanning
+    // function that can cause the game to lock up.  If we're using an old
+    // version, we need to apply a workaround.  But the workaround has its
+    // own drawbacks ...
+
+    {
+        const SDL_version *mixer_version;
+        int v;
+
+        mixer_version = Mix_Linked_Version();
+        v = SDL_VERSIONNUM(mixer_version->major,
+                           mixer_version->minor,
+                           mixer_version->patch);
+
+        if (v <= SDL_VERSIONNUM(1, 2, 8))
+        {
+            setpanning_workaround = true;
+            fprintf(stderr, "\n"
+              "ATTENTION: You are using an old version of SDL_mixer!\n"
+              "           This version has a bug that may cause "
+                          "your sound to stutter.\n"
+              "           Please upgrade to a newer version!\n"
+              "\n");
+        }
+    }
+
+    Mix_AllocateChannels(NUM_CHANNELS);
+
+    SDL_PauseAudio(0);
+
+    sound_initialized = true;
+
+    return true;
+}
+
+static snddevice_t sound_sdl_devices[] = 
+{
+    SNDDEVICE_SB,
+    SNDDEVICE_PAS,
+    SNDDEVICE_GUS,
+    SNDDEVICE_WAVEBLASTER,
+    SNDDEVICE_SOUNDCANVAS,
+    SNDDEVICE_AWE32,
+};
+
+sound_module_t sound_sdl_module = 
+{
+    sound_sdl_devices,
+    arrlen(sound_sdl_devices),
+    I_SDL_InitSound,
+    I_SDL_ShutdownSound,
+    I_SDL_GetSfxLumpNum,
+    I_SDL_UpdateSound,
+    I_SDL_UpdateSoundParams,
+    I_SDL_StartSound,
+    I_SDL_StopSound,
+    I_SDL_SoundIsPlaying,
+    I_SDL_PrecacheSounds,
+};
+
index a8ca6ba189f3e47f3432d0281f853c8b64abbefb..71947d21101626f3863a9a0671a7a4c1f3ce4b2f 100644 (file)
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
-// DESCRIPTION:
-//     System interface for sound.
+// DESCRIPTION:  none
 //
-//-----------------------------------------------------------------------------
-
-static const char
-rcsid[] = "$Id: i_unix.c,v 1.5 1997/02/03 22:45:10 b1 Exp $";
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdarg.h>
 
-#include <math.h>
-#include <errno.h>
+#ifdef ORIGCODE
+#include "SDL_mixer.h"
+#endif
 
-#include <sys/time.h>
-#include <sys/types.h>
+#include "config.h"
+#include "doomfeatures.h"
+#include "doomtype.h"
 
-#ifndef LINUX
-#include <sys/filio.h>
+#ifdef ORIGCODE
+#include "gusconf.h"
 #endif
+#include "i_sound.h"
+#include "i_video.h"
+#include "m_argv.h"
+#include "m_config.h"
 
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
+// Sound sample rate to use for digital output (Hz)
 
-// Linux voxware output.
-#include <linux/soundcard.h>
+int snd_samplerate = 44100;
 
-// Timer stuff. Experimental.
-#include <time.h>
-#include <signal.h>
+// Maximum number of bytes to dedicate to allocated sound effects.
+// (Default: 64MB)
 
-#include "z_zone.h"
+int snd_cachesize = 64 * 1024 * 1024;
 
-#include "i_system.h"
-#include "i_sound.h"
-#include "m_argv.h"
-#include "m_misc.h"
-#include "w_wad.h"
-
-#include "doomdef.h"
-
-// UNIX hack, to be removed.
-#ifdef SNDSERV
-// Separate sound server process.
-FILE*  sndserver=0;
-char*  sndserver_filename = "./sndserver ";
-#elif SNDINTR
-
-// Update all 30 millisecs, approx. 30fps synchronized.
-// Linux resolution is allegedly 10 millisecs,
-//  scale is microseconds.
-#define SOUND_INTERVAL     500
-
-// Get the interrupt. Set duration in millisecs.
-int I_SoundSetTimer( int duration_of_tick );
-void I_SoundDelTimer( void );
-#else
-// None?
-#endif
+// Config variable that controls the sound buffer size.
+// We default to 28ms (1000 / 35fps = 1 buffer per tic).
 
+int snd_maxslicetime_ms = 28;
 
-// A quick hack to establish a protocol between
-// synchronous mix buffer updates and asynchronous
-// audio writes. Probably redundant with gametic.
-static int flag = 0;
+// External command to invoke to play back music.
 
-// The number of internal mixing channels,
-//  the samples calculated for each mixing step,
-//  the size of the 16bit, 2 hardware channel (stereo)
-//  mixing buffer, and the samplerate of the raw data.
+char *snd_musiccmd = "";
 
+// Low-level sound and music modules we are using
 
-// Needed for calling the actual sound output.
-#define SAMPLECOUNT            512
-#define NUM_CHANNELS           8
-// It is 2 for 16bit, and 2 for two channels.
-#define BUFMUL                  4
-#define MIXBUFFERSIZE          (SAMPLECOUNT*BUFMUL)
+static sound_module_t *sound_module;
+static music_module_t *music_module;
 
-#define SAMPLERATE             11025   // Hz
-#define SAMPLESIZE             2       // 16bit
+int snd_musicdevice = SNDDEVICE_SB;
+int snd_sfxdevice = SNDDEVICE_SB;
 
-// The actual lengths of all sound effects.
-int            lengths[NUMSFX];
+// Sound modules
 
-// The actual output device.
-int    audio_fd;
+extern void I_InitTimidityConfig(void);
+extern sound_module_t sound_sdl_module;
+extern sound_module_t sound_pcsound_module;
+extern music_module_t music_sdl_module;
+extern music_module_t music_opl_module;
 
-// The global mixing buffer.
-// Basically, samples from all active internal channels
-//  are modifed and added, and stored in the buffer
-//  that is submitted to the audio device.
-signed short   mixbuffer[MIXBUFFERSIZE];
+// For OPL module:
 
+extern int opl_io_port;
 
-// The channel step amount...
-unsigned int   channelstep[NUM_CHANNELS];
-// ... and a 0.16 bit remainder of last step.
-unsigned int   channelstepremainder[NUM_CHANNELS];
+// For native music module:
 
+extern char *timidity_cfg_path;
 
-// The channel data pointers, start and end.
-unsigned char* channels[NUM_CHANNELS];
-unsigned char* channelsend[NUM_CHANNELS];
+// DOS-specific options: These are unused but should be maintained
+// so that the config file can be shared between chocolate
+// doom and doom.exe
 
+#if ORIGCODE
+static int snd_sbport = 0;
+static int snd_sbirq = 0;
+static int snd_sbdma = 0;
+static int snd_mport = 0;
+#endif
 
-// Time/gametic that the channel started playing,
-//  used to determine oldest, which automatically
-//  has lowest priority.
-// In case number of active sounds exceeds
-//  available channels.
-int            channelstart[NUM_CHANNELS];
+// Compiled-in sound modules:
 
-// The sound in channel handles,
-//  determined on registration,
-//  might be used to unregister/stop/modify,
-//  currently unused.
-int            channelhandles[NUM_CHANNELS];
+static sound_module_t *sound_modules[] = 
+{
+#ifdef FEATURE_SOUND
+    &sound_sdl_module,
+    &sound_pcsound_module,
+#endif
+    NULL,
+};
 
-// SFX id of the playing sound effect.
-// Used to catch duplicates (like chainsaw).
-int            channelids[NUM_CHANNELS];                       
+// Compiled-in music modules:
 
-// Pitch to stepping lookup, unused.
-int            steptable[256];
+static music_module_t *music_modules[] =
+{
+#ifdef FEATURE_SOUND
+    &music_sdl_module,
+    &music_opl_module,
+#endif
+    NULL,
+};
 
-// Volume lookups.
-int            vol_lookup[128*256];
+// Check if a sound device is in the given list of devices
 
-// Hardware left and right channel volume lookup.
-int*           channelleftvol_lookup[NUM_CHANNELS];
-int*           channelrightvol_lookup[NUM_CHANNELS];
+static boolean SndDeviceInList(snddevice_t device, snddevice_t *list,
+                               int len)
+{
+    int i;
 
+    for (i=0; i<len; ++i)
+    {
+        if (device == list[i])
+        {
+            return true;
+        }
+    }
 
+    return false;
+}
 
+// Find and initialize a sound_module_t appropriate for the setting
+// in snd_sfxdevice.
 
-//
-// Safe ioctl, convenience.
-//
-void
-myioctl
-( int  fd,
-  int  command,
-  int* arg )
-{   
-    int                rc;
-    
-    rc = ioctl(fd, command, arg);  
-    if (rc < 0)
-    {
-       fprintf(stderr, "ioctl(dsp,%d,arg) failed\n", command);
-       fprintf(stderr, "errno=%d\n", errno);
-       exit(-1);
+static void InitSfxModule(boolean use_sfx_prefix)
+{
+    int i;
+
+    sound_module = NULL;
+
+    for (i=0; sound_modules[i] != NULL; ++i)
+    {
+        // Is the sfx device in the list of devices supported by
+        // this module?
+
+        if (SndDeviceInList(snd_sfxdevice, 
+                            sound_modules[i]->sound_devices,
+                            sound_modules[i]->num_sound_devices))
+        {
+            // Initialize the module
+
+            if (sound_modules[i]->Init(use_sfx_prefix))
+            {
+                sound_module = sound_modules[i];
+                return;
+            }
+        }
     }
 }
 
+// Initialize music according to snd_musicdevice.
 
+static void InitMusicModule(void)
+{
+    int i;
 
+    music_module = NULL;
 
+    for (i=0; music_modules[i] != NULL; ++i)
+    {
+        // Is the music device in the list of devices supported
+        // by this module?
+
+        if (SndDeviceInList(snd_musicdevice, 
+                            music_modules[i]->sound_devices,
+                            music_modules[i]->num_sound_devices))
+        {
+            // Initialize the module
+
+            if (music_modules[i]->Init())
+            {
+                music_module = music_modules[i];
+                return;
+            }
+        }
+    }
+}
 
 //
-// This function loads the sound data from the WAD lump,
-//  for single sound.
+// Initializes sound stuff, including volume
+// Sets channels, SFX and music volume,
+//  allocates channel buffer, sets S_sfx lookup.
 //
-void*
-getsfx
-( char*         sfxname,
-  int*          len )
-{
-    unsigned char*      sfx;
-    unsigned char*      paddedsfx;
-    int                 i;
-    int                 size;
-    int                 paddedsize;
-    char                name[20];
-    int                 sfxlump;
-
-    
-    // Get the sound data from the WAD, allocate lump
-    //  in zone memory.
-    sprintf(name, "ds%s", sfxname);
-
-    // Now, there is a severe problem with the
-    //  sound handling, in it is not (yet/anymore)
-    //  gamemode aware. That means, sounds from
-    //  DOOM II will be requested even with DOOM
-    //  shareware.
-    // The sound list is wired into sounds.c,
-    //  which sets the external variable.
-    // I do not do runtime patches to that
-    //  variable. Instead, we will use a
-    //  default sound for replacement.
-    if ( W_CheckNumForName(name) == -1 )
-      sfxlump = W_GetNumForName("dspistol");
-    else
-      sfxlump = W_GetNumForName(name);
-    
-    size = W_LumpLength( sfxlump );
-
-    // Debug.
-    // fprintf( stderr, "." );
-    //fprintf( stderr, " -loading  %s (lump %d, %d bytes)\n",
-    //      sfxname, sfxlump, size );
-    //fflush( stderr );
-    
-    sfx = (unsigned char*)W_CacheLumpNum( sfxlump, PU_STATIC );
-
-    // Pads the sound effect out to the mixing buffer size.
-    // The original realloc would interfere with zone memory.
-    paddedsize = ((size-8 + (SAMPLECOUNT-1)) / SAMPLECOUNT) * SAMPLECOUNT;
-
-    // Allocate from zone memory.
-    paddedsfx = (unsigned char*)Z_Malloc( paddedsize+8, PU_STATIC, 0 );
-    // ddt: (unsigned char *) realloc(sfx, paddedsize+8);
-    // This should interfere with zone memory handling,
-    //  which does not kick in in the soundserver.
-
-    // Now copy and pad.
-    memcpy(  paddedsfx, sfx, size );
-    for (i=size ; i<paddedsize+8 ; i++)
-        paddedsfx[i] = 128;
-
-    // Remove the cached lump.
-    Z_Free( sfx );
-    
-    // Preserve padded length.
-    *len = paddedsize;
-
-    // Return allocated padded data.
-    return (void *) (paddedsfx + 8);
-}
 
+void I_InitSound(boolean use_sfx_prefix)
+{  
+    boolean nosound, nosfx, nomusic;
 
+    //!
+    // @vanilla
+    //
+    // Disable all sound output.
+    //
 
+    nosound = M_CheckParm("-nosound") > 0;
 
+    //!
+    // @vanilla
+    //
+    // Disable sound effects. 
+    //
 
-//
-// This function adds a sound to the
-//  list of currently active sounds,
-//  which is maintained as a given number
-//  (eight, usually) of internal channels.
-// Returns a handle.
-//
-int
-addsfx
-( int          sfxid,
-  int          volume,
-  int          step,
-  int          seperation )
-{
-    static unsigned short      handlenums = 0;
-    int                i;
-    int                rc = -1;
-    
-    int                oldest = gametic;
-    int                oldestnum = 0;
-    int                slot;
-
-    int                rightvol;
-    int                leftvol;
-
-    // Chainsaw troubles.
-    // Play these sound effects only one at a time.
-    if ( sfxid == sfx_sawup
-        || sfxid == sfx_sawidl
-        || sfxid == sfx_sawful
-        || sfxid == sfx_sawhit
-        || sfxid == sfx_stnmov
-        || sfxid == sfx_pistol  )
-    {
-       // Loop all channels, check.
-       for (i=0 ; i<NUM_CHANNELS ; i++)
-       {
-           // Active, and using the same SFX?
-           if ( (channels[i])
-                && (channelids[i] == sfxid) )
-           {
-               // Reset.
-               channels[i] = 0;
-               // We are sure that iff,
-               //  there will only be one.
-               break;
-           }
-       }
-    }
-
-    // Loop all channels to find oldest SFX.
-    for (i=0; (i<NUM_CHANNELS) && (channels[i]); i++)
-    {
-       if (channelstart[i] < oldest)
-       {
-           oldestnum = i;
-           oldest = channelstart[i];
-       }
-    }
-
-    // Tales from the cryptic.
-    // If we found a channel, fine.
-    // If not, we simply overwrite the first one, 0.
-    // Probably only happens at startup.
-    if (i == NUM_CHANNELS)
-       slot = oldestnum;
-    else
-       slot = i;
-
-    // Okay, in the less recent channel,
-    //  we will handle the new SFX.
-    // Set pointer to raw data.
-    channels[slot] = (unsigned char *) S_sfx[sfxid].data;
-    // Set pointer to end of raw data.
-    channelsend[slot] = channels[slot] + lengths[sfxid];
-
-    // Reset current handle number, limited to 0..100.
-    if (!handlenums)
-       handlenums = 100;
-
-    // Assign current handle number.
-    // Preserved so sounds could be stopped (unused).
-    channelhandles[slot] = rc = handlenums++;
-
-    // Set stepping???
-    // Kinda getting the impression this is never used.
-    channelstep[slot] = step;
-    // ???
-    channelstepremainder[slot] = 0;
-    // Should be gametic, I presume.
-    channelstart[slot] = gametic;
-
-    // Separation, that is, orientation/stereo.
-    //  range is: 1 - 256
-    seperation += 1;
-
-    // Per left/right channel.
-    //  x^2 seperation,
-    //  adjust volume properly.
-    leftvol =
-       volume - ((volume*seperation*seperation) >> 16); ///(256*256);
-    seperation = seperation - 257;
-    rightvol =
-       volume - ((volume*seperation*seperation) >> 16);        
-
-    // Sanity check, clamp volume.
-    if (rightvol < 0 || rightvol > 127)
-       I_Error("rightvol out of bounds");
-    
-    if (leftvol < 0 || leftvol > 127)
-       I_Error("leftvol out of bounds");
-    
-    // Get the proper lookup table piece
-    //  for this volume level???
-    channelleftvol_lookup[slot] = &vol_lookup[leftvol*256];
-    channelrightvol_lookup[slot] = &vol_lookup[rightvol*256];
-
-    // Preserve sound SFX id,
-    //  e.g. for avoiding duplicates of chainsaw.
-    channelids[slot] = sfxid;
-
-    // You tell me.
-    return rc;
-}
-
+    nosfx = M_CheckParm("-nosfx") > 0;
 
+    //!
+    // @vanilla
+    //
+    // Disable music.
+    //
 
+    nomusic = M_CheckParm("-nomusic") > 0;
 
+    // Initialize the sound and music subsystems.
 
-//
-// SFX API
-// Note: this was called by S_Init.
-// However, whatever they did in the
-// old DPMS based DOS version, this
-// were simply dummies in the Linux
-// version.
-// See soundserver initdata().
-//
-void I_SetChannels()
-{
-  // Init internal lookups (raw data, mixing buffer, channels).
-  // This function sets up internal lookups used during
-  //  the mixing process. 
-  int          i;
-  int          j;
-    
-  int* steptablemid = steptable + 128;
-  
-  // Okay, reset internal mixing channels to zero.
-  /*for (i=0; i<NUM_CHANNELS; i++)
-  {
-    channels[i] = 0;
-  }*/
-
-  // This table provides step widths for pitch parameters.
-  // I fail to see that this is currently used.
-  for (i=-128 ; i<128 ; i++)
-    steptablemid[i] = (int)(pow(2.0, (i/64.0))*65536.0);
-  
-  
-  // Generates volume lookup tables
-  //  which also turn the unsigned samples
-  //  into signed samples.
-  for (i=0 ; i<128 ; i++)
-    for (j=0 ; j<256 ; j++)
-      vol_lookup[i*256+j] = (i*(j-128)*256)/127;
-}      
-
-void I_SetSfxVolume(int volume)
-{
-  // Identical to DOS.
-  // Basically, this should propagate
-  //  the menu/config file setting
-  //  to the state variable used in
-  //  the mixing.
-  snd_SfxVolume = volume;
+    if (!nosound && !screensaver_mode)
+    {
+        // This is kind of a hack. If native MIDI is enabled, set up
+        // the TIMIDITY_CFG environment variable here before SDL_mixer
+        // is opened.
+
+        if (!nomusic
+         && (snd_musicdevice == SNDDEVICE_GENMIDI
+          || snd_musicdevice == SNDDEVICE_GUS))
+        {
+            I_InitTimidityConfig();
+        }
+
+        if (!nosfx)
+        {
+            InitSfxModule(use_sfx_prefix);
+        }
+
+        if (!nomusic)
+        {
+            InitMusicModule();
+        }
+    }
 }
 
-// MUSIC API - dummy. Some code from DOS version.
-void I_SetMusicVolume(int volume)
+void I_ShutdownSound(void)
 {
-  // Internal state variable.
-  snd_MusicVolume = volume;
-  // Now set volume on output device.
-  // Whatever( snd_MusciVolume );
-}
+    if (sound_module != NULL)
+    {
+        sound_module->Shutdown();
+    }
 
+    if (music_module != NULL)
+    {
+        music_module->Shutdown();
+    }
+}
 
-//
-// Retrieve the raw data lump index
-//  for a given SFX name.
-//
-int I_GetSfxLumpNum(sfxinfo_t* sfx)
+int I_GetSfxLumpNum(sfxinfo_t *sfxinfo)
 {
-    char namebuf[9];
-    sprintf(namebuf, "ds%s", sfx->name);
-    return W_GetNumForName(namebuf);
+    if (sound_module != NULL) 
+    {
+        return sound_module->GetSfxLumpNum(sfxinfo);
+    }
+    else
+    {
+        return 0;
+    }
 }
 
-//
-// Starting a sound means adding it
-//  to the current list of active sounds
-//  in the internal channels.
-// As the SFX info struct contains
-//  e.g. a pointer to the raw data,
-//  it is ignored.
-// As our sound handling does not handle
-//  priority, it is ignored.
-// Pitching (that is, increased speed of playback)
-//  is set, but currently not used by mixing.
-//
-int
-I_StartSound
-( int          id,
-  int          vol,
-  int          sep,
-  int          pitch,
-  int          priority )
+void I_UpdateSound(void)
 {
+    if (sound_module != NULL)
+    {
+        sound_module->Update();
+    }
 
-  // UNUSED
-  priority = 0;
-  
-#ifdef SNDSERV 
-    if (sndserver)
-    {
-       fprintf(sndserver, "p%2.2x%2.2x%2.2x%2.2x\n", id, pitch, vol, sep);
-       fflush(sndserver);
-    }
-    // warning: control reaches end of non-void function.
-    return id;
-#else
-    // Debug.
-    //fprintf( stderr, "starting sound %d", id );
-    
-    // Returns a handle (not used).
-    id = addsfx( id, vol, steptable[pitch], sep );
-
-    // fprintf( stderr, "/handle is %d\n", id );
-    
-    return id;
-#endif
+    if (music_module != NULL && music_module->Poll != NULL)
+    {
+        music_module->Poll();
+    }
 }
 
+static void CheckVolumeSeparation(int *vol, int *sep)
+{
+    if (*sep < 0)
+    {
+        *sep = 0;
+    }
+    else if (*sep > 254)
+    {
+        *sep = 254;
+    }
 
+    if (*vol < 0)
+    {
+        *vol = 0;
+    }
+    else if (*vol > 127)
+    {
+        *vol = 127;
+    }
+}
 
-void I_StopSound (int handle)
+void I_UpdateSoundParams(int channel, int vol, int sep)
 {
-  // You need the handle returned by StartSound.
-  // Would be looping all channels,
-  //  tracking down the handle,
-  //  an setting the channel to zero.
-  
-  // UNUSED.
-  handle = 0;
+    if (sound_module != NULL)
+    {
+        CheckVolumeSeparation(&vol, &sep);
+        sound_module->UpdateSoundParams(channel, vol, sep);
+    }
 }
 
-
-int I_SoundIsPlaying(int handle)
+int I_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep)
 {
-    // Ouch.
-    return gametic < handle;
+    if (sound_module != NULL)
+    {
+        CheckVolumeSeparation(&vol, &sep);
+        return sound_module->StartSound(sfxinfo, channel, vol, sep);
+    }
+    else
+    {
+        return 0;
+    }
 }
 
-
-
-
-//
-// This function loops all active (internal) sound
-//  channels, retrieves a given number of samples
-//  from the raw sound data, modifies it according
-//  to the current (internal) channel parameters,
-//  mixes the per channel samples into the global
-//  mixbuffer, clamping it to the allowed range,
-//  and sets up everything for transferring the
-//  contents of the mixbuffer to the (two)
-//  hardware channels (left and right, that is).
-//
-// This function currently supports only 16bit.
-//
-void I_UpdateSound( void )
+void I_StopSound(int channel)
 {
-#ifdef SNDINTR
-  // Debug. Count buffer misses with interrupt.
-  static int misses = 0;
-#endif
-
-  
-  // Mix current sound data.
-  // Data, from raw sound, for right and left.
-  register unsigned int        sample;
-  register int         dl;
-  register int         dr;
-  
-  // Pointers in global mixbuffer, left, right, end.
-  signed short*                leftout;
-  signed short*                rightout;
-  signed short*                leftend;
-  // Step in mixbuffer, left and right, thus two.
-  int                          step;
-
-  // Mixing channel index.
-  int                          chan;
-    
-    // Left and right channel
-    //  are in global mixbuffer, alternating.
-    leftout = mixbuffer;
-    rightout = mixbuffer+1;
-    step = 2;
-
-    // Determine end, for left channel only
-    //  (right channel is implicit).
-    leftend = mixbuffer + SAMPLECOUNT*step;
-
-    // Mix sounds into the mixing buffer.
-    // Loop over step*SAMPLECOUNT,
-    //  that is 512 values for two channels.
-    while (leftout != leftend)
-    {
-       // Reset left/right value. 
-       dl = 0;
-       dr = 0;
-
-       // Love thy L2 chache - made this a loop.
-       // Now more channels could be set at compile time
-       //  as well. Thus loop those  channels.
-       for ( chan = 0; chan < NUM_CHANNELS; chan++ )
-       {
-           // Check channel, if active.
-           if (channels[ chan ])
-           {
-               // Get the raw data from the channel. 
-               sample = *channels[ chan ];
-               // Add left and right part
-               //  for this channel (sound)
-               //  to the current data.
-               // Adjust volume accordingly.
-               dl += channelleftvol_lookup[ chan ][sample];
-               dr += channelrightvol_lookup[ chan ][sample];
-               // Increment index ???
-               channelstepremainder[ chan ] += channelstep[ chan ];
-               // MSB is next sample???
-               channels[ chan ] += channelstepremainder[ chan ] >> 16;
-               // Limit to LSB???
-               channelstepremainder[ chan ] &= 65536-1;
-
-               // Check whether we are done.
-               if (channels[ chan ] >= channelsend[ chan ])
-                   channels[ chan ] = 0;
-           }
-       }
-       
-       // Clamp to range. Left hardware channel.
-       // Has been char instead of short.
-       // if (dl > 127) *leftout = 127;
-       // else if (dl < -128) *leftout = -128;
-       // else *leftout = dl;
-
-       if (dl > 0x7fff)
-           *leftout = 0x7fff;
-       else if (dl < -0x8000)
-           *leftout = -0x8000;
-       else
-           *leftout = dl;
-
-       // Same for right hardware channel.
-       if (dr > 0x7fff)
-           *rightout = 0x7fff;
-       else if (dr < -0x8000)
-           *rightout = -0x8000;
-       else
-           *rightout = dr;
-
-       // Increment current pointers in mixbuffer.
-       leftout += step;
-       rightout += step;
-    }
-
-#ifdef SNDINTR
-    // Debug check.
-    if ( flag )
-    {
-      misses += flag;
-      flag = 0;
-    }
-    
-    if ( misses > 10 )
-    {
-      fprintf( stderr, "I_SoundUpdate: missed 10 buffer writes\n");
-      misses = 0;
-    }
-    
-    // Increment flag for update.
-    flag++;
-#endif
+    if (sound_module != NULL)
+    {
+        sound_module->StopSound(channel);
+    }
 }
 
-
-// 
-// This would be used to write out the mixbuffer
-//  during each game loop update.
-// Updates sound buffer and audio device at runtime. 
-// It is called during Timer interrupt with SNDINTR.
-// Mixing now done synchronous, and
-//  only output be done asynchronous?
-//
-void
-I_SubmitSound(void)
+boolean I_SoundIsPlaying(int channel)
 {
-  // Write it to DSP device.
-  write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL);
+    if (sound_module != NULL)
+    {
+        return sound_module->SoundIsPlaying(channel);
+    }
+    else
+    {
+        return false;
+    }
 }
 
-
-
-void
-I_UpdateSoundParams
-( int  handle,
-  int  vol,
-  int  sep,
-  int  pitch)
+void I_PrecacheSounds(sfxinfo_t *sounds, int num_sounds)
 {
-  // I fail too see that this is used.
-  // Would be using the handle to identify
-  //  on which channel the sound might be active,
-  //  and resetting the channel parameters.
-
-  // UNUSED.
-  handle = vol = sep = pitch = 0;
+    if (sound_module != NULL && sound_module->CacheSounds != NULL)
+    {
+       sound_module->CacheSounds(sounds, num_sounds);
+    }
 }
 
-
-
-
-void I_ShutdownSound(void)
-{    
-#ifdef SNDSERV
-  if (sndserver)
-  {
-    // Send a "quit" command.
-    fprintf(sndserver, "q\n");
-    fflush(sndserver);
-  }
-#else
-  // Wait till all pending sounds are finished.
-  int done = 0;
-  int i;
-  
-
-  // FIXME (below).
-  fprintf( stderr, "I_ShutdownSound: NOT finishing pending sounds\n");
-  fflush( stderr );
-  
-  while ( !done )
-  {
-    for( i=0 ; i<8 && !channels[i] ; i++);
-    
-    // FIXME. No proper channel output.
-    //if (i==8)
-    done=1;
-  }
-#ifdef SNDINTR
-  I_SoundDelTimer();
-#endif
-  
-  // Cleaning up -releasing the DSP device.
-  close ( audio_fd );
-#endif
-
-  // Done.
-  return;
+void I_InitMusic(void)
+{
 }
 
+void I_ShutdownMusic(void)
+{
 
+}
 
-
-
-
-void
-I_InitSound()
-{ 
-#ifdef SNDSERV
-  char buffer[256];
-  
-  if (getenv("DOOMWADDIR"))
-    sprintf(buffer, "%s/%s",
-           getenv("DOOMWADDIR"),
-           sndserver_filename);
-  else
-    sprintf(buffer, "%s", sndserver_filename);
-  
-  // start sound process
-  if ( !access(buffer, X_OK) )
-  {
-    strcat(buffer, " -quiet");
-    sndserver = popen(buffer, "w");
-  }
-  else
-    fprintf(stderr, "Could not start sound server [%s]\n", buffer);
-#else
-    
-  int i;
-  
-#ifdef SNDINTR
-  fprintf( stderr, "I_SoundSetTimer: %d microsecs\n", SOUND_INTERVAL );
-  I_SoundSetTimer( SOUND_INTERVAL );
-#endif
-    
-  // Secure and configure sound device first.
-  fprintf( stderr, "I_InitSound: ");
-  
-  audio_fd = open("/dev/dsp", O_WRONLY);
-  if (audio_fd<0)
-    fprintf(stderr, "Could not open /dev/dsp\n");
-  
-                     
-  i = 11 | (2<<16);                                           
-  myioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &i);
-  myioctl(audio_fd, SNDCTL_DSP_RESET, 0);
-  
-  i=SAMPLERATE;
-  
-  myioctl(audio_fd, SNDCTL_DSP_SPEED, &i);
-  
-  i=1;
-  myioctl(audio_fd, SNDCTL_DSP_STEREO, &i);
-  
-  myioctl(audio_fd, SNDCTL_DSP_GETFMTS, &i);
-  
-  if (i&=AFMT_S16_LE)    
-    myioctl(audio_fd, SNDCTL_DSP_SETFMT, &i);
-  else
-    fprintf(stderr, "Could not play signed 16 data\n");
-
-  fprintf(stderr, " configured audio device\n" );
-
-    
-  // Initialize external data (all sounds) at start, keep static.
-  fprintf( stderr, "I_InitSound: ");
-  
-  for (i=1 ; i<NUMSFX ; i++)
-  { 
-    // Alias? Example is the chaingun sound linked to pistol.
-    if (!S_sfx[i].link)
-    {
-      // Load data from WAD file.
-      S_sfx[i].data = getsfx( S_sfx[i].name, &lengths[i] );
-    }  
-    else
+void I_SetMusicVolume(int volume)
+{
+    if (music_module != NULL)
     {
-      // Previously loaded already?
-      S_sfx[i].data = S_sfx[i].link->data;
-      lengths[i] = lengths[(S_sfx[i].link - S_sfx)/sizeof(sfxinfo_t)];
-    }
-  }
-
-  fprintf( stderr, " pre-cached all sound data\n");
-  
-  // Now initialize mixbuffer with zero.
-  for ( i = 0; i< MIXBUFFERSIZE; i++ )
-    mixbuffer[i] = 0;
-  
-  // Finished initialization.
-  fprintf(stderr, "I_InitSound: sound module ready\n");
-    
-#endif
+        music_module->SetMusicVolume(volume);
+    }
 }
 
-
-
-
-//
-// MUSIC API.
-// Still no music done.
-// Remains. Dummies.
-//
-void I_InitMusic(void)         { }
-void I_ShutdownMusic(void)     { }
-
-static int     looping=0;
-static int     musicdies=-1;
-
-void I_PlaySong(int handle, int looping)
+void I_PauseSong(void)
 {
-  // UNUSED.
-  handle = looping = 0;
-  musicdies = gametic + TICRATE*30;
+    if (music_module != NULL)
+    {
+        music_module->PauseMusic();
+    }
 }
 
-void I_PauseSong (int handle)
+void I_ResumeSong(void)
 {
-  // UNUSED.
-  handle = 0;
+    if (music_module != NULL)
+    {
+        music_module->ResumeMusic();
+    }
 }
 
-void I_ResumeSong (int handle)
+void *I_RegisterSong(void *data, int len)
 {
-  // UNUSED.
-  handle = 0;
+    if (music_module != NULL)
+    {
+        return music_module->RegisterSong(data, len);
+    }
+    else
+    {
+        return NULL;
+    }
 }
 
-void I_StopSong(int handle)
+void I_UnRegisterSong(void *handle)
 {
-  // UNUSED.
-  handle = 0;
-  
-  looping = 0;
-  musicdies = 0;
+    if (music_module != NULL)
+    {
+        music_module->UnRegisterSong(handle);
+    }
 }
 
-void I_UnRegisterSong(int handle)
+void I_PlaySong(void *handle, boolean looping)
 {
-  // UNUSED.
-  handle = 0;
+    if (music_module != NULL)
+    {
+        music_module->PlaySong(handle, looping);
+    }
 }
 
-int I_RegisterSong(void* data)
+void I_StopSong(void)
 {
-  // UNUSED.
-  data = NULL;
-  
-  return 1;
+    if (music_module != NULL)
+    {
+        music_module->StopSong();
+    }
 }
 
-// Is the song playing?
-int I_QrySongPlaying(int handle)
+boolean I_MusicIsPlaying(void)
 {
-  // UNUSED.
-  handle = 0;
-  return looping || musicdies > gametic;
+    if (music_module != NULL)
+    {
+        return music_module->MusicIsPlaying();
+    }
+    else
+    {
+        return false;
+    }
 }
 
-
-
-//
-// Experimental stuff.
-// A Linux timer interrupt, for asynchronous
-//  sound output.
-// I ripped this out of the Timer class in
-//  our Difference Engine, including a few
-//  SUN remains...
-//  
-#ifdef sun
-    typedef     sigset_t        tSigSet;
-#else    
-    typedef     int             tSigSet;
+void I_BindSoundVariables(void)
+{
+#ifdef ORIGCODE
+    extern int use_libsamplerate;
+    extern float libsamplerate_scale;
+
+    M_BindVariable("snd_musicdevice",   &snd_musicdevice);
+    M_BindVariable("snd_sfxdevice",     &snd_sfxdevice);
+    M_BindVariable("snd_sbport",        &snd_sbport);
+    M_BindVariable("snd_sbirq",         &snd_sbirq);
+    M_BindVariable("snd_sbdma",         &snd_sbdma);
+    M_BindVariable("snd_mport",         &snd_mport);
+    M_BindVariable("snd_maxslicetime_ms", &snd_maxslicetime_ms);
+    M_BindVariable("snd_musiccmd",      &snd_musiccmd);
+    M_BindVariable("snd_samplerate",    &snd_samplerate);
+    M_BindVariable("snd_cachesize",     &snd_cachesize);
+    M_BindVariable("opl_io_port",       &opl_io_port);
+
+    M_BindVariable("timidity_cfg_path", &timidity_cfg_path);
+    M_BindVariable("gus_patch_path",    &gus_patch_path);
+    M_BindVariable("gus_ram_kb",        &gus_ram_kb);
+
+#ifdef FEATURE_SOUND
+    M_BindVariable("use_libsamplerate",   &use_libsamplerate);
+    M_BindVariable("libsamplerate_scale", &libsamplerate_scale);
 #endif
 
+    // Before SDL_mixer version 1.2.11, MIDI music caused the game
+    // to crash when it looped.  If this is an old SDL_mixer version,
+    // disable MIDI.
 
-// We might use SIGVTALRM and ITIMER_VIRTUAL, if the process
-//  time independend timer happens to get lost due to heavy load.
-// SIGALRM and ITIMER_REAL doesn't really work well.
-// There are issues with profiling as well.
-static int /*__itimer_which*/  itimer = ITIMER_REAL;
-
-static int sig = SIGALRM;
-
-// Interrupt handler.
-void I_HandleSoundTimer( int ignore )
-{
-  // Debug.
-  //fprintf( stderr, "%c", '+' ); fflush( stderr );
-  
-  // Feed sound device if necesary.
-  if ( flag )
-  {
-    // See I_SubmitSound().
-    // Write it to DSP device.
-    write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL);
-
-    // Reset flag counter.
-    flag = 0;
-  }
-  else
-    return;
-  
-  // UNUSED, but required.
-  ignore = 0;
-  return;
-}
+#ifdef __MACOSX__
+    {
+        const SDL_version *v = Mix_Linked_Version();
 
-// Get the interrupt. Set duration in millisecs.
-int I_SoundSetTimer( int duration_of_tick )
-{
-  // Needed for gametick clockwork.
-  struct itimerval    value;
-  struct itimerval    ovalue;
-  struct sigaction    act;
-  struct sigaction    oact;
-
-  int res;
-  
-  // This sets to SA_ONESHOT and SA_NOMASK, thus we can not use it.
-  //     signal( _sig, handle_SIG_TICK );
-  
-  // Now we have to change this attribute for repeated calls.
-  act.sa_handler = I_HandleSoundTimer;
-#ifndef sun    
-  //ac t.sa_mask = _sig;
+        if (SDL_VERSIONNUM(v->major, v->minor, v->patch)
+          < SDL_VERSIONNUM(1, 2, 11))
+        {
+            snd_musicdevice = SNDDEVICE_NONE;
+        }
+    }
+#endif
 #endif
-  act.sa_flags = SA_RESTART;
-  
-  sigaction( sig, &act, &oact );
-
-  value.it_interval.tv_sec    = 0;
-  value.it_interval.tv_usec   = duration_of_tick;
-  value.it_value.tv_sec       = 0;
-  value.it_value.tv_usec      = duration_of_tick;
-
-  // Error is -1.
-  res = setitimer( itimer, &value, &ovalue );
-
-  // Debug.
-  if ( res == -1 )
-    fprintf( stderr, "I_SoundSetTimer: interrupt n.a.\n");
-  
-  return res;
 }
 
-
-// Remove the interrupt. Set duration to zero.
-void I_SoundDelTimer()
-{
-  // Debug.
-  if ( I_SoundSetTimer( 0 ) == -1)
-    fprintf( stderr, "I_SoundDelTimer: failed to remove interrupt. Doh!\n");
-}
index bbfabac659aaa0f2b7c80633d33e05c5d78897b2..e429e960f491258b010008218901d3cbdcc7fa00 100644 (file)
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
-//     System interface, sound.
+//     The not so system specific sound interface.
 //
-//-----------------------------------------------------------------------------
+
 
 #ifndef __I_SOUND__
 #define __I_SOUND__
 
-#include "doomdef.h"
+#include "doomtype.h"
 
-// UNIX hack, to be removed.
-#ifdef SNDSERV
-#include <stdio.h>
-extern FILE* sndserver;
-extern char* sndserver_filename;
-#endif
 
-#include "doomstat.h"
-#include "sounds.h"
+//
+// SoundFX struct.
+//
+typedef struct sfxinfo_struct  sfxinfo_t;
 
+struct sfxinfo_struct
+{
+    // tag name, used for hexen.
+    char *tagname;
+    
+    // lump name.  If we are running with use_sfx_prefix=true, a
+    // 'DS' (or 'DP' for PC speaker sounds) is prepended to this.
 
+    char name[9];
 
-// Init at program start...
-void I_InitSound();
+    // Sfx priority
+    int priority;
 
-// ... update sound buffer and audio device at runtime...
-void I_UpdateSound(void);
-void I_SubmitSound(void);
+    // referenced sound if a link
+    sfxinfo_t *link;
 
-// ... shut down and relase at program termination.
-void I_ShutdownSound(void);
+    // pitch if a link
+    int pitch;
 
+    // volume if a link
+    int volume;
+
+    // this is checked every second to see if sound
+    // can be thrown out (if 0, then decrement, if -1,
+    // then throw out, if > 0, then it is in use)
+    int usefulness;
+
+    // lump number of sfx
+    int lumpnum;               
+
+    // Maximum number of channels that the sound can be played on 
+    // (Heretic)
+    int numchannels;
+
+    // data used by the low level code
+    void *driver_data;
+};
 
 //
-//  SFX I/O
+// MusicInfo struct.
 //
+typedef struct
+{
+    // up to 6-character name
+    char *name;
 
-// Initialize channels?
-void I_SetChannels();
+    // lump number of music
+    int lumpnum;
+    
+    // music data
+    void *data;
 
-// Get raw data lump index for sound descriptor.
-int I_GetSfxLumpNum (sfxinfo_t* sfxinfo );
+    // music handle once registered
+    void *handle;
+    
+} musicinfo_t;
 
+typedef enum 
+{
+    SNDDEVICE_NONE = 0,
+    SNDDEVICE_PCSPEAKER = 1,
+    SNDDEVICE_ADLIB = 2,
+    SNDDEVICE_SB = 3,
+    SNDDEVICE_PAS = 4,
+    SNDDEVICE_GUS = 5,
+    SNDDEVICE_WAVEBLASTER = 6,
+    SNDDEVICE_SOUNDCANVAS = 7,
+    SNDDEVICE_GENMIDI = 8,
+    SNDDEVICE_AWE32 = 9,
+    SNDDEVICE_CD = 10,
+} snddevice_t;
 
-// Starts a sound in a particular sound channel.
-int
-I_StartSound
-( int          id,
-  int          vol,
-  int          sep,
-  int          pitch,
-  int          priority );
+// Interface for sound modules
 
+typedef struct
+{
+    // List of sound devices that this sound module is used for.
 
-// Stops a sound channel.
-void I_StopSound(int handle);
+    snddevice_t *sound_devices;
+    int num_sound_devices;
 
-// Called by S_*() functions
-//  to see if a channel is still playing.
-// Returns 0 if no longer playing, 1 if playing.
-int I_SoundIsPlaying(int handle);
+    // Initialise sound module
+    // Returns true if successfully initialised
 
-// Updates the volume, separation,
-//  and pitch of a sound channel.
-void
-I_UpdateSoundParams
-( int          handle,
-  int          vol,
-  int          sep,
-  int          pitch );
+    boolean (*Init)(boolean use_sfx_prefix);
 
+    // Shutdown sound module
+
+    void (*Shutdown)(void);
+
+    // Returns the lump index of the given sound.
+
+    int (*GetSfxLumpNum)(sfxinfo_t *sfxinfo);
+
+    // Called periodically to update the subsystem.
+
+    void (*Update)(void);
+
+    // Update the sound settings on the given channel.
+
+    void (*UpdateSoundParams)(int channel, int vol, int sep);
+
+    // Start a sound on a given channel.  Returns the channel id
+    // or -1 on failure.
+
+    int (*StartSound)(sfxinfo_t *sfxinfo, int channel, int vol, int sep);
+
+    // Stop the sound playing on the given channel.
+
+    void (*StopSound)(int channel);
+
+    // Query if a sound is playing on the given channel
+
+    boolean (*SoundIsPlaying)(int channel);
+
+    // Called on startup to precache sound effects (if necessary)
+
+    void (*CacheSounds)(sfxinfo_t *sounds, int num_sounds);
+
+} sound_module_t;
+
+void I_InitSound(boolean use_sfx_prefix);
+void I_ShutdownSound(void);
+int I_GetSfxLumpNum(sfxinfo_t *sfxinfo);
+void I_UpdateSound(void);
+void I_UpdateSoundParams(int channel, int vol, int sep);
+int I_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep);
+void I_StopSound(int channel);
+boolean I_SoundIsPlaying(int channel);
+void I_PrecacheSounds(sfxinfo_t *sounds, int num_sounds);
+
+// Interface for music modules
+
+typedef struct
+{
+    // List of sound devices that this music module is used for.
+
+    snddevice_t *sound_devices;
+    int num_sound_devices;
+
+    // Initialise the music subsystem
+
+    boolean (*Init)(void);
+
+    // Shutdown the music subsystem
+
+    void (*Shutdown)(void);
+
+    // Set music volume - range 0-127
+
+    void (*SetMusicVolume)(int volume);
+
+    // Pause music
+
+    void (*PauseMusic)(void);
+
+    // Un-pause music
+
+    void (*ResumeMusic)(void);
+
+    // Register a song handle from data
+    // Returns a handle that can be used to play the song
+
+    void *(*RegisterSong)(void *data, int len);
+
+    // Un-register (free) song data
+
+    void (*UnRegisterSong)(void *handle);
+
+    // Play the song
+
+    void (*PlaySong)(void *handle, boolean looping);
+
+    // Stop playing the current song.
+
+    void (*StopSong)(void);
+
+    // Query if music is playing.
+
+    boolean (*MusicIsPlaying)(void);
+
+    // Invoked periodically to poll.
+
+    void (*Poll)(void);
+} music_module_t;
 
-//
-//  MUSIC I/O
-//
 void I_InitMusic(void);
 void I_ShutdownMusic(void);
-// Volume.
 void I_SetMusicVolume(int volume);
-// PAUSE game handling.
-void I_PauseSong(int handle);
-void I_ResumeSong(int handle);
-// Registers a song handle to song data.
-int I_RegisterSong(void *data);
-// Called by anything that wishes to start music.
-//  plays a song, and when the song is done,
-//  starts playing it again in an endless loop.
-// Horrible thing to do, considering.
-void
-I_PlaySong
-( int          handle,
-  int          looping );
-// Stops a song over 3 seconds.
-void I_StopSong(int handle);
-// See above (register), then think backwards
-void I_UnRegisterSong(int handle);
-
-
+void I_PauseSong(void);
+void I_ResumeSong(void);
+void *I_RegisterSong(void *data, int len);
+void I_UnRegisterSong(void *handle);
+void I_PlaySong(void *handle, boolean looping);
+void I_StopSong(void);
+boolean I_MusicIsPlaying(void);
+
+extern int snd_sfxdevice;
+extern int snd_musicdevice;
+extern int snd_samplerate;
+extern int snd_cachesize;
+extern int snd_maxslicetime_ms;
+extern char *snd_musiccmd;
+
+void I_BindSoundVariables(void);
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
+
diff --git a/frosted-doom/i_swap.h b/frosted-doom/i_swap.h
new file mode 100644 (file)
index 0000000..d1fd754
--- /dev/null
@@ -0,0 +1,54 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//     Endianess handling, swapping 16bit and 32bit.
+//
+
+
+#ifndef __I_SWAP__
+#define __I_SWAP__
+
+#ifdef ORIGCODE
+#include "SDL_endian.h"
+
+// Endianess handling.
+// WAD files are stored little endian.
+
+// Just use SDL's endianness swapping functions.
+
+// These are deliberately cast to signed values; this is the behaviour
+// of the macros in the original source and some code relies on it.
+
+#define SHORT(x)  ((signed short) SDL_SwapLE16(x))
+#define LONG(x)   ((signed int) SDL_SwapLE32(x))
+
+// Defines for checking the endianness of the system.
+
+#if SDL_BYTEORDER == SYS_LIL_ENDIAN
+#define SYS_LITTLE_ENDIAN
+#elif SDL_BYTEORDER == SYS_BIG_ENDIAN
+#define SYS_BIG_ENDIAN
+#endif
+
+#else
+       
+#define SHORT(x)  ((signed short) (x))
+#define LONG(x)   ((signed int) (x))
+
+#define SYS_LITTLE_ENDIAN
+
+#endif
+#endif
+
index cb16aa34ab46b74fc32ec7c708a948bb4b070dd9..5d000910f25f17d5c90eebdf0465d0446bd20353 100644 (file)
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $";
+
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
 #include <stdarg.h>
-#include <sys/time.h>
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#else
 #include <unistd.h>
+#endif
 
-#include "doomdef.h"
+#ifdef ORIGCODE
+#include "SDL.h"
+#endif
+
+#include "config.h"
+
+#include "deh_str.h"
+#include "doomtype.h"
+#include "m_argv.h"
+#include "m_config.h"
 #include "m_misc.h"
-#include "i_video.h"
+#include "i_joystick.h"
 #include "i_sound.h"
+#include "i_timer.h"
+#include "i_video.h"
 
-#include "d_net.h"
-#include "g_game.h"
+#include "i_system.h"
 
-#ifdef __GNUG__
-#pragma implementation "i_system.h"
+#include "w_wad.h"
+#include "z_zone.h"
+
+#ifdef __MACOSX__
+#include <CoreFoundation/CFUserNotification.h>
 #endif
-#include "i_system.h"
 
+#define DEFAULT_RAM 6 /* MiB */
+#define MIN_RAM     6  /* MiB */
 
 
+typedef struct atexit_listentry_s atexit_listentry_t;
 
-int    mb_used = 6;
+struct atexit_listentry_s
+{
+    atexit_func_t func;
+    boolean run_on_error;
+    atexit_listentry_t *next;
+};
 
+static atexit_listentry_t *exit_funcs = NULL;
 
-void
-I_Tactile
-( int  on,
-  int  off,
-  int  total )
+void I_AtExit(atexit_func_t func, boolean run_on_error)
 {
-  // UNUSED.
-  on = off = total = 0;
+    atexit_listentry_t *entry;
+
+    entry = malloc(sizeof(*entry));
+
+    entry->func = func;
+    entry->run_on_error = run_on_error;
+    entry->next = exit_funcs;
+    exit_funcs = entry;
 }
 
-ticcmd_t       emptycmd;
-ticcmd_t*      I_BaseTiccmd(void)
+// Tactile feedback function, probably used for the Logitech Cyberman
+
+void I_Tactile(int on, int off, int total)
 {
-    return &emptycmd;
 }
 
+// Zone memory auto-allocation function that allocates the zone size
+// by trying progressively smaller zone sizes until one is found that
+// works.
 
-int  I_GetHeapSize (void)
+static byte *AutoAllocMemory(int *size, int default_ram, int min_ram)
 {
-    return mb_used*1024*1024;
+    byte *zonemem;
+
+    // Allocate the zone memory.  This loop tries progressively smaller
+    // zone sizes until a size is found that can be allocated.
+    // If we used the -mb command line parameter, only the parameter
+    // provided is accepted.
+
+    zonemem = NULL;
+
+    while (zonemem == NULL)
+    {
+        // We need a reasonable minimum amount of RAM to start.
+
+        if (default_ram < min_ram)
+        {
+            I_Error("Unable to allocate %i MiB of RAM for zone", default_ram);
+        }
+
+        // Try to allocate the zone memory.
+
+        *size = default_ram * 1024 * 1024;
+
+        zonemem = malloc(*size);
+
+        // Failed to allocate?  Reduce zone size until we reach a size
+        // that is acceptable.
+
+        if (zonemem == NULL)
+        {
+            default_ram -= 1;
+        }
+    }
+
+    return zonemem;
 }
 
-byte* I_ZoneBase (int* size)
+byte *I_ZoneBase (int *size)
 {
-    *size = mb_used*1024*1024;
-    return (byte *) malloc (*size);
+    byte *zonemem;
+    int min_ram, default_ram;
+    int p;
+
+    //!
+    // @arg <mb>
+    //
+    // Specify the heap size, in MiB (default 16).
+    //
+
+    p = M_CheckParmWithArgs("-mb", 1);
+
+    if (p > 0)
+    {
+        default_ram = atoi(myargv[p+1]);
+        min_ram = default_ram;
+    }
+    else
+    {
+        default_ram = DEFAULT_RAM;
+        min_ram = MIN_RAM;
+    }
+
+    zonemem = AutoAllocMemory(size, default_ram, min_ram);
+
+    printf("zone memory: %p, %x allocated for zone\n", 
+           zonemem, *size);
+
+    return zonemem;
 }
 
+void I_PrintBanner(char *msg)
+{
+    int i;
+    int spaces = 35 - (strlen(msg) / 2);
+
+    for (i=0; i<spaces; ++i)
+        putchar(' ');
 
+    puts(msg);
+}
 
-//
-// I_GetTime
-// returns time in 1/70th second tics
-//
-int  I_GetTime (void)
+void I_PrintDivider(void)
 {
-    struct timeval     tp;
-    struct timezone    tzp;
-    int                        newtics;
-    static int         basetime=0;
-  
-    gettimeofday(&tp, &tzp);
-    if (!basetime)
-       basetime = tp.tv_sec;
-    newtics = (tp.tv_sec-basetime)*TICRATE + tp.tv_usec*TICRATE/1000000;
-    return newtics;
+    int i;
+
+    for (i=0; i<75; ++i)
+    {
+        putchar('=');
+    }
+
+    putchar('\n');
 }
 
+void I_PrintStartupBanner(char *gamedescription)
+{
+    I_PrintDivider();
+    I_PrintBanner(gamedescription);
+    I_PrintDivider();
+    
+    printf(
+    " " PACKAGE_NAME " is free software, covered by the GNU General Public\n"
+    " License.  There is NO warranty; not even for MERCHANTABILITY or FITNESS\n"
+    " FOR A PARTICULAR PURPOSE. You are welcome to change and distribute\n"
+    " copies under certain conditions. See the source for more information.\n");
 
+    I_PrintDivider();
+}
+
+// 
+// I_ConsoleStdout
+//
+// Returns true if stdout is a real console, false if it is a file
+//
+
+boolean I_ConsoleStdout(void)
+{
+#ifdef _WIN32
+    // SDL "helpfully" always redirects stdout to a file.
+    return 0;
+#else
+#if ORIGCODE
+    return isatty(fileno(stdout));
+#else
+       return 0;
+#endif
+#endif
+}
 
 //
 // I_Init
 //
+/*
 void I_Init (void)
 {
-    I_InitSound();
-    //  I_InitGraphics();
+    I_CheckIsScreensaver();
+    I_InitTimer();
+    I_InitJoystick();
+}
+void I_BindVariables(void)
+{
+    I_BindVideoVariables();
+    I_BindJoystickVariables();
+    I_BindSoundVariables();
 }
+*/
 
 //
 // I_Quit
 //
+
 void I_Quit (void)
 {
-    D_QuitNetGame ();
-    I_ShutdownSound();
-    I_ShutdownMusic();
-    M_SaveDefaults ();
-    I_ShutdownGraphics();
-    exit(0);
-}
+    atexit_listentry_t *entry;
 
-void I_WaitVBL(int count)
-{
-#ifdef SGI
-    sginap(1);                                           
-#else
-#ifdef SUN
-    sleep(0);
-#else
-    usleep (count * (1000000/70) );                                
-#endif
+    // Run through all exit functions
+    entry = exit_funcs; 
+
+    while (entry != NULL)
+    {
+        entry->func();
+        entry = entry->next;
+    }
+
+#if ORIGCODE
+    SDL_Quit();
+
+    exit(0);
 #endif
 }
 
-void I_BeginRead(void)
+#if !defined(_WIN32) && !defined(__MACOSX__)
+#define ZENITY_BINARY "/usr/bin/zenity"
+
+// returns non-zero if zenity is available
+
+static int ZenityAvailable(void)
 {
+    return system(ZENITY_BINARY " --help >/dev/null 2>&1") == 0;
 }
 
-void I_EndRead(void)
+// Escape special characters in the given string so that they can be
+// safely enclosed in shell quotes.
+
+static char *EscapeShellString(char *string)
 {
+    char *result;
+    char *r, *s;
+
+    // In the worst case, every character might be escaped.
+    result = malloc(strlen(string) * 2 + 3);
+    r = result;
+
+    // Enclosing quotes.
+    *r = '"';
+    ++r;
+
+    for (s = string; *s != '\0'; ++s)
+    {
+        // From the bash manual:
+        //
+        //  "Enclosing characters in double quotes preserves the literal
+        //   value of all characters within the quotes, with the exception
+        //   of $, `, \, and, when history expansion is enabled, !."
+        //
+        // Therefore, escape these characters by prefixing with a backslash.
+
+        if (strchr("$`\\!", *s) != NULL)
+        {
+            *r = '\\';
+            ++r;
+        }
+
+        *r = *s;
+        ++r;
+    }
+
+    // Enclosing quotes.
+    *r = '"';
+    ++r;
+    *r = '\0';
+
+    return result;
 }
 
-byte*  I_AllocLow(int length)
+// Open a native error box with a message using zenity
+
+static int ZenityErrorBox(char *message)
 {
-    byte*      mem;
-        
-    mem = (byte *)malloc (length);
-    memset (mem,0,length);
-    return mem;
+    int result;
+    char *escaped_message;
+    char *errorboxpath;
+    static size_t errorboxpath_size;
+
+    if (!ZenityAvailable())
+    {
+        return 0;
+    }
+
+    escaped_message = EscapeShellString(message);
+
+    errorboxpath_size = strlen(ZENITY_BINARY) + strlen(escaped_message) + 19;
+    errorboxpath = malloc(errorboxpath_size);
+    M_snprintf(errorboxpath, errorboxpath_size, "%s --error --text=%s",
+               ZENITY_BINARY, escaped_message);
+
+    result = system(errorboxpath);
+
+    free(errorboxpath);
+    free(escaped_message);
+
+    return result;
 }
 
+#endif /* !defined(_WIN32) && !defined(__MACOSX__) */
+
 
 //
 // I_Error
 //
-extern boolean demorecording;
+
+static boolean already_quitting = false;
 
 void I_Error (char *error, ...)
 {
-    va_list    argptr;
+    char msgbuf[512];
+    va_list argptr;
+    atexit_listentry_t *entry;
+    boolean exit_gui_popup;
+
+    if (already_quitting)
+    {
+        fprintf(stderr, "Warning: recursive call to I_Error detected.\n");
+#if ORIGCODE
+        exit(-1);
+#endif
+    }
+    else
+    {
+        already_quitting = true;
+    }
 
     // Message first.
-    va_start (argptr,error);
-    fprintf (stderr, "Error: ");
-    vfprintf (stderr,error,argptr);
-    fprintf (stderr, "\n");
-    va_end (argptr);
-
-    fflush( stderr );
+    va_start(argptr, error);
+    //fprintf(stderr, "\nError: ");
+    vfprintf(stderr, error, argptr);
+    fprintf(stderr, "\n\n");
+    va_end(argptr);
+    fflush(stderr);
+
+    // Write a copy of the message into buffer.
+    va_start(argptr, error);
+    memset(msgbuf, 0, sizeof(msgbuf));
+    M_vsnprintf(msgbuf, sizeof(msgbuf), error, argptr);
+    va_end(argptr);
 
     // Shutdown. Here might be other errors.
-    if (demorecording)
-       G_CheckDemoStatus();
 
-    D_QuitNetGame ();
-    I_ShutdownGraphics();
-    
+    entry = exit_funcs;
+
+    while (entry != NULL)
+    {
+        if (entry->run_on_error)
+        {
+            entry->func();
+        }
+
+        entry = entry->next;
+    }
+
+    exit_gui_popup = !M_ParmExists("-nogui");
+
+    // Pop up a GUI dialog box to show the error message, if the
+    // game was not run from the console (and the user will
+    // therefore be unable to otherwise see the message).
+    if (exit_gui_popup && !I_ConsoleStdout())
+#ifdef _WIN32
+    {
+        wchar_t wmsgbuf[512];
+
+        MultiByteToWideChar(CP_ACP, 0,
+                            msgbuf, strlen(msgbuf) + 1,
+                            wmsgbuf, sizeof(wmsgbuf));
+
+        MessageBoxW(NULL, wmsgbuf, L"", MB_OK);
+    }
+#elif defined(__MACOSX__)
+    {
+        CFStringRef message;
+       int i;
+
+       // The CoreFoundation message box wraps text lines, so replace
+       // newline characters with spaces so that multiline messages
+       // are continuous.
+
+       for (i = 0; msgbuf[i] != '\0'; ++i)
+        {
+            if (msgbuf[i] == '\n')
+            {
+                msgbuf[i] = ' ';
+            }
+        }
+
+        message = CFStringCreateWithCString(NULL, msgbuf,
+                                            kCFStringEncodingUTF8);
+
+        CFUserNotificationDisplayNotice(0,
+                                        kCFUserNotificationCautionAlertLevel,
+                                        NULL,
+                                        NULL,
+                                        NULL,
+                                        CFSTR(PACKAGE_STRING),
+                                        message,
+                                        NULL);
+    }
+#else
+    {
+        ZenityErrorBox(msgbuf);
+    }
+#endif
+
+    // abort();
+#if ORIGCODE
+    SDL_Quit();
+
     exit(-1);
+#else
+    while (true)
+    {
+    }
+#endif
 }
+
+//
+// Read Access Violation emulation.
+//
+// From PrBoom+, by entryway.
+//
+
+// C:\>debug
+// -d 0:0
+//
+// DOS 6.22:
+// 0000:0000  (57 92 19 00) F4 06 70 00-(16 00)
+// DOS 7.1:
+// 0000:0000  (9E 0F C9 00) 65 04 70 00-(16 00)
+// Win98:
+// 0000:0000  (9E 0F C9 00) 65 04 70 00-(16 00)
+// DOSBox under XP:
+// 0000:0000  (00 00 00 F1) ?? ?? ?? 00-(07 00)
+
+#define DOS_MEM_DUMP_SIZE 10
+
+static const unsigned char mem_dump_dos622[DOS_MEM_DUMP_SIZE] = {
+  0x57, 0x92, 0x19, 0x00, 0xF4, 0x06, 0x70, 0x00, 0x16, 0x00};
+static const unsigned char mem_dump_win98[DOS_MEM_DUMP_SIZE] = {
+  0x9E, 0x0F, 0xC9, 0x00, 0x65, 0x04, 0x70, 0x00, 0x16, 0x00};
+static const unsigned char mem_dump_dosbox[DOS_MEM_DUMP_SIZE] = {
+  0x00, 0x00, 0x00, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00};
+static unsigned char mem_dump_custom[DOS_MEM_DUMP_SIZE];
+
+static const unsigned char *dos_mem_dump = mem_dump_dos622;
+
+boolean I_GetMemoryValue(unsigned int offset, void *value, int size)
+{
+    static boolean firsttime = true;
+
+    if (firsttime)
+    {
+        int p, i, val;
+
+        firsttime = false;
+        i = 0;
+
+        //!
+        // @category compat
+        // @arg <version>
+        //
+        // Specify DOS version to emulate for NULL pointer dereference
+        // emulation.  Supported versions are: dos622, dos71, dosbox.
+        // The default is to emulate DOS 7.1 (Windows 98).
+        //
+
+        p = M_CheckParmWithArgs("-setmem", 1);
+
+        if (p > 0)
+        {
+            if (!strcasecmp(myargv[p + 1], "dos622"))
+            {
+                dos_mem_dump = mem_dump_dos622;
+            }
+            if (!strcasecmp(myargv[p + 1], "dos71"))
+            {
+                dos_mem_dump = mem_dump_win98;
+            }
+            else if (!strcasecmp(myargv[p + 1], "dosbox"))
+            {
+                dos_mem_dump = mem_dump_dosbox;
+            }
+            else
+            {
+                for (i = 0; i < DOS_MEM_DUMP_SIZE; ++i)
+                {
+                    ++p;
+
+                    if (p >= myargc || myargv[p][0] == '-')
+                    {
+                        break;
+                    }
+
+                    M_StrToInt(myargv[p], &val);
+                    mem_dump_custom[i++] = (unsigned char) val;
+                }
+
+                dos_mem_dump = mem_dump_custom;
+            }
+        }
+    }
+
+    switch (size)
+    {
+    case 1:
+        *((unsigned char *) value) = dos_mem_dump[offset];
+        return true;
+    case 2:
+        *((unsigned short *) value) = dos_mem_dump[offset]
+                                    | (dos_mem_dump[offset + 1] << 8);
+        return true;
+    case 4:
+        *((unsigned int *) value) = dos_mem_dump[offset]
+                                  | (dos_mem_dump[offset + 1] << 8)
+                                  | (dos_mem_dump[offset + 2] << 16)
+                                  | (dos_mem_dump[offset + 3] << 24);
+        return true;
+    }
+
+    return false;
+}
+
index 89541407146007e4cb370639019ab96dfbfcde28..b65daff00db292aa643b86efbc675335c6f3c67a 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     System specific interface stuff.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __I_SYSTEM__
 #include "d_ticcmd.h"
 #include "d_event.h"
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
+typedef void (*atexit_func_t)(void);
 
 // Called by DoomMain.
 void I_Init (void);
@@ -39,29 +34,8 @@ void I_Init (void);
 // for the zone management.
 byte*  I_ZoneBase (int *size);
 
+boolean I_ConsoleStdout(void);
 
-// Called by D_DoomLoop,
-// returns current time in tics.
-int I_GetTime (void);
-
-
-//
-// Called by D_DoomLoop,
-// called before processing any tics in a frame
-// (just after displaying a frame).
-// Time consuming syncronous operations
-// are performed here (joystick reading).
-// Can call D_PostEvent.
-//
-void I_StartFrame (void);
-
-
-//
-// Called by D_DoomLoop,
-// called before processing each tic in a frame.
-// Quick syncronous operations are performed here.
-// Can call D_PostEvent.
-void I_StartTic (void);
 
 // Asynchronous interrupt functions should maintain private queues
 // that are read by the synchronous functions
@@ -78,20 +52,33 @@ ticcmd_t* I_BaseTiccmd (void);
 // Clean exit, displays sell blurb.
 void I_Quit (void);
 
-
-// Allocates from low memory under dos,
-// just mallocs under unix
-byte* I_AllocLow (int length);
+void I_Error (char *error, ...);
 
 void I_Tactile (int on, int off, int total);
 
+boolean I_GetMemoryValue(unsigned int offset, void *value, int size);
 
-void I_Error (char *error, ...);
+// Schedule a function to be called when the program exits.
+// If run_if_error is true, the function is called if the exit
+// is due to an error (I_Error)
 
+void I_AtExit(atexit_func_t func, boolean run_if_error);
+
+// Add all system-specific config file variable bindings.
+
+void I_BindVariables(void);
+
+// Print startup banner copyright message.
+
+void I_PrintStartupBanner(char *gamedescription);
+
+// Print a centered text banner displaying the given string.
+
+void I_PrintBanner(char *text);
+
+// Print a dividing line for startup banners.
+
+void I_PrintDivider(void);
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
+
diff --git a/frosted-doom/i_timer.c b/frosted-doom/i_timer.c
new file mode 100644 (file)
index 0000000..081b38e
--- /dev/null
@@ -0,0 +1,93 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//      Timer functions.
+//
+
+#include "i_timer.h"
+#include "doomtype.h"
+
+#include <stdarg.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+//
+// I_GetTime
+// returns time in 1/35th second tics
+//
+
+static uint32_t basetime = 0;
+
+int I_GetTicks(void)
+{
+    struct timeval  tp;
+    struct timezone tzp;
+  
+    gettimeofday(&tp, &tzp);
+    return (tp.tv_sec * 1000) + (tp.tv_usec / 1000); /* return milliseconds */
+}
+
+int  I_GetTime (void)
+{
+    uint32_t ticks;
+
+    ticks = I_GetTicks();
+
+    if (basetime == 0)
+        basetime = ticks;
+
+    ticks -= basetime;
+
+    return (ticks * TICRATE) / 1000;    
+}
+
+
+//
+// Same as I_GetTime, but returns time in milliseconds
+//
+
+int I_GetTimeMS(void)
+{
+    uint32_t ticks;
+
+    ticks = I_GetTicks();
+
+    if (basetime == 0)
+        basetime = ticks;
+
+    return ticks - basetime;
+}
+
+// Sleep for a specified number of ms
+
+void I_Sleep(int ms)
+{
+    //SDL_Delay(ms);
+    usleep (ms * 1000);    
+}
+
+void I_WaitVBL(int count)
+{
+    //I_Sleep((count * 1000) / 70);
+}
+
+
+void I_InitTimer(void)
+{
+    // initialize timer
+
+    //SDL_Init(SDL_INIT_TIMER);
+}
+
diff --git a/frosted-doom/i_timer.h b/frosted-doom/i_timer.h
new file mode 100644 (file)
index 0000000..9b3dbb8
--- /dev/null
@@ -0,0 +1,42 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//      System-specific timer interface
+//
+
+
+#ifndef __I_TIMER__
+#define __I_TIMER__
+
+#define TICRATE 35
+
+// Called by D_DoomLoop,
+// returns current time in tics.
+int I_GetTime (void);
+
+// returns current time in ms
+int I_GetTimeMS (void);
+
+// Pause for a specified number of ms
+void I_Sleep(int ms);
+
+// Initialize timer
+void I_InitTimer(void);
+
+// Wait for vertical retrace or pause a bit.
+void I_WaitVBL(int count);
+
+#endif
+
index 31af77b6eb335d00a0379afbd07c4f1c957a1a43..def458be9917284787177731b556e3b6bf15e097 100644 (file)
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
-//     DOOM graphics stuff for X11, UNIX.
+//     DOOM graphics stuff for SDL.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: i_x.c,v 1.6 1997/02/03 22:45:10 b1 Exp $";
 
+#include "SDL/SDL.h"
 #include <stdlib.h>
-#include <unistd.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/keysym.h>
-
-#include <X11/extensions/XShm.h>
-// Had to dig up XShm.c for this one.
-// It is in the libXext, but not in the XFree86 headers.
-#ifdef LINUX
-int XShmGetEventBase( Display* dpy ); // problems with g++?
-#endif
+#include <ctype.h>
+#include <math.h>
+#include <string.h>
 
-#include <stdarg.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
 
-#include <netinet/in.h>
-#include <errno.h>
-#include <signal.h>
+#include "icon.c"
 
-#include "doomstat.h"
+#include "config.h"
+#include "deh_str.h"
+#include "doomtype.h"
+#include "doomkeys.h"
+#include "i_joystick.h"
 #include "i_system.h"
-#include "v_video.h"
+#include "i_swap.h"
+#include "i_timer.h"
+#include "i_video.h"
+#include "i_scale.h"
 #include "m_argv.h"
-#include "d_main.h"
+#include "m_config.h"
+#include "m_misc.h"
+#include "tables.h"
+#include "v_video.h"
+#include "w_wad.h"
+#include "z_zone.h"
 
-#include "doomdef.h"
+// Lookup table for mapping ASCII characters to their equivalent when
+// shift is pressed on an American layout keyboard:
 
-#define POINTER_WARP_COUNTDOWN 1
+static const char shiftxform[] =
+{
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+    11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+    21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+    31, ' ', '!', '"', '#', '$', '%', '&',
+    '"', // shift-'
+    '(', ')', '*', '+',
+    '<', // shift-,
+    '_', // shift--
+    '>', // shift-.
+    '?', // shift-/
+    ')', // shift-0
+    '!', // shift-1
+    '@', // shift-2
+    '#', // shift-3
+    '$', // shift-4
+    '%', // shift-5
+    '^', // shift-6
+    '&', // shift-7
+    '*', // shift-8
+    '(', // shift-9
+    ':',
+    ':', // shift-;
+    '<',
+    '+', // shift-=
+    '>', '?', '@',
+    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
+    'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+    '[', // shift-[
+    '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK
+    ']', // shift-]
+    '"', '_',
+    '\'', // shift-`
+    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
+    'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+    '{', '|', '}', '~', 127
+};
 
-Display*       X_display=0;
-Window         X_mainWindow;
-Colormap       X_cmap;
-Visual*                X_visual;
-GC             X_gc;
-XEvent         X_event;
-int            X_screen;
-XVisualInfo    X_visualinfo;
-XImage*                image;
-int            X_width;
-int            X_height;
 
-// MIT SHared Memory extension.
-boolean                doShm;
+#define LOADING_DISK_W 16
+#define LOADING_DISK_H 16
 
-XShmSegmentInfo        X_shminfo;
-int            X_shmeventtype;
+// Non aspect ratio-corrected modes (direct multiples of 320x200)
 
-// Fake mouse handling.
-// This cannot work properly w/o DGA.
-// Needs an invisible mouse cursor at least.
-boolean                grabMouse;
-int            doPointerWarp = POINTER_WARP_COUNTDOWN;
+static screen_mode_t *screen_modes[] = {
+    &mode_scale_1x,
+    &mode_scale_2x,
+    &mode_scale_3x,
+    &mode_scale_4x,
+    &mode_scale_5x,
+};
 
-// Blocky mode,
-// replace each 320x200 pixel with multiply*multiply pixels.
-// According to Dave Taylor, it still is a bonehead thing
-// to use ....
-static int     multiply=1;
+// Aspect ratio corrected modes (4:3 ratio)
 
+static screen_mode_t *screen_modes_corrected[] = {
 
-//
-//  Translates the key currently in X_event
-//
+    // Vertically stretched modes (320x200 -> 320x240 and multiples)
 
-int xlatekey(void)
-{
+    &mode_stretch_1x,
+    &mode_stretch_2x,
+    &mode_stretch_3x,
+    &mode_stretch_4x,
+    &mode_stretch_5x,
 
-    int rc;
-
-    switch(rc = XKeycodeToKeysym(X_display, X_event.xkey.keycode, 0))
-    {
-      case XK_Left:    rc = KEY_LEFTARROW;     break;
-      case XK_Right:   rc = KEY_RIGHTARROW;    break;
-      case XK_Down:    rc = KEY_DOWNARROW;     break;
-      case XK_Up:      rc = KEY_UPARROW;       break;
-      case XK_Escape:  rc = KEY_ESCAPE;        break;
-      case XK_Return:  rc = KEY_ENTER;         break;
-      case XK_Tab:     rc = KEY_TAB;           break;
-      case XK_F1:      rc = KEY_F1;            break;
-      case XK_F2:      rc = KEY_F2;            break;
-      case XK_F3:      rc = KEY_F3;            break;
-      case XK_F4:      rc = KEY_F4;            break;
-      case XK_F5:      rc = KEY_F5;            break;
-      case XK_F6:      rc = KEY_F6;            break;
-      case XK_F7:      rc = KEY_F7;            break;
-      case XK_F8:      rc = KEY_F8;            break;
-      case XK_F9:      rc = KEY_F9;            break;
-      case XK_F10:     rc = KEY_F10;           break;
-      case XK_F11:     rc = KEY_F11;           break;
-      case XK_F12:     rc = KEY_F12;           break;
-       
-      case XK_BackSpace:
-      case XK_Delete:  rc = KEY_BACKSPACE;     break;
+    // Horizontally squashed modes (320x200 -> 256x200 and multiples)
 
-      case XK_Pause:   rc = KEY_PAUSE;         break;
+    &mode_squash_1x,
+    &mode_squash_2x,
+    &mode_squash_3x,
+    &mode_squash_4x,
+    &mode_squash_5x,
+};
 
-      case XK_KP_Equal:
-      case XK_equal:   rc = KEY_EQUALS;        break;
+// SDL video driver name
 
-      case XK_KP_Subtract:
-      case XK_minus:   rc = KEY_MINUS;         break;
+char *video_driver = "";
 
-      case XK_Shift_L:
-      case XK_Shift_R:
-       rc = KEY_RSHIFT;
-       break;
-       
-      case XK_Control_L:
-      case XK_Control_R:
-       rc = KEY_RCTRL;
-       break;
-       
-      case XK_Alt_L:
-      case XK_Meta_L:
-      case XK_Alt_R:
-      case XK_Meta_R:
-       rc = KEY_RALT;
-       break;
-       
-      default:
-       if (rc >= XK_space && rc <= XK_asciitilde)
-           rc = rc - XK_space + ' ';
-       if (rc >= 'A' && rc <= 'Z')
-           rc = rc - 'A' + 'a';
-       break;
-    }
+// Window position:
 
-    return rc;
+static char *window_position = "";
 
-}
+// SDL surface for the screen.
 
-void I_ShutdownGraphics(void)
-{
-  // Detach from X server
-  if (!XShmDetach(X_display, &X_shminfo))
-           I_Error("XShmDetach() failed in I_ShutdownGraphics()");
+static SDL_Surface *screen;
 
-  // Release shared memory.
-  shmdt(X_shminfo.shmaddr);
-  shmctl(X_shminfo.shmid, IPC_RMID, 0);
+// Window title
 
-  // Paranoia.
-  image->data = NULL;
-}
+static char *window_title = "";
 
+// Intermediate 8-bit buffer that we draw to instead of 'screen'.
+// This is used when we are rendering in 32-bit screen mode.
+// When in a real 8-bit screen mode, screenbuffer == screen.
 
+static SDL_Surface *screenbuffer = NULL;
 
-//
-// I_StartFrame
-//
-void I_StartFrame (void)
-{
-    // er?
+// palette
 
-}
+static SDL_Color palette[256];
+static boolean palette_to_set;
 
-static int     lastmousex = 0;
-static int     lastmousey = 0;
-boolean                mousemoved = false;
-boolean                shmFinished;
+// display has been set up?
 
-void I_GetEvent(void)
-{
+static boolean initialized = false;
 
-    event_t event;
+// disable mouse?
 
-    // put event-grabbing stuff in here
-    XNextEvent(X_display, &X_event);
-    switch (X_event.type)
-    {
-      case KeyPress:
-       event.type = ev_keydown;
-       event.data1 = xlatekey();
-       D_PostEvent(&event);
-       // fprintf(stderr, "k");
-       break;
-      case KeyRelease:
-       event.type = ev_keyup;
-       event.data1 = xlatekey();
-       D_PostEvent(&event);
-       // fprintf(stderr, "ku");
-       break;
-      case ButtonPress:
-       event.type = ev_mouse;
-       event.data1 =
-           (X_event.xbutton.state & Button1Mask)
-           | (X_event.xbutton.state & Button2Mask ? 2 : 0)
-           | (X_event.xbutton.state & Button3Mask ? 4 : 0)
-           | (X_event.xbutton.button == Button1)
-           | (X_event.xbutton.button == Button2 ? 2 : 0)
-           | (X_event.xbutton.button == Button3 ? 4 : 0);
-       event.data2 = event.data3 = 0;
-       D_PostEvent(&event);
-       // fprintf(stderr, "b");
-       break;
-      case ButtonRelease:
-       event.type = ev_mouse;
-       event.data1 =
-           (X_event.xbutton.state & Button1Mask)
-           | (X_event.xbutton.state & Button2Mask ? 2 : 0)
-           | (X_event.xbutton.state & Button3Mask ? 4 : 0);
-       // suggest parentheses around arithmetic in operand of |
-       event.data1 =
-           event.data1
-           ^ (X_event.xbutton.button == Button1 ? 1 : 0)
-           ^ (X_event.xbutton.button == Button2 ? 2 : 0)
-           ^ (X_event.xbutton.button == Button3 ? 4 : 0);
-       event.data2 = event.data3 = 0;
-       D_PostEvent(&event);
-       // fprintf(stderr, "bu");
-       break;
-      case MotionNotify:
-       event.type = ev_mouse;
-       event.data1 =
-           (X_event.xmotion.state & Button1Mask)
-           | (X_event.xmotion.state & Button2Mask ? 2 : 0)
-           | (X_event.xmotion.state & Button3Mask ? 4 : 0);
-       event.data2 = (X_event.xmotion.x - lastmousex) << 2;
-       event.data3 = (lastmousey - X_event.xmotion.y) << 2;
-
-       if (event.data2 || event.data3)
-       {
-           lastmousex = X_event.xmotion.x;
-           lastmousey = X_event.xmotion.y;
-           if (X_event.xmotion.x != X_width/2 &&
-               X_event.xmotion.y != X_height/2)
-           {
-               D_PostEvent(&event);
-               // fprintf(stderr, "m");
-               mousemoved = false;
-           } else
-           {
-               mousemoved = true;
-           }
-       }
-       break;
-       
-      case Expose:
-      case ConfigureNotify:
-       break;
-       
-      default:
-       if (doShm && X_event.type == X_shmeventtype) shmFinished = true;
-       break;
-    }
+static boolean nomouse = false;
+int usemouse = 1;
 
-}
+// Bit mask of mouse button state.
 
-Cursor
-createnullcursor
-( Display*     display,
-  Window       root )
-{
-    Pixmap cursormask;
-    XGCValues xgc;
-    GC gc;
-    XColor dummycolour;
-    Cursor cursor;
-
-    cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
-    xgc.function = GXclear;
-    gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
-    XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
-    dummycolour.pixel = 0;
-    dummycolour.red = 0;
-    dummycolour.flags = 04;
-    cursor = XCreatePixmapCursor(display, cursormask, cursormask,
-                                &dummycolour,&dummycolour, 0,0);
-    XFreePixmap(display,cursormask);
-    XFreeGC(display,gc);
-    return cursor;
-}
+static unsigned int mouse_button_state = 0;
+
+// Disallow mouse and joystick movement to cause forward/backward
+// motion.  Specified with the '-novert' command line parameter.
+// This is an int to allow saving to config file
+
+int novert = 0;
+
+// Save screenshots in PNG format.
+
+int png_screenshots = 0;
+
+// if true, I_VideoBuffer is screen->pixels
+
+static boolean native_surface;
+
+// Screen width and height, from configuration file.
+
+int screen_width = SCREENWIDTH;
+int screen_height = SCREENHEIGHT;
+
+// Color depth.
+
+int screen_bpp = 0;
+
+// Automatically adjust video settings if the selected mode is 
+// not a valid video mode.
+
+static int autoadjust_video_settings = 1;
+
+// Run in full screen mode?  (int type for config code)
+
+int fullscreen = true;
+
+// Aspect ratio correction mode
+
+int aspect_ratio_correct = true;
+
+// Time to wait for the screen to settle on startup before starting the
+// game (ms)
+
+static int startup_delay = 1000;
+
+// Grab the mouse? (int type for config code)
+
+static int grabmouse = true;
+
+// The screen buffer; this is modified to draw things to the screen
+
+byte *I_VideoBuffer = NULL;
+
+// If true, game is running as a screensaver
+
+boolean screensaver_mode = false;
+
+// Flag indicating whether the screen is currently visible:
+// when the screen isnt visible, don't render the screen
+
+boolean screenvisible;
 
+// If true, we display dots at the bottom of the screen to 
+// indicate FPS.
+
+static boolean display_fps_dots;
+
+// If this is true, the screen is rendered but not blitted to the
+// video buffer.
+
+static boolean noblit;
+
+// Callback function to invoke to determine whether to grab the 
+// mouse pointer.
+
+static grabmouse_callback_t grabmouse_callback = NULL;
+
+// disk image data and background overwritten by the disk to be
+// restored by EndRead
+
+static byte *disk_image = NULL;
+static byte *saved_background;
+static boolean window_focused;
+
+// Empty mouse cursor
+
+static SDL_Cursor *cursors[2];
+
+// The screen mode and scale functions being used
+
+static screen_mode_t *screen_mode;
+
+// Window resize state.
+
+static boolean need_resize = false;
+static unsigned int resize_w, resize_h;
+static unsigned int last_resize_time;
+
+// If true, keyboard mapping is ignored, like in Vanilla Doom.
+// The sensible thing to do is to disable this if you have a non-US
+// keyboard.
+
+int vanilla_keyboard_mapping = true;
+
+// Is the shift key currently down?
+
+static int shiftdown = 0;
+
+// Mouse acceleration
 //
-// I_StartTic
+// This emulates some of the behavior of DOS mouse drivers by increasing
+// the speed when the mouse is moved fast.
 //
-void I_StartTic (void)
+// The mouse input values are input directly to the game, but when
+// the values exceed the value of mouse_threshold, they are multiplied
+// by mouse_acceleration to increase the speed.
+
+float mouse_acceleration = 2.0;
+int mouse_threshold = 10;
+
+// Gamma correction level to use
+
+int usegamma = 0;
+
+static void ApplyWindowResize(unsigned int w, unsigned int h);
+
+static boolean MouseShouldBeGrabbed()
 {
+    // never grab the mouse when in screensaver mode
+   
+    if (screensaver_mode)
+        return false;
 
-    if (!X_display)
-       return;
+    // if the window doesn't have focus, never grab it
 
-    while (XPending(X_display))
-       I_GetEvent();
+    if (!window_focused)
+        return false;
 
-    // Warp the pointer back to the middle of the window
-    //  or it will wander off - that is, the game will
-    //  loose input focus within X11.
-    if (grabMouse)
-    {
-       if (!--doPointerWarp)
-       {
-           XWarpPointer( X_display,
-                         None,
-                         X_mainWindow,
-                         0, 0,
-                         0, 0,
-                         X_width/2, X_height/2);
+    // always grab the mouse when full screen (dont want to 
+    // see the mouse pointer)
 
-           doPointerWarp = POINTER_WARP_COUNTDOWN;
-       }
-    }
+    if (fullscreen)
+        return true;
+
+    // Don't grab the mouse if mouse input is disabled
+
+    if (!usemouse || nomouse)
+        return false;
+
+    // if we specify not to grab the mouse, never grab
+
+    if (!grabmouse)
+        return false;
+
+    // Invoke the grabmouse callback function to determine whether
+    // the mouse should be grabbed
 
-    mousemoved = false;
+    if (grabmouse_callback != NULL)
+    {
+        return grabmouse_callback();
+    }
+    else
+    {
+        return true;
+    }
+}
 
+void I_SetGrabMouseCallback(grabmouse_callback_t func)
+{
+    grabmouse_callback = func;
 }
 
+// Set the variable controlling FPS dots.
 
-//
-// I_UpdateNoBlit
-//
-void I_UpdateNoBlit (void)
+void I_DisplayFPSDots(boolean dots_on)
 {
-    // what is this?
+    display_fps_dots = dots_on;
 }
 
+// Update the value of window_focused when we get a focus event
 //
-// I_FinishUpdate
-//
-void I_FinishUpdate (void)
+// We try to make ourselves be well-behaved: the grab on the mouse
+// is removed if we lose focus (such as a popup window appearing),
+// and we dont move the mouse around if we aren't focused either.
+
+static void UpdateFocus(void)
 {
+    Uint8 state;
 
-    static int lasttic;
-    int                tics;
-    int                i;
-    // UNUSED static unsigned char *bigscreen=0;
+    state = SDL_GetAppState();
 
-    // draws little dots on the bottom of the screen
-    if (devparm)
-    {
+    // We should have input (keyboard) focus and be visible 
+    // (not minimized)
 
-       i = I_GetTime();
-       tics = i - lasttic;
-       lasttic = i;
-       if (tics > 20) tics = 20;
+    window_focused = (state & SDL_APPINPUTFOCUS) && (state & SDL_APPACTIVE);
 
-       for (i=0 ; i<tics*2 ; i+=2)
-           screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0xff;
-       for ( ; i<20*2 ; i+=2)
-           screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0;
-    
-    }
+    // Should the screen be grabbed?
 
-    // scales the screen size before blitting it
-    if (multiply == 2)
-    {
-       unsigned int *olineptrs[2];
-       unsigned int *ilineptr;
-       int x, y, i;
-       unsigned int twoopixels;
-       unsigned int twomoreopixels;
-       unsigned int fouripixels;
-
-       ilineptr = (unsigned int *) (screens[0]);
-       for (i=0 ; i<2 ; i++)
-           olineptrs[i] = (unsigned int *) &image->data[i*X_width];
-
-       y = SCREENHEIGHT;
-       while (y--)
-       {
-           x = SCREENWIDTH;
-           do
-           {
-               fouripixels = *ilineptr++;
-               twoopixels =    (fouripixels & 0xff000000)
-                   |   ((fouripixels>>8) & 0xffff00)
-                   |   ((fouripixels>>16) & 0xff);
-               twomoreopixels =        ((fouripixels<<16) & 0xff000000)
-                   |   ((fouripixels<<8) & 0xffff00)
-                   |   (fouripixels & 0xff);
-#ifdef __BIG_ENDIAN__
-               *olineptrs[0]++ = twoopixels;
-               *olineptrs[1]++ = twoopixels;
-               *olineptrs[0]++ = twomoreopixels;
-               *olineptrs[1]++ = twomoreopixels;
-#else
-               *olineptrs[0]++ = twomoreopixels;
-               *olineptrs[1]++ = twomoreopixels;
-               *olineptrs[0]++ = twoopixels;
-               *olineptrs[1]++ = twoopixels;
-#endif
-           } while (x-=4);
-           olineptrs[0] += X_width/4;
-           olineptrs[1] += X_width/4;
-       }
-
-    }
-    else if (multiply == 3)
-    {
-       unsigned int *olineptrs[3];
-       unsigned int *ilineptr;
-       int x, y, i;
-       unsigned int fouropixels[3];
-       unsigned int fouripixels;
-
-       ilineptr = (unsigned int *) (screens[0]);
-       for (i=0 ; i<3 ; i++)
-           olineptrs[i] = (unsigned int *) &image->data[i*X_width];
-
-       y = SCREENHEIGHT;
-       while (y--)
-       {
-           x = SCREENWIDTH;
-           do
-           {
-               fouripixels = *ilineptr++;
-               fouropixels[0] = (fouripixels & 0xff000000)
-                   |   ((fouripixels>>8) & 0xff0000)
-                   |   ((fouripixels>>16) & 0xffff);
-               fouropixels[1] = ((fouripixels<<8) & 0xff000000)
-                   |   (fouripixels & 0xffff00)
-                   |   ((fouripixels>>8) & 0xff);
-               fouropixels[2] = ((fouripixels<<16) & 0xffff0000)
-                   |   ((fouripixels<<8) & 0xff00)
-                   |   (fouripixels & 0xff);
-#ifdef __BIG_ENDIAN__
-               *olineptrs[0]++ = fouropixels[0];
-               *olineptrs[1]++ = fouropixels[0];
-               *olineptrs[2]++ = fouropixels[0];
-               *olineptrs[0]++ = fouropixels[1];
-               *olineptrs[1]++ = fouropixels[1];
-               *olineptrs[2]++ = fouropixels[1];
-               *olineptrs[0]++ = fouropixels[2];
-               *olineptrs[1]++ = fouropixels[2];
-               *olineptrs[2]++ = fouropixels[2];
-#else
-               *olineptrs[0]++ = fouropixels[2];
-               *olineptrs[1]++ = fouropixels[2];
-               *olineptrs[2]++ = fouropixels[2];
-               *olineptrs[0]++ = fouropixels[1];
-               *olineptrs[1]++ = fouropixels[1];
-               *olineptrs[2]++ = fouropixels[1];
-               *olineptrs[0]++ = fouropixels[0];
-               *olineptrs[1]++ = fouropixels[0];
-               *olineptrs[2]++ = fouropixels[0];
-#endif
-           } while (x-=4);
-           olineptrs[0] += 2*X_width/4;
-           olineptrs[1] += 2*X_width/4;
-           olineptrs[2] += 2*X_width/4;
-       }
+    screenvisible = (state & SDL_APPACTIVE) != 0;
+}
 
+// Show or hide the mouse cursor. We have to use different techniques
+// depending on the OS.
+
+static void SetShowCursor(boolean show)
+{
+    // On Windows, using SDL_ShowCursor() adds lag to the mouse input,
+    // so work around this by setting an invisible cursor instead. On
+    // other systems, it isn't possible to change the cursor, so this
+    // hack has to be Windows-only. (Thanks to entryway for this)
+
+#ifdef _WIN32
+    if (show)
+    {
+        SDL_SetCursor(cursors[1]);
     }
-    else if (multiply == 4)
+    else
     {
-       // Broken. Gotta fix this some day.
-       void Expand4(unsigned *, double *);
-       Expand4 ((unsigned *)(screens[0]), (double *) (image->data));
+        SDL_SetCursor(cursors[0]);
     }
+#else
+    SDL_ShowCursor(show);
+#endif
+
+    // When the cursor is hidden, grab the input.
 
-    if (doShm)
+    if (!screensaver_mode)
     {
+        SDL_WM_GrabInput(!show);
+    }
+}
+
+void I_EnableLoadingDisk(void)
+{
+    patch_t *disk;
+    byte *tmpbuf;
+    char *disk_name;
+    int y;
+    char buf[20];
 
-       if (!XShmPutImage(      X_display,
-                               X_mainWindow,
-                               X_gc,
-                               image,
-                               0, 0,
-                               0, 0,
-                               X_width, X_height,
-                               True ))
-           I_Error("XShmPutImage() failed\n");
+    SDL_VideoDriverName(buf, 15);
 
-       // wait for it to finish and processes all input events
-       shmFinished = false;
-       do
-       {
-           I_GetEvent();
-       } while (!shmFinished);
+    if (!strcmp(buf, "Quartz"))
+    {
+        // MacOS Quartz gives us pageflipped graphics that screw up the 
+        // display when we use the loading disk.  Disable it.
+        // This is a gross hack.
 
+        return;
     }
+
+    if (M_CheckParm("-cdrom") > 0)
+        disk_name = DEH_String("STCDROM");
     else
-    {
+        disk_name = DEH_String("STDISK");
 
-       // draw the image
-       XPutImage(      X_display,
-                       X_mainWindow,
-                       X_gc,
-                       image,
-                       0, 0,
-                       0, 0,
-                       X_width, X_height );
+    disk = W_CacheLumpName(disk_name, PU_STATIC);
 
-       // sync up with server
-       XSync(X_display, False);
+    // Draw the patch into a temporary buffer
 
-    }
+    tmpbuf = Z_Malloc(SCREENWIDTH * (disk->height + 1), PU_STATIC, NULL);
+    V_UseBuffer(tmpbuf);
 
-}
+    // Draw the disk to the screen:
 
+    V_DrawPatch(0, 0, disk);
 
-//
-// I_ReadScreen
-//
-void I_ReadScreen (byte* scr)
-{
-    memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT);
-}
+    disk_image = Z_Malloc(LOADING_DISK_W * LOADING_DISK_H, PU_STATIC, NULL);
+    saved_background = Z_Malloc(LOADING_DISK_W * LOADING_DISK_H, PU_STATIC, NULL);
+
+    for (y=0; y<LOADING_DISK_H; ++y) 
+    {
+        memcpy(disk_image + LOADING_DISK_W * y,
+               tmpbuf + SCREENWIDTH * y,
+               LOADING_DISK_W);
+    }
 
+    // All done - free the screen buffer and restore the normal 
+    // video buffer.
+
+    W_ReleaseLumpName(disk_name);
+    V_RestoreBuffer();
+    Z_Free(tmpbuf);
+}
 
 //
-// Palette stuff.
+// Translates the SDL key
 //
-static XColor  colors[256];
 
-void UploadNewPalette(Colormap cmap, byte *palette)
+static int TranslateKey(SDL_keysym *sym)
 {
+    switch(sym->sym)
+    {
+      case SDLK_LEFT:  return KEY_LEFTARROW;
+      case SDLK_RIGHT: return KEY_RIGHTARROW;
+      case SDLK_DOWN:  return KEY_DOWNARROW;
+      case SDLK_UP:    return KEY_UPARROW;
+      case SDLK_ESCAPE:        return KEY_ESCAPE;
+      case SDLK_RETURN:        return KEY_ENTER;
+      case SDLK_TAB:   return KEY_TAB;
+      case SDLK_F1:    return KEY_F1;
+      case SDLK_F2:    return KEY_F2;
+      case SDLK_F3:    return KEY_F3;
+      case SDLK_F4:    return KEY_F4;
+      case SDLK_F5:    return KEY_F5;
+      case SDLK_F6:    return KEY_F6;
+      case SDLK_F7:    return KEY_F7;
+      case SDLK_F8:    return KEY_F8;
+      case SDLK_F9:    return KEY_F9;
+      case SDLK_F10:   return KEY_F10;
+      case SDLK_F11:   return KEY_F11;
+      case SDLK_F12:   return KEY_F12;
+      case SDLK_PRINT:  return KEY_PRTSCR;
+
+      case SDLK_BACKSPACE: return KEY_BACKSPACE;
+      case SDLK_DELETE:        return KEY_DEL;
+
+      case SDLK_PAUSE: return KEY_PAUSE;
+
+#if !SDL_VERSION_ATLEAST(1, 3, 0)
+      case SDLK_EQUALS: return KEY_EQUALS;
+#endif
 
-    register int       i;
-    register int       c;
-    static boolean     firstcall = true;
+      case SDLK_MINUS:          return KEY_MINUS;
 
-#ifdef __cplusplus
-    if (X_visualinfo.c_class == PseudoColor && X_visualinfo.depth == 8)
-#else
-    if (X_visualinfo.class == PseudoColor && X_visualinfo.depth == 8)
+      case SDLK_LSHIFT:
+      case SDLK_RSHIFT:
+       return KEY_RSHIFT;
+       
+      case SDLK_LCTRL:
+      case SDLK_RCTRL:
+       return KEY_RCTRL;
+       
+      case SDLK_LALT:
+      case SDLK_RALT:
+#if !SDL_VERSION_ATLEAST(1, 3, 0)
+      case SDLK_LMETA:
+      case SDLK_RMETA:
 #endif
-       {
-           // initialize the colormap
-           if (firstcall)
-           {
-               firstcall = false;
-               for (i=0 ; i<256 ; i++)
-               {
-                   colors[i].pixel = i;
-                   colors[i].flags = DoRed|DoGreen|DoBlue;
-               }
-           }
-
-           // set the X colormap entries
-           for (i=0 ; i<256 ; i++)
-           {
-               c = gammatable[usegamma][*palette++];
-               colors[i].red = (c<<8) + c;
-               c = gammatable[usegamma][*palette++];
-               colors[i].green = (c<<8) + c;
-               c = gammatable[usegamma][*palette++];
-               colors[i].blue = (c<<8) + c;
-           }
-
-           // store the colors to the current colormap
-           XStoreColors(X_display, cmap, colors, 256);
-
-       }
+        return KEY_RALT;
+
+      case SDLK_CAPSLOCK: return KEY_CAPSLOCK;
+      case SDLK_SCROLLOCK: return KEY_SCRLCK;
+      case SDLK_NUMLOCK: return KEY_NUMLOCK;
+
+      case SDLK_KP0: return KEYP_0;
+      case SDLK_KP1: return KEYP_1;
+      case SDLK_KP2: return KEYP_2;
+      case SDLK_KP3: return KEYP_3;
+      case SDLK_KP4: return KEYP_4;
+      case SDLK_KP5: return KEYP_5;
+      case SDLK_KP6: return KEYP_6;
+      case SDLK_KP7: return KEYP_7;
+      case SDLK_KP8: return KEYP_8;
+      case SDLK_KP9: return KEYP_9;
+
+      case SDLK_KP_PERIOD:   return KEYP_PERIOD;
+      case SDLK_KP_MULTIPLY: return KEYP_MULTIPLY;
+      case SDLK_KP_PLUS:     return KEYP_PLUS;
+      case SDLK_KP_MINUS:    return KEYP_MINUS;
+      case SDLK_KP_DIVIDE:   return KEYP_DIVIDE;
+      case SDLK_KP_EQUALS:   return KEYP_EQUALS;
+      case SDLK_KP_ENTER:    return KEYP_ENTER;
+
+      case SDLK_HOME: return KEY_HOME;
+      case SDLK_INSERT: return KEY_INS;
+      case SDLK_END: return KEY_END;
+      case SDLK_PAGEUP: return KEY_PGUP;
+      case SDLK_PAGEDOWN: return KEY_PGDN;
+
+#ifdef SDL_HAVE_APP_KEYS
+        case SDLK_APP1:        return KEY_F1;
+        case SDLK_APP2:        return KEY_F2;
+        case SDLK_APP3:        return KEY_F3;
+        case SDLK_APP4:        return KEY_F4;
+        case SDLK_APP5:        return KEY_F5;
+        case SDLK_APP6:        return KEY_F6;
+#endif
+
+      default:
+        return tolower(sym->sym);
+    }
 }
 
-//
-// I_SetPalette
-//
-void I_SetPalette (byte* palette)
+void I_ShutdownGraphics(void)
 {
-    UploadNewPalette(X_cmap, palette);
+    if (initialized)
+    {
+        SetShowCursor(true);
+
+        SDL_QuitSubSystem(SDL_INIT_VIDEO);
+
+        initialized = false;
+    }
 }
 
 
+
 //
-// This function is probably redundant,
-//  if XShmDetach works properly.
-// ddt never detached the XShm memory,
-//  thus there might have been stale
-//  handles accumulating.
+// I_StartFrame
 //
-void grabsharedmemory(int size)
+void I_StartFrame (void)
 {
+    // er?
 
-  int                  key = ('d'<<24) | ('o'<<16) | ('o'<<8) | 'm';
-  struct shmid_ds      shminfo;
-  int                  minsize = 320*200;
-  int                  id;
-  int                  rc;
-  // UNUSED int done=0;
-  int                  pollution=5;
-  
-  // try to use what was here before
-  do
-  {
-    id = shmget((key_t) key, minsize, 0777); // just get the id
-    if (id != -1)
-    {
-      rc=shmctl(id, IPC_STAT, &shminfo); // get stats on it
-      if (!rc) 
-      {
-       if (shminfo.shm_nattch)
-       {
-         fprintf(stderr, "User %d appears to be running "
-                 "DOOM.  Is that wise?\n", shminfo.shm_cpid);
-         key++;
-       }
-       else
-       {
-         if (getuid() == shminfo.shm_perm.cuid)
-         {
-           rc = shmctl(id, IPC_RMID, 0);
-           if (!rc)
-             fprintf(stderr,
-                     "Was able to kill my old shared memory\n");
-           else
-             I_Error("Was NOT able to kill my old shared memory");
-           
-           id = shmget((key_t)key, size, IPC_CREAT|0777);
-           if (id==-1)
-             I_Error("Could not get shared memory");
-           
-           rc=shmctl(id, IPC_STAT, &shminfo);
-           
-           break;
-           
-         }
-         if (size >= shminfo.shm_segsz)
-         {
-           fprintf(stderr,
-                   "will use %d's stale shared memory\n",
-                   shminfo.shm_cpid);
-           break;
-         }
-         else
-         {
-           fprintf(stderr,
-                   "warning: can't use stale "
-                   "shared memory belonging to id %d, "
-                   "key=0x%x\n",
-                   shminfo.shm_cpid, key);
-           key++;
-         }
-       }
-      }
-      else
-      {
-       I_Error("could not get stats on key=%d", key);
-      }
-    }
-    else
-    {
-      id = shmget((key_t)key, size, IPC_CREAT|0777);
-      if (id==-1)
-      {
-       fprintf(stderr, "errno=%d\n", errno);
-       I_Error("Could not get any shared memory");
-      }
-      break;
-    }
-  } while (--pollution);
-  
-  if (!pollution)
-  {
-    I_Error("Sorry, system too polluted with stale "
-           "shared memory segments.\n");
-    }  
-  
-  X_shminfo.shmid = id;
-  
-  // attach to the shared memory segment
-  image->data = X_shminfo.shmaddr = shmat(id, 0, 0);
-  
-  fprintf(stderr, "shared memory id=%d, addr=0x%x\n", id,
-         (int) (image->data));
 }
 
-void I_InitGraphics(void)
+static void UpdateMouseButtonState(unsigned int button, boolean on)
 {
+    event_t event;
 
-    char*              displayname;
-    char*              d;
-    int                        n;
-    int                        pnum;
-    int                        x=0;
-    int                        y=0;
-    
-    // warning: char format, different type arg
-    char               xsign=' ';
-    char               ysign=' ';
-    
-    int                        oktodraw;
-    unsigned long      attribmask;
-    XSetWindowAttributes attribs;
-    XGCValues          xgcvalues;
-    int                        valuemask;
-    static int         firsttime=1;
-
-    if (!firsttime)
-       return;
-    firsttime = 0;
+    if (button < SDL_BUTTON_LEFT || button > MAX_MOUSE_BUTTONS)
+    {
+        return;
+    }
 
-    signal(SIGINT, (void (*)(int)) I_Quit);
+    // Note: button "0" is left, button "1" is right,
+    // button "2" is middle for Doom.  This is different
+    // to how SDL sees things.
 
-    if (M_CheckParm("-2"))
-       multiply = 2;
+    switch (button)
+    {
+        case SDL_BUTTON_LEFT:
+            button = 0;
+            break;
+
+        case SDL_BUTTON_RIGHT:
+            button = 1;
+            break;
+
+        case SDL_BUTTON_MIDDLE:
+            button = 2;
+            break;
+
+        default:
+            // SDL buttons are indexed from 1.
+            --button;
+            break;
+    }
 
-    if (M_CheckParm("-3"))
-       multiply = 3;
+    // Turn bit representing this button on or off.
 
-    if (M_CheckParm("-4"))
-       multiply = 4;
+    if (on)
+    {
+        mouse_button_state |= (1 << button);
+    }
+    else
+    {
+        mouse_button_state &= ~(1 << button);
+    }
 
-    X_width = SCREENWIDTH * multiply;
-    X_height = SCREENHEIGHT * multiply;
+    // Post an event with the new button state.
 
-    // check for command-line display name
-    if ( (pnum=M_CheckParm("-disp")) ) // suggest parentheses around assignment
-       displayname = myargv[pnum+1];
-    else
-       displayname = 0;
+    event.type = ev_mouse;
+    event.data1 = mouse_button_state;
+    event.data2 = event.data3 = 0;
+    D_PostEvent(&event);
+}
 
-    // check if the user wants to grab the mouse (quite unnice)
-    grabMouse = !!M_CheckParm("-grabmouse");
+static int AccelerateMouse(int val)
+{
+    if (val < 0)
+        return -AccelerateMouse(-val);
 
-    // check for command-line geometry
-    if ( (pnum=M_CheckParm("-geom")) ) // suggest parentheses around assignment
+    if (val > mouse_threshold)
     {
-       // warning: char format, different type arg 3,5
-       n = sscanf(myargv[pnum+1], "%c%d%c%d", &xsign, &x, &ysign, &y);
-       
-       if (n==2)
-           x = y = 0;
-       else if (n==6)
-       {
-           if (xsign == '-')
-               x = -x;
-           if (ysign == '-')
-               y = -y;
-       }
-       else
-           I_Error("bad -geom parameter");
-    }
-
-    // open the display
-    X_display = XOpenDisplay(displayname);
-    if (!X_display)
-    {
-       if (displayname)
-           I_Error("Could not open display [%s]", displayname);
-       else
-           I_Error("Could not open display (DISPLAY=[%s])", getenv("DISPLAY"));
-    }
-
-    // use the default visual 
-    X_screen = DefaultScreen(X_display);
-    if (!XMatchVisualInfo(X_display, X_screen, 8, PseudoColor, &X_visualinfo))
-       I_Error("xdoom currently only supports 256-color PseudoColor screens");
-    X_visual = X_visualinfo.visual;
-
-    // check for the MITSHM extension
-    doShm = XShmQueryExtension(X_display);
-
-    // even if it's available, make sure it's a local connection
-    if (doShm)
-    {
-       if (!displayname) displayname = (char *) getenv("DISPLAY");
-       if (displayname)
-       {
-           d = displayname;
-           while (*d && (*d != ':')) d++;
-           if (*d) *d = 0;
-           if (!(!strcasecmp(displayname, "unix") || !*displayname)) doShm = false;
-       }
-    }
-
-    fprintf(stderr, "Using MITSHM extension\n");
-
-    // create the colormap
-    X_cmap = XCreateColormap(X_display, RootWindow(X_display,
-                                                  X_screen), X_visual, AllocAll);
-
-    // setup attributes for main window
-    attribmask = CWEventMask | CWColormap | CWBorderPixel;
-    attribs.event_mask =
-       KeyPressMask
-       | KeyReleaseMask
-       // | PointerMotionMask | ButtonPressMask | ButtonReleaseMask
-       | ExposureMask;
-
-    attribs.colormap = X_cmap;
-    attribs.border_pixel = 0;
-
-    // create the main window
-    X_mainWindow = XCreateWindow(      X_display,
-                                       RootWindow(X_display, X_screen),
-                                       x, y,
-                                       X_width, X_height,
-                                       0, // borderwidth
-                                       8, // depth
-                                       InputOutput,
-                                       X_visual,
-                                       attribmask,
-                                       &attribs );
-
-    XDefineCursor(X_display, X_mainWindow,
-                 createnullcursor( X_display, X_mainWindow ) );
-
-    // create the GC
-    valuemask = GCGraphicsExposures;
-    xgcvalues.graphics_exposures = False;
-    X_gc = XCreateGC(  X_display,
-                       X_mainWindow,
-                       valuemask,
-                       &xgcvalues );
-
-    // map the window
-    XMapWindow(X_display, X_mainWindow);
-
-    // wait until it is OK to draw
-    oktodraw = 0;
-    while (!oktodraw)
-    {
-       XNextEvent(X_display, &X_event);
-       if (X_event.type == Expose
-           && !X_event.xexpose.count)
-       {
-           oktodraw = 1;
-       }
-    }
-
-    // grabs the pointer so it is restricted to this window
-    if (grabMouse)
-       XGrabPointer(X_display, X_mainWindow, True,
-                    ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
-                    GrabModeAsync, GrabModeAsync,
-                    X_mainWindow, None, CurrentTime);
-
-    if (doShm)
-    {
-
-       X_shmeventtype = XShmGetEventBase(X_display) + ShmCompletion;
-
-       // create the image
-       image = XShmCreateImage(        X_display,
-                                       X_visual,
-                                       8,
-                                       ZPixmap,
-                                       0,
-                                       &X_shminfo,
-                                       X_width,
-                                       X_height );
-
-       grabsharedmemory(image->bytes_per_line * image->height);
-
-
-       // UNUSED
-       // create the shared memory segment
-       // X_shminfo.shmid = shmget (IPC_PRIVATE,
-       // image->bytes_per_line * image->height, IPC_CREAT | 0777);
-       // if (X_shminfo.shmid < 0)
-       // {
-       // perror("");
-       // I_Error("shmget() failed in InitGraphics()");
-       // }
-       // fprintf(stderr, "shared memory id=%d\n", X_shminfo.shmid);
-       // attach to the shared memory segment
-       // image->data = X_shminfo.shmaddr = shmat(X_shminfo.shmid, 0, 0);
-       
-
-       if (!image->data)
-       {
-           perror("");
-           I_Error("shmat() failed in InitGraphics()");
-       }
+        return (int)((val - mouse_threshold) * mouse_acceleration + mouse_threshold);
+    }
+    else
+    {
+        return val;
+    }
+}
 
-       // get the X server to attach to it
-       if (!XShmAttach(X_display, &X_shminfo))
-           I_Error("XShmAttach() failed in InitGraphics()");
+// Get the equivalent ASCII (Unicode?) character for a keypress.
 
+static int GetTypedChar(SDL_Event *event)
+{
+    int key;
+
+    // If Vanilla keyboard mapping enabled, the keyboard
+    // scan code is used to give the character typed.
+    // This does not change depending on keyboard layout.
+    // If you have a German keyboard, pressing 'z' will
+    // give 'y', for example.  It is desirable to be able
+    // to fix this so that people with non-standard 
+    // keyboard mappings can type properly.  If vanilla
+    // mode is disabled, use the properly translated 
+    // version.
+
+    if (vanilla_keyboard_mapping)
+    {
+        key = TranslateKey(&event->key.keysym);
+
+        // Is shift held down?  If so, perform a translation.
+
+        if (shiftdown > 0)
+        {
+            if (key >= 0 && key < arrlen(shiftxform))
+            {
+                key = shiftxform[key];
+            }
+            else
+            {
+                key = 0;
+            }
+        }
+
+        return key;
     }
     else
     {
-       image = XCreateImage(   X_display,
-                               X_visual,
-                               8,
-                               ZPixmap,
-                               0,
-                               (char*)malloc(X_width * X_height),
-                               X_width, X_height,
-                               8,
-                               X_width );
+        // Unicode value, from key layout.
 
+        return tolower(event->key.keysym.unicode);
     }
+}
 
-    if (multiply == 1)
-       screens[0] = (unsigned char *) (image->data);
+static void UpdateShiftStatus(SDL_Event *event)
+{
+    int change;
+
+    if (event->type == SDL_KEYDOWN)
+    {
+        change = 1;
+    }
+    else if (event->type == SDL_KEYUP)
+    {
+        change = -1;
+    }
     else
-       screens[0] = (unsigned char *) malloc (SCREENWIDTH * SCREENHEIGHT);
+    {
+        return;
+    }
 
+    if (event->key.keysym.sym == SDLK_LSHIFT 
+     || event->key.keysym.sym == SDLK_RSHIFT)
+    {
+        shiftdown += change;
+    }
 }
 
+void I_GetEvent(void)
+{
+    SDL_Event sdlevent;
+    event_t event;
 
-unsigned       exptable[256];
+    // possibly not needed
+    
+    SDL_PumpEvents();
 
-void InitExpand (void)
-{
-    int                i;
-       
-    for (i=0 ; i<256 ; i++)
-       exptable[i] = i | (i<<8) | (i<<16) | (i<<24);
+    // put event-grabbing stuff in here
+    
+    while (SDL_PollEvent(&sdlevent))
+    {
+        // ignore mouse events when the window is not focused
+
+        if (!window_focused 
+         && (sdlevent.type == SDL_MOUSEMOTION
+          || sdlevent.type == SDL_MOUSEBUTTONDOWN
+          || sdlevent.type == SDL_MOUSEBUTTONUP))
+        {
+            continue;
+        }
+
+        if (screensaver_mode && sdlevent.type == SDL_QUIT)
+        {
+            I_Quit();
+        }
+
+        UpdateShiftStatus(&sdlevent);
+
+        // process event
+        
+        switch (sdlevent.type)
+        {
+            case SDL_KEYDOWN:
+                // data1 has the key pressed, data2 has the character
+                // (shift-translated, etc)
+                event.type = ev_keydown;
+                event.data1 = TranslateKey(&sdlevent.key.keysym);
+                event.data2 = GetTypedChar(&sdlevent);
+
+                if (event.data1 != 0)
+                {
+                    D_PostEvent(&event);
+                }
+                break;
+
+            case SDL_KEYUP:
+                event.type = ev_keyup;
+                event.data1 = TranslateKey(&sdlevent.key.keysym);
+
+                // data2 is just initialized to zero for ev_keyup.
+                // For ev_keydown it's the shifted Unicode character
+                // that was typed, but if something wants to detect
+                // key releases it should do so based on data1
+                // (key ID), not the printable char.
+
+                event.data2 = 0;
+
+                if (event.data1 != 0)
+                {
+                    D_PostEvent(&event);
+                }
+                break;
+
+                /*
+            case SDL_MOUSEMOTION:
+                event.type = ev_mouse;
+                event.data1 = mouse_button_state;
+                event.data2 = AccelerateMouse(sdlevent.motion.xrel);
+                event.data3 = -AccelerateMouse(sdlevent.motion.yrel);
+                D_PostEvent(&event);
+                break;
+                */
+
+            case SDL_MOUSEBUTTONDOWN:
+               if (usemouse && !nomouse)
+               {
+                    UpdateMouseButtonState(sdlevent.button.button, true);
+               }
+                break;
+
+            case SDL_MOUSEBUTTONUP:
+               if (usemouse && !nomouse)
+               {
+                    UpdateMouseButtonState(sdlevent.button.button, false);
+               }
+                break;
+
+            case SDL_QUIT:
+                event.type = ev_quit;
+                D_PostEvent(&event);
+                break;
+
+            case SDL_ACTIVEEVENT:
+                // need to update our focus state
+                UpdateFocus();
+                break;
+
+            case SDL_VIDEOEXPOSE:
+                palette_to_set = true;
+                break;
+
+            case SDL_RESIZABLE:
+                need_resize = true;
+                resize_w = sdlevent.resize.w;
+                resize_h = sdlevent.resize.h;
+                last_resize_time = SDL_GetTicks();
+                break;
+
+            default:
+                break;
+        }
+    }
 }
 
-double         exptable2[256*256];
+// Warp the mouse back to the middle of the screen
 
-void InitExpand2 (void)
+static void CenterMouse(void)
 {
-    int                i;
-    int                j;
-    // UNUSED unsigned iexp, jexp;
-    double*    exp;
-    union
-    {
-       double          d;
-       unsigned        u[2];
-    } pixel;
-       
-    printf ("building exptable2...\n");
-    exp = exptable2;
-    for (i=0 ; i<256 ; i++)
-    {
-       pixel.u[0] = i | (i<<8) | (i<<16) | (i<<24);
-       for (j=0 ; j<256 ; j++)
-       {
-           pixel.u[1] = j | (j<<8) | (j<<16) | (j<<24);
-           *exp++ = pixel.d;
-       }
-    }
-    printf ("done.\n");
+    // Warp the the screen center
+
+    SDL_WarpMouse(screen->w / 2, screen->h / 2);
+
+    // Clear any relative movement caused by warping
+
+    SDL_PumpEvents();
+#if SDL_VERSION_ATLEAST(1, 3, 0)
+    SDL_GetRelativeMouseState(0, NULL, NULL);
+#else
+    SDL_GetRelativeMouseState(NULL, NULL);
+#endif
 }
 
-int    inited;
+//
+// Read the change in mouse state to generate mouse motion events
+//
+// This is to combine all mouse movement for a tic into one mouse
+// motion event.
 
-void
-Expand4
-( unsigned*    lineptr,
-  double*      xline )
+static void I_ReadMouse(void)
 {
-    double     dpixel;
-    unsigned   x;
-    unsigned   y;
-    unsigned   fourpixels;
-    unsigned   step;
-    double*    exp;
-       
-    exp = exptable2;
-    if (!inited)
+    int x, y;
+    event_t ev;
+
+#if SDL_VERSION_ATLEAST(1, 3, 0)
+    SDL_GetRelativeMouseState(0, &x, &y);
+#else
+    SDL_GetRelativeMouseState(&x, &y);
+#endif
+
+    if (x != 0 || y != 0) 
     {
-       inited = 1;
-       InitExpand2 ();
+        ev.type = ev_mouse;
+        ev.data1 = mouse_button_state;
+        ev.data2 = AccelerateMouse(x);
+
+        if (!novert)
+        {
+            ev.data3 = -AccelerateMouse(y);
+        }
+        else
+        {
+            ev.data3 = 0;
+        }
+        
+        D_PostEvent(&ev);
     }
-               
-               
-    step = 3*SCREENWIDTH/2;
-       
-    y = SCREENHEIGHT-1;
-    do
-    {
-       x = SCREENWIDTH;
-
-       do
-       {
-           fourpixels = lineptr[0];
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
-           xline[0] = dpixel;
-           xline[160] = dpixel;
-           xline[320] = dpixel;
-           xline[480] = dpixel;
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
-           xline[1] = dpixel;
-           xline[161] = dpixel;
-           xline[321] = dpixel;
-           xline[481] = dpixel;
-
-           fourpixels = lineptr[1];
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
-           xline[2] = dpixel;
-           xline[162] = dpixel;
-           xline[322] = dpixel;
-           xline[482] = dpixel;
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
-           xline[3] = dpixel;
-           xline[163] = dpixel;
-           xline[323] = dpixel;
-           xline[483] = dpixel;
-
-           fourpixels = lineptr[2];
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
-           xline[4] = dpixel;
-           xline[164] = dpixel;
-           xline[324] = dpixel;
-           xline[484] = dpixel;
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
-           xline[5] = dpixel;
-           xline[165] = dpixel;
-           xline[325] = dpixel;
-           xline[485] = dpixel;
-
-           fourpixels = lineptr[3];
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
-           xline[6] = dpixel;
-           xline[166] = dpixel;
-           xline[326] = dpixel;
-           xline[486] = dpixel;
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
-           xline[7] = dpixel;
-           xline[167] = dpixel;
-           xline[327] = dpixel;
-           xline[487] = dpixel;
-
-           lineptr+=4;
-           xline+=8;
-       } while (x-=16);
-       xline += step;
-    } while (y--);
+
+    if (MouseShouldBeGrabbed())
+    {
+        CenterMouse();
+    }
+}
+
+//
+// I_StartTic
+//
+void I_StartTic (void)
+{
+    if (!initialized)
+    {
+        return;
+    }
+
+    I_GetEvent();
+
+    if (usemouse && !nomouse)
+    {
+        I_ReadMouse();
+    }
+
+    I_UpdateJoystick();
+}
+
+
+//
+// I_UpdateNoBlit
+//
+void I_UpdateNoBlit (void)
+{
+    // what is this?
+}
+
+static void UpdateGrab(void)
+{
+    static boolean currently_grabbed = false;
+    boolean grab;
+
+    grab = MouseShouldBeGrabbed();
+
+    if (screensaver_mode)
+    {
+        // Hide the cursor in screensaver mode
+
+        SetShowCursor(false);
+    }
+    else if (grab && !currently_grabbed)
+    {
+        SetShowCursor(false);
+        CenterMouse();
+    }
+    else if (!grab && currently_grabbed)
+    {
+        SetShowCursor(true);
+
+        // When releasing the mouse from grab, warp the mouse cursor to
+        // the bottom-right of the screen. This is a minimally distracting
+        // place for it to appear - we may only have released the grab
+        // because we're at an end of level intermission screen, for
+        // example.
+
+        SDL_WarpMouse(screen->w - 16, screen->h - 16);
+        SDL_GetRelativeMouseState(NULL, NULL);
+    }
+
+    currently_grabbed = grab;
+
+}
+
+// Update a small portion of the screen
+//
+// Does stretching and buffer blitting if neccessary
+//
+// Return true if blit was successful.
+
+static boolean BlitArea(int x1, int y1, int x2, int y2)
+{
+    int x_offset, y_offset;
+    boolean result;
+
+    // No blit needed on native surface
+
+    if (native_surface)
+    {
+       return true;
+    }
+
+    x_offset = (screenbuffer->w - screen_mode->width) / 2;
+    y_offset = (screenbuffer->h - screen_mode->height) / 2;
+
+    if (SDL_LockSurface(screenbuffer) >= 0)
+    {
+        I_InitScale(I_VideoBuffer,
+                    (byte *) screenbuffer->pixels
+                                + (y_offset * screenbuffer->pitch)
+                                + x_offset,
+                    screenbuffer->pitch);
+        result = screen_mode->DrawScreen(x1, y1, x2, y2);
+       SDL_UnlockSurface(screenbuffer);
+    }
+    else
+    {
+        result = false;
+    }
+
+    return result;
+}
+
+static void UpdateRect(int x1, int y1, int x2, int y2)
+{
+    int x1_scaled, x2_scaled, y1_scaled, y2_scaled;
+
+    // Do stretching and blitting
+
+    if (BlitArea(x1, y1, x2, y2))
+    {
+        // Update the area
+
+        x1_scaled = (x1 * screen_mode->width) / SCREENWIDTH;
+        y1_scaled = (y1 * screen_mode->height) / SCREENHEIGHT;
+        x2_scaled = (x2 * screen_mode->width) / SCREENWIDTH;
+        y2_scaled = (y2 * screen_mode->height) / SCREENHEIGHT;
+
+        SDL_UpdateRect(screen,
+                       x1_scaled, y1_scaled,
+                       x2_scaled - x1_scaled,
+                       y2_scaled - y1_scaled);
+    }
+}
+
+void I_BeginRead(void)
+{
+    byte *screenloc = I_VideoBuffer
+                    + (SCREENHEIGHT - LOADING_DISK_H) * SCREENWIDTH
+                    + (SCREENWIDTH - LOADING_DISK_W);
+    int y;
+
+    if (!initialized || disk_image == NULL)
+        return;
+
+    // save background and copy the disk image in
+
+    for (y=0; y<LOADING_DISK_H; ++y)
+    {
+        memcpy(saved_background + y * LOADING_DISK_W,
+               screenloc,
+               LOADING_DISK_W);
+        memcpy(screenloc,
+               disk_image + y * LOADING_DISK_W,
+               LOADING_DISK_W);
+
+        screenloc += SCREENWIDTH;
+    }
+
+    UpdateRect(SCREENWIDTH - LOADING_DISK_W, SCREENHEIGHT - LOADING_DISK_H,
+               SCREENWIDTH, SCREENHEIGHT);
+}
+
+void I_EndRead(void)
+{
+    byte *screenloc = I_VideoBuffer
+                    + (SCREENHEIGHT - LOADING_DISK_H) * SCREENWIDTH
+                    + (SCREENWIDTH - LOADING_DISK_W);
+    int y;
+
+    if (!initialized || disk_image == NULL)
+        return;
+
+    // save background and copy the disk image in
+
+    for (y=0; y<LOADING_DISK_H; ++y)
+    {
+        memcpy(screenloc,
+               saved_background + y * LOADING_DISK_W,
+               LOADING_DISK_W);
+
+        screenloc += SCREENWIDTH;
+    }
+
+    UpdateRect(SCREENWIDTH - LOADING_DISK_W, SCREENHEIGHT - LOADING_DISK_H,
+               SCREENWIDTH, SCREENHEIGHT);
+}
+
+//
+// I_FinishUpdate
+//
+void I_FinishUpdate (void)
+{
+    static int lasttic;
+    int                tics;
+    int                i;
+
+    if (!initialized)
+        return;
+
+    if (noblit)
+        return;
+
+    if (need_resize && SDL_GetTicks() > last_resize_time + 500)
+    {
+        ApplyWindowResize(resize_w, resize_h);
+        need_resize = false;
+        palette_to_set = true;
+    }
+
+    UpdateGrab();
+
+    // Don't update the screen if the window isn't visible.
+    // Not doing this breaks under Windows when we alt-tab away 
+    // while fullscreen.
+
+    if (!(SDL_GetAppState() & SDL_APPACTIVE))
+        return;
+
+    // draws little dots on the bottom of the screen
+
+    if (display_fps_dots)
+    {
+       i = I_GetTime();
+       tics = i - lasttic;
+       lasttic = i;
+       if (tics > 20) tics = 20;
+
+       for (i=0 ; i<tics*4 ; i+=4)
+           I_VideoBuffer[ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0xff;
+       for ( ; i<20*4 ; i+=4)
+           I_VideoBuffer[ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0;
+    }
+
+    // draw to screen
+
+    BlitArea(0, 0, SCREENWIDTH, SCREENHEIGHT);
+
+    if (palette_to_set)
+    {
+        SDL_SetColors(screenbuffer, palette, 0, 256);
+        palette_to_set = false;
+
+        // In native 8-bit mode, if we have a palette to set, the act
+        // of setting the palette updates the screen
+
+        if (screenbuffer == screen)
+        {
+            return;
+        }
+    }
+
+    // In 8in32 mode, we must blit from the fake 8-bit screen buffer
+    // to the real screen before doing a screen flip.
+
+    if (screenbuffer != screen)
+    {
+        SDL_Rect dst_rect;
+
+        // Center the buffer within the full screen space.
+
+        dst_rect.x = (screen->w - screenbuffer->w) / 2;
+        dst_rect.y = (screen->h - screenbuffer->h) / 2;
+
+        SDL_BlitSurface(screenbuffer, NULL, screen, &dst_rect);
+    }
+
+    SDL_Flip(screen);
+}
+
+
+//
+// I_ReadScreen
+//
+void I_ReadScreen (byte* scr)
+{
+    memcpy(scr, I_VideoBuffer, SCREENWIDTH*SCREENHEIGHT);
+}
+
+
+//
+// I_SetPalette
+//
+void I_SetPalette (byte *doompalette)
+{
+    int i;
+
+    for (i=0; i<256; ++i)
+    {
+        // Zero out the bottom two bits of each channel - the PC VGA
+        // controller only supports 6 bits of accuracy.
+
+        palette[i].r = gammatable[usegamma][*doompalette++] & ~3;
+        palette[i].g = gammatable[usegamma][*doompalette++] & ~3;
+        palette[i].b = gammatable[usegamma][*doompalette++] & ~3;
+    }
+
+    palette_to_set = true;
+}
+
+// Given an RGB value, find the closest matching palette index.
+
+int I_GetPaletteIndex(int r, int g, int b)
+{
+    int best, best_diff, diff;
+    int i;
+
+    best = 0; best_diff = INT_MAX;
+
+    for (i = 0; i < 256; ++i)
+    {
+        diff = (r - palette[i].r) * (r - palette[i].r)
+             + (g - palette[i].g) * (g - palette[i].g)
+             + (b - palette[i].b) * (b - palette[i].b);
+
+        if (diff < best_diff)
+        {
+            best = i;
+            best_diff = diff;
+        }
+
+        if (diff == 0)
+        {
+            break;
+        }
+    }
+
+    return best;
+}
+
+// 
+// Set the window title
+//
+
+void I_SetWindowTitle(char *title)
+{
+    window_title = title;
+}
+
+//
+// Call the SDL function to set the window title, based on 
+// the title set with I_SetWindowTitle.
+//
+
+void I_InitWindowTitle(void)
+{
+    char *buf;
+
+    buf = M_StringJoin(window_title, " - ", PACKAGE_STRING, NULL);
+    SDL_WM_SetCaption(buf, NULL);
+    free(buf);
+}
+
+// Set the application icon
+
+void I_InitWindowIcon(void)
+{
+    SDL_Surface *surface;
+    Uint8 *mask;
+    int i;
+
+    // Generate the mask
+
+    mask = malloc(icon_w * icon_h / 8);
+    memset(mask, 0, icon_w * icon_h / 8);
+
+    for (i=0; i<icon_w * icon_h; ++i)
+    {
+        if (icon_data[i * 3] != 0x00
+         || icon_data[i * 3 + 1] != 0x00
+         || icon_data[i * 3 + 2] != 0x00)
+        {
+            mask[i / 8] |= 1 << (7 - i % 8);
+        }
+    }
+
+    surface = SDL_CreateRGBSurfaceFrom(icon_data,
+                                       icon_w,
+                                       icon_h,
+                                       24,
+                                       icon_w * 3,
+                                       0xff << 0,
+                                       0xff << 8,
+                                       0xff << 16,
+                                       0);
+
+    SDL_WM_SetIcon(surface, mask);
+    SDL_FreeSurface(surface);
+    free(mask);
+}
+
+// Pick the modes list to use:
+
+static void GetScreenModes(screen_mode_t ***modes_list, int *num_modes)
+{
+    if (aspect_ratio_correct)
+    {
+        *modes_list = screen_modes_corrected;
+        *num_modes = arrlen(screen_modes_corrected);
+    }
+    else
+    {
+        *modes_list = screen_modes;
+        *num_modes = arrlen(screen_modes);
+    }
+}
+
+// Find which screen_mode_t to use for the given width and height.
+
+static screen_mode_t *I_FindScreenMode(int w, int h)
+{
+    screen_mode_t **modes_list;
+    screen_mode_t *best_mode;
+    int modes_list_length;
+    int num_pixels;
+    int best_num_pixels;
+    int i;
+
+    // Special case: 320x200 and 640x400 are available even if aspect 
+    // ratio correction is turned on.  These modes have non-square
+    // pixels.
+
+    if (fullscreen)
+    {
+        if (w == SCREENWIDTH && h == SCREENHEIGHT)
+        {
+            return &mode_scale_1x;
+        }
+        else if (w == SCREENWIDTH*2 && h == SCREENHEIGHT*2)
+        {
+            return &mode_scale_2x;
+        }
+    }
+
+    GetScreenModes(&modes_list, &modes_list_length);
+
+    // Find the biggest screen_mode_t in the list that fits within these 
+    // dimensions
+
+    best_mode = NULL;
+    best_num_pixels = 0;
+
+    for (i=0; i<modes_list_length; ++i) 
+    {
+        // Will this fit within the dimensions? If not, ignore.
+
+        if (modes_list[i]->width > w || modes_list[i]->height > h)
+        {
+            continue;
+        }
+
+        num_pixels = modes_list[i]->width * modes_list[i]->height;
+
+        if (num_pixels > best_num_pixels)
+        {
+            // This is a better mode than the current one
+
+            best_mode = modes_list[i];
+            best_num_pixels = num_pixels;
+        }
+    }
+
+    return best_mode;
+}
+
+// Adjust to an appropriate fullscreen mode.
+// Returns true if successful.
+
+static boolean AutoAdjustFullscreen(void)
+{
+    SDL_Rect **modes;
+    SDL_Rect *best_mode;
+    screen_mode_t *screen_mode;
+    int diff, best_diff;
+    int i;
+
+    modes = SDL_ListModes(NULL, SDL_FULLSCREEN);
+
+    // No fullscreen modes available at all?
+
+    if (modes == NULL || modes == (SDL_Rect **) -1 || *modes == NULL)
+    {
+        return false;
+    }
+
+    // Find the best mode that matches the mode specified in the
+    // configuration file
+
+    best_mode = NULL;
+    best_diff = INT_MAX;
+
+    for (i=0; modes[i] != NULL; ++i)
+    {
+        //printf("%ix%i?\n", modes[i]->w, modes[i]->h);
+
+        // What screen_mode_t would be used for this video mode?
+
+        screen_mode = I_FindScreenMode(modes[i]->w, modes[i]->h);
+
+        // Never choose a screen mode that we cannot run in, or
+        // is poor quality for fullscreen
+
+        if (screen_mode == NULL || screen_mode->poor_quality)
+        {
+        //    printf("\tUnsupported / poor quality\n");
+            continue;
+        }
+
+        // Do we have the exact mode?
+        // If so, no autoadjust needed
+
+        if (screen_width == modes[i]->w && screen_height == modes[i]->h)
+        {
+        //    printf("\tExact mode!\n");
+            return true;
+        }
+
+        // Is this mode better than the current mode?
+
+        diff = (screen_width - modes[i]->w) * (screen_width - modes[i]->w)
+             + (screen_height - modes[i]->h) * (screen_height - modes[i]->h);
+
+        if (diff < best_diff)
+        {
+        //    printf("\tA valid mode\n");
+            best_mode = modes[i];
+            best_diff = diff;
+        }
+    }
+
+    if (best_mode == NULL)
+    {
+        // Unable to find a valid mode!
+
+        return false;
+    }
+
+    printf("I_InitGraphics: %ix%i mode not supported on this machine.\n",
+           screen_width, screen_height);
+
+    screen_width = best_mode->w;
+    screen_height = best_mode->h;
+
+    return true;
+}
+
+// Auto-adjust to a valid windowed mode.
+
+static void AutoAdjustWindowed(void)
+{
+    screen_mode_t *best_mode;
+
+    // Find a screen_mode_t to fit within the current settings
+
+    best_mode = I_FindScreenMode(screen_width, screen_height);
+
+    if (best_mode == NULL)
+    {
+        // Nothing fits within the current settings.
+        // Pick the closest to 320x200 possible.
+
+        best_mode = I_FindScreenMode(SCREENWIDTH, SCREENHEIGHT_4_3);
+    }
+
+    // Switch to the best mode if necessary.
+
+    if (best_mode->width != screen_width || best_mode->height != screen_height)
+    {
+        printf("I_InitGraphics: Cannot run at specified mode: %ix%i\n",
+               screen_width, screen_height);
+
+        screen_width = best_mode->width;
+        screen_height = best_mode->height;
+    }
+}
+
+// Auto-adjust to a valid color depth.
+
+static void AutoAdjustColorDepth(void)
+{
+    SDL_Rect **modes;
+    SDL_PixelFormat format;
+    const SDL_VideoInfo *info;
+    int flags;
+
+    // If screen_bpp=0, we should use the current (default) pixel depth.
+    // Fetch it from SDL.
+
+    if (screen_bpp == 0)
+    {
+        info = SDL_GetVideoInfo();
+
+        if (info != NULL && info->vfmt != NULL)
+        {
+            screen_bpp = info->vfmt->BitsPerPixel;
+        }
+    }
+
+    if (fullscreen)
+    {
+        flags = SDL_FULLSCREEN;
+    }
+    else
+    {
+        flags = 0;
+    }
+
+    format.BitsPerPixel = screen_bpp;
+    format.BytesPerPixel = (screen_bpp + 7) / 8;
+
+    // Are any screen modes supported at the configured color depth?
+
+    modes = SDL_ListModes(&format, flags);
+
+    // If not, we must autoadjust to something sensible.
+
+    if (modes == NULL)
+    {
+        printf("I_InitGraphics: %ibpp color depth not supported.\n",
+               screen_bpp);
+
+        info = SDL_GetVideoInfo();
+
+        if (info != NULL && info->vfmt != NULL)
+        {
+            screen_bpp = info->vfmt->BitsPerPixel;
+        }
+    }
+}
+
+// If the video mode set in the configuration file is not available,
+// try to choose a different mode.
+
+static void I_AutoAdjustSettings(void)
+{
+    int old_screen_w, old_screen_h, old_screen_bpp;
+
+    old_screen_w = screen_width;
+    old_screen_h = screen_height;
+    old_screen_bpp = screen_bpp;
+
+    // Possibly adjust color depth.
+
+    AutoAdjustColorDepth();
+
+    // If we are running fullscreen, try to autoadjust to a valid fullscreen
+    // mode.  If this is impossible, switch to windowed.
+
+    if (fullscreen && !AutoAdjustFullscreen())
+    {
+        fullscreen = 0;
+    }
+
+    // If we are running windowed, pick a valid window size.
+
+    if (!fullscreen)
+    {
+        AutoAdjustWindowed();
+    }
+
+    // Have the settings changed?  Show a message.
+
+    if (screen_width != old_screen_w || screen_height != old_screen_h
+     || screen_bpp != old_screen_bpp)
+    {
+        printf("I_InitGraphics: Auto-adjusted to %ix%ix%ibpp.\n",
+               screen_width, screen_height, screen_bpp);
+
+        printf("NOTE: Your video settings have been adjusted.  "
+               "To disable this behavior,\n"
+               "set autoadjust_video_settings to 0 in your "
+               "configuration file.\n");
+    }
+}
+
+// Set video size to a particular scale factor (1x, 2x, 3x, etc.)
+
+static void SetScaleFactor(int factor)
+{
+    int w, h;
+
+    // Pick 320x200 or 320x240, depending on aspect ratio correct
+
+    if (aspect_ratio_correct)
+    {
+        w = SCREENWIDTH;
+        h = SCREENHEIGHT_4_3;
+    }
+    else
+    {
+        w = SCREENWIDTH;
+        h = SCREENHEIGHT;
+    }
+
+    screen_width = w * factor;
+    screen_height = h * factor;
+}
+
+void I_GraphicsCheckCommandLine(void)
+{
+    int i;
+
+    //!
+    // @vanilla
+    //
+    // Disable blitting the screen.
+    //
+
+    noblit = M_CheckParm ("-noblit"); 
+
+    //!
+    // @category video 
+    //
+    // Grab the mouse when running in windowed mode.
+    //
+
+    if (M_CheckParm("-grabmouse"))
+    {
+        grabmouse = true;
+    }
+
+    //!
+    // @category video 
+    //
+    // Don't grab the mouse when running in windowed mode.
+    //
+
+    if (M_CheckParm("-nograbmouse"))
+    {
+        grabmouse = false;
+    }
+
+    // default to fullscreen mode, allow override with command line
+    // nofullscreen because we love prboom
+
+    //!
+    // @category video 
+    //
+    // Run in a window.
+    //
+
+    if (M_CheckParm("-window") || M_CheckParm("-nofullscreen"))
+    {
+        fullscreen = false;
+    }
+
+    //!
+    // @category video 
+    //
+    // Run in fullscreen mode.
+    //
+
+    if (M_CheckParm("-fullscreen"))
+    {
+        fullscreen = true;
+    }
+
+    //!
+    // @category video 
+    //
+    // Disable the mouse.
+    //
+
+    nomouse = M_CheckParm("-nomouse") > 0;
+
+    //!
+    // @category video
+    // @arg <x>
+    //
+    // Specify the screen width, in pixels.
+    //
+
+    i = M_CheckParmWithArgs("-width", 1);
+
+    if (i > 0)
+    {
+        screen_width = atoi(myargv[i + 1]);
+    }
+
+    //!
+    // @category video
+    // @arg <y>
+    //
+    // Specify the screen height, in pixels.
+    //
+
+    i = M_CheckParmWithArgs("-height", 1);
+
+    if (i > 0)
+    {
+        screen_height = atoi(myargv[i + 1]);
+    }
+
+    //!
+    // @category video
+    // @arg <bpp>
+    //
+    // Specify the color depth of the screen, in bits per pixel.
+    //
+
+    i = M_CheckParmWithArgs("-bpp", 1);
+
+    if (i > 0)
+    {
+        screen_bpp = atoi(myargv[i + 1]);
+    }
+
+    // Because we love Eternity:
+
+    //!
+    // @category video
+    //
+    // Set the color depth of the screen to 32 bits per pixel.
+    //
+
+    if (M_CheckParm("-8in32"))
+    {
+        screen_bpp = 32;
+    }
+
+    //!
+    // @category video
+    // @arg <WxY>[wf]
+    //
+    // Specify the dimensions of the window or fullscreen mode.  An
+    // optional letter of w or f appended to the dimensions selects
+    // windowed or fullscreen mode.
+
+    i = M_CheckParmWithArgs("-geometry", 1);
+
+    if (i > 0)
+    {
+        int w, h, s;
+        char f;
+
+        s = sscanf(myargv[i + 1], "%ix%i%1c", &w, &h, &f);
+        if (s == 2 || s == 3)
+        {
+            screen_width = w;
+            screen_height = h;
+
+            if (s == 3 && f == 'f')
+            {
+                fullscreen = true;
+            }
+            else if (s == 3 && f == 'w')
+            {
+                fullscreen = false;
+            }
+        }
+    }
+
+    //!
+    // @category video
+    //
+    // Don't scale up the screen.
+    //
+
+    if (M_CheckParm("-1")) 
+    {
+        SetScaleFactor(1);
+    }
+
+    //!
+    // @category video
+    //
+    // Double up the screen to 2x its normal size.
+    //
+
+    if (M_CheckParm("-2")) 
+    {
+        SetScaleFactor(2);
+    }
+
+    //!
+    // @category video
+    //
+    // Double up the screen to 3x its normal size.
+    //
+
+    if (M_CheckParm("-3")) 
+    {
+        SetScaleFactor(3);
+    }
+
+    //!
+    // @category video
+    //
+    // Disable vertical mouse movement.
+    //
+
+    if (M_CheckParm("-novert"))
+    {
+        novert = true;
+    }
+
+    //!
+    // @category video
+    //
+    // Enable vertical mouse movement.
+    //
+
+    if (M_CheckParm("-nonovert"))
+    {
+        novert = false;
+    }
+}
+
+// Check if we have been invoked as a screensaver by xscreensaver.
+
+void I_CheckIsScreensaver(void)
+{
+    char *env;
+
+    env = getenv("XSCREENSAVER_WINDOW");
+
+    if (env != NULL)
+    {
+        screensaver_mode = true;
+    }
+}
+
+static void CreateCursors(void)
+{
+    static Uint8 empty_cursor_data = 0;
+
+    // Save the default cursor so it can be recalled later
+
+    cursors[1] = SDL_GetCursor();
+
+    // Create an empty cursor
+
+    cursors[0] = SDL_CreateCursor(&empty_cursor_data,
+                                  &empty_cursor_data,
+                                  1, 1, 0, 0);
+}
+
+static void SetSDLVideoDriver(void)
+{
+    // Allow a default value for the SDL video driver to be specified
+    // in the configuration file.
+
+    if (strcmp(video_driver, "") != 0)
+    {
+        char *env_string;
+
+        env_string = M_StringJoin("SDL_VIDEODRIVER=", video_driver, NULL);
+        putenv(env_string);
+        free(env_string);
+    }
+}
+
+static void SetWindowPositionVars(void)
+{
+    char buf[64];
+    int x, y;
+
+    if (window_position == NULL || !strcmp(window_position, ""))
+    {
+        return;
+    }
+
+    if (!strcmp(window_position, "center"))
+    {
+        putenv("SDL_VIDEO_CENTERED=1");
+    }
+    else if (sscanf(window_position, "%i,%i", &x, &y) == 2)
+    {
+        M_snprintf(buf, sizeof(buf), "SDL_VIDEO_WINDOW_POS=%i,%i", x, y);
+        putenv(buf);
+    }
+}
+
+static char *WindowBoxType(screen_mode_t *mode, int w, int h)
+{
+    if (mode->width != w && mode->height != h) 
+    {
+        return "Windowboxed";
+    }
+    else if (mode->width == w) 
+    {
+        return "Letterboxed";
+    }
+    else if (mode->height == h)
+    {
+        return "Pillarboxed";
+    }
+    else
+    {
+        return "...";
+    }
+}
+
+static void SetVideoMode(screen_mode_t *mode, int w, int h)
+{
+    byte *doompal;
+    int flags = 0;
+
+    doompal = W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE);
+
+    // If we are already running and in a true color mode, we need
+    // to free the screenbuffer surface before setting the new mode.
+
+    if (screenbuffer != NULL && screen != screenbuffer)
+    {
+        SDL_FreeSurface(screenbuffer);
+    }
+
+    // Generate lookup tables before setting the video mode.
+
+    if (mode != NULL && mode->InitMode != NULL)
+    {
+        mode->InitMode(doompal);
+    }
+
+    // Set the video mode.
+
+    flags |= SDL_SWSURFACE | SDL_DOUBLEBUF;
+
+    if (screen_bpp == 8)
+    {
+        flags |= SDL_HWPALETTE;
+    }
+
+    if (fullscreen)
+    {
+        flags |= SDL_FULLSCREEN;
+    }
+    else
+    {
+        // In windowed mode, the window can be resized while the game is
+        // running.  This feature is disabled on OS X, as it adds an ugly
+        // scroll handle to the corner of the screen.
+
+#ifndef __MACOSX__
+        flags |= SDL_RESIZABLE;
+#endif
+    }
+
+    screen = SDL_SetVideoMode(w, h, screen_bpp, flags);
+
+    if (screen == NULL)
+    {
+        I_Error("Error setting video mode %ix%ix%ibpp: %s\n",
+                w, h, screen_bpp, SDL_GetError());
+    }
+
+    // Blank out the full screen area in case there is any junk in
+    // the borders that won't otherwise be overwritten.
+
+    SDL_FillRect(screen, NULL, 0);
+
+    // If mode was not set, it must be set now that we know the
+    // screen size.
+
+    if (mode == NULL)
+    {
+        mode = I_FindScreenMode(screen->w, screen->h);
+
+        if (mode == NULL)
+        {
+            I_Error("I_InitGraphics: Unable to find a screen mode small "
+                    "enough for %ix%i", screen->w, screen->h);
+        }
+
+        // Generate lookup tables before setting the video mode.
+
+        if (mode->InitMode != NULL)
+        {
+            mode->InitMode(doompal);
+        }
+    }
+
+    // Create the screenbuffer surface; if we have a real 8-bit palettized
+    // screen, then we can use the screen as the screenbuffer.
+
+    if (screen->format->BitsPerPixel == 8)
+    {
+        screenbuffer = screen;
+    }
+    else
+    {
+        screenbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE,
+                                            mode->width, mode->height, 8,
+                                            0, 0, 0, 0);
+
+        SDL_FillRect(screenbuffer, NULL, 0);
+    }
+
+    // Save screen mode.
+
+    screen_mode = mode;
+}
+
+static void ApplyWindowResize(unsigned int w, unsigned int h)
+{
+    screen_mode_t *mode;
+
+    // Find the biggest screen mode that will fall within these
+    // dimensions, falling back to the smallest mode possible if
+    // none is found.
+
+    mode = I_FindScreenMode(w, h);
+
+    if (mode == NULL)
+    {
+        mode = I_FindScreenMode(SCREENWIDTH, SCREENHEIGHT);
+    }
+
+    // Reset mode to resize window.
+
+    printf("Resize to %ix%i\n", mode->width, mode->height);
+    SetVideoMode(mode, mode->width, mode->height);
+
+    // Save settings.
+
+    screen_width = mode->width;
+    screen_height = mode->height;
+}
+
+void I_InitGraphics(void)
+{
+    SDL_Event dummy;
+    byte *doompal;
+    char *env;
+
+    // Pass through the XSCREENSAVER_WINDOW environment variable to 
+    // SDL_WINDOWID, to embed the SDL window into the Xscreensaver
+    // window.
+
+    env = getenv("XSCREENSAVER_WINDOW");
+
+    if (env != NULL)
+    {
+        char winenv[30];
+        int winid;
+
+        sscanf(env, "0x%x", &winid);
+        M_snprintf(winenv, sizeof(winenv), "SDL_WINDOWID=%i", winid);
+
+        putenv(winenv);
+    }
+
+    SetSDLVideoDriver();
+    SetWindowPositionVars();
+
+    if (SDL_Init(SDL_INIT_VIDEO) < 0) 
+    {
+        I_Error("Failed to initialize video: %s", SDL_GetError());
+    }
+
+    // Set up title and icon.  Windows cares about the ordering; this
+    // has to be done before the call to SDL_SetVideoMode.
+
+    I_InitWindowTitle();
+#if !SDL_VERSION_ATLEAST(1, 3, 0)
+    I_InitWindowIcon();
+#endif
+
+    // Warning to OS X users... though they might never see it :(
+#ifdef __MACOSX__
+    if (fullscreen)
+    {
+        printf("Some old versions of OS X might crash in fullscreen mode.\n"
+               "If this happens to you, switch back to windowed mode.\n");
+    }
+#endif
+
+    //
+    // Enter into graphics mode.
+    //
+    // When in screensaver mode, run full screen and auto detect
+    // screen dimensions (don't change video mode)
+    //
+
+    if (screensaver_mode)
+    {
+        SetVideoMode(NULL, 0, 0);
+    }
+    else
+    {
+        int w, h;
+
+        if (autoadjust_video_settings)
+        {
+            I_AutoAdjustSettings();
+        }
+
+        w = screen_width;
+        h = screen_height;
+
+        screen_mode = I_FindScreenMode(w, h);
+
+        if (screen_mode == NULL)
+        {
+            I_Error("I_InitGraphics: Unable to find a screen mode small "
+                    "enough for %ix%i", w, h);
+        }
+
+        if (w != screen_mode->width || h != screen_mode->height)
+        {
+            printf("I_InitGraphics: %s (%ix%i within %ix%i)\n",
+                   WindowBoxType(screen_mode, w, h),
+                   screen_mode->width, screen_mode->height, w, h);
+        }
+
+        SetVideoMode(screen_mode, w, h);
+    }
+
+    // Start with a clear black screen
+    // (screen will be flipped after we set the palette)
+
+    SDL_FillRect(screenbuffer, NULL, 0);
+
+    // Set the palette
+
+    doompal = W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE);
+    I_SetPalette(doompal);
+    SDL_SetColors(screenbuffer, palette, 0, 256);
+
+    CreateCursors();
+
+    UpdateFocus();
+    UpdateGrab();
+
+    // On some systems, it takes a second or so for the screen to settle
+    // after changing modes.  We include the option to add a delay when
+    // setting the screen mode, so that the game doesn't start immediately
+    // with the player unable to see anything.
+
+    if (fullscreen && !screensaver_mode)
+    {
+        SDL_Delay(startup_delay);
+    }
+
+    // Check if we have a native surface we can use
+    // If we have to lock the screen, draw to a buffer and copy
+    // Likewise if the screen pitch is not the same as the width
+    // If we have to multiply, drawing is done to a separate 320x200 buf
+
+    native_surface = screen == screenbuffer
+                  && !SDL_MUSTLOCK(screen)
+                  && screen_mode == &mode_scale_1x
+                  && screen->pitch == SCREENWIDTH
+                  && aspect_ratio_correct;
+
+    // If not, allocate a buffer and copy from that buffer to the
+    // screen when we do an update
+
+    if (native_surface)
+    {
+       I_VideoBuffer = (unsigned char *) screen->pixels;
+
+        I_VideoBuffer += (screen->h - SCREENHEIGHT) / 2;
+    }
+    else
+    {
+       I_VideoBuffer = (unsigned char *) Z_Malloc (SCREENWIDTH * SCREENHEIGHT, 
+                                                    PU_STATIC, NULL);
+    }
+
+    V_RestoreBuffer();
+
+    // Clear the screen to black.
+
+    memset(I_VideoBuffer, 0, SCREENWIDTH * SCREENHEIGHT);
+
+    // We need SDL to give us translated versions of keys as well
+
+    SDL_EnableUNICODE(1);
+
+    // Repeat key presses - this is what Vanilla Doom does
+    // Not sure about repeat rate - probably dependent on which DOS
+    // driver is used.  This is good enough though.
+
+    SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
+
+    // clear out any events waiting at the start and center the mouse
+  
+    while (SDL_PollEvent(&dummy));
+
+    initialized = true;
+
+    // Call I_ShutdownGraphics on quit
+
+    I_AtExit(I_ShutdownGraphics, true);
 }
 
+// Bind all variables controlling video options into the configuration
+// file system.
+
+void I_BindVideoVariables(void)
+{
+    M_BindVariable("use_mouse",                 &usemouse);
+    M_BindVariable("autoadjust_video_settings", &autoadjust_video_settings);
+    M_BindVariable("fullscreen",                &fullscreen);
+    M_BindVariable("aspect_ratio_correct",      &aspect_ratio_correct);
+    M_BindVariable("startup_delay",             &startup_delay);
+    M_BindVariable("screen_width",              &screen_width);
+    M_BindVariable("screen_height",             &screen_height);
+    M_BindVariable("screen_bpp",                &screen_bpp);
+    M_BindVariable("grabmouse",                 &grabmouse);
+    M_BindVariable("mouse_acceleration",        &mouse_acceleration);
+    M_BindVariable("mouse_threshold",           &mouse_threshold);
+    M_BindVariable("video_driver",              &video_driver);
+    M_BindVariable("window_position",           &window_position);
+    M_BindVariable("usegamma",                  &usegamma);
+    M_BindVariable("vanilla_keyboard_mapping",  &vanilla_keyboard_mapping);
+    M_BindVariable("novert",                    &novert);
+    M_BindVariable("png_screenshots",           &png_screenshots);
+
+    // Windows Vista or later?  Set screen color depth to
+    // 32 bits per pixel, as 8-bit palettized screen modes
+    // don't work properly in recent versions.
+
+#if defined(_WIN32) && !defined(_WIN32_WCE)
+    {
+        OSVERSIONINFOEX version_info;
+
+        ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX));
+        version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+
+        GetVersionEx((OSVERSIONINFO *) &version_info);
+
+        if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT
+         && version_info.dwMajorVersion >= 6)
+        {
+            screen_bpp = 32;
+        }
+    }
+#endif
+
+    // Disable fullscreen by default on OS X, as there is an SDL bug
+    // where some old versions of OS X (<= Snow Leopard) crash.
 
+#ifdef __MACOSX__
+    fullscreen = 0;
+    screen_width = 800;
+    screen_height = 600;
+#endif
+}
index ba8569b228f24626d7879ee1b5a4b787cf0afc55..3c7db198dc0732a01b7f161a8d13ae1973cd959b 100644 (file)
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     System specific interface stuff.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __I_VIDEO__
 #define __I_VIDEO__
 
-
 #include "doomtype.h"
 
-#ifdef __GNUG__
-#pragma interface
-#endif
-
+// Screen width and height.
+
+#define SCREENWIDTH  320
+#define SCREENHEIGHT 200
+
+// Screen width used for "squash" scale functions
+
+#define SCREENWIDTH_4_3 256
+
+// Screen height used for "stretch" scale functions.
+
+#define SCREENHEIGHT_4_3 240
+
+#define MAX_MOUSE_BUTTONS 8
+
+typedef struct
+{
+    // Screen width and height
+
+    int width;
+    int height;
+
+    // Initialisation function to call when using this mode.
+    // Called with a pointer to the Doom palette.
+    //
+    // If NULL, no init function is called.
+
+    void (*InitMode)(byte *palette);
+    
+    // Function to call to draw the screen from the source buffer.
+    // Return true if draw was successful.
+
+    boolean (*DrawScreen)(int x1, int y1, int x2, int y2);
+
+    // If true, this is a "poor quality" mode.  The autoadjust
+    // code should always attempt to use a different mode to this
+    // mode in fullscreen.
+    //
+    // Some notes about what "poor quality" means in this context:
+    //
+    // The aspect ratio correction works by scaling up to the larger
+    // screen size and then drawing pixels on the edges between the
+    // "virtual" pixels so that an authentic blocky look-and-feel is
+    // achieved.
+    //
+    // For a mode like 640x480, you can imagine the grid of the
+    // "original" pixels spaced out, with extra "blurry" pixels added
+    // in the space between them to fill it out. However, when you're
+    // running at a resolution like 320x240, this is not the case. In
+    // the small screen case, every single pixel has to be a blurry
+    // interpolation of two pixels from the original image.
+    //
+    // If you run in 320x240 and put your face up close to the screen
+    // you can see this: it's particularly visible in the small yellow
+    // status bar numbers for example. Overall it still looks "okay"
+    // but there's an obvious - albeit small - deterioration in
+    // quality.
+    //
+    // Once you get to 640x480, all the original pixels are there at
+    // least once and it's okay (the higher the resolution, the more
+    // accurate it is). When I first wrote the code I was expecting
+    // that even higher resolutions would be needed before it would
+    // look acceptable, but it turned out to be okay even at 640x480.
+
+    boolean poor_quality;
+} screen_mode_t;
+
+typedef boolean (*grabmouse_callback_t)(void);
 
 // Called by D_DoomMain,
 // determines the hardware configuration
 // and sets up the video mode
 void I_InitGraphics (void);
 
+void I_GraphicsCheckCommandLine(void);
 
 void I_ShutdownGraphics(void);
 
 // Takes full 8 bit values.
 void I_SetPalette (byte* palette);
+int I_GetPaletteIndex(int r, int g, int b);
 
 void I_UpdateNoBlit (void);
 void I_FinishUpdate (void);
 
-// Wait for vertical retrace or pause a bit.
-void I_WaitVBL(int count);
-
 void I_ReadScreen (byte* scr);
 
 void I_BeginRead (void);
-void I_EndRead (void);
 
+void I_SetWindowTitle(char *title);
+
+void I_CheckIsScreensaver(void);
+void I_SetGrabMouseCallback(grabmouse_callback_t func);
+
+void I_DisplayFPSDots(boolean dots_on);
+void I_BindVideoVariables(void);
+
+void I_InitWindowTitle(void);
+void I_InitWindowIcon(void);
+
+// Called before processing any tics in a frame (just after displaying a frame).
+// Time consuming syncronous operations are performed here (joystick reading).
+
+void I_StartFrame (void);
 
+// Called before processing each tic in a frame.
+// Quick syncronous operations are performed here.
+
+void I_StartTic (void);
+
+// Enable the loading disk image displayed when reading from disk.
+
+void I_EnableLoadingDisk(void);
+
+extern char *video_driver;
+extern boolean screenvisible;
+
+extern float mouse_acceleration;
+extern int mouse_threshold;
+extern int vanilla_keyboard_mapping;
+extern boolean screensaver_mode;
+extern int usegamma;
+extern byte *I_VideoBuffer;
+
+extern int screen_width;
+extern int screen_height;
+extern int screen_bpp;
+extern int fullscreen;
+extern int aspect_ratio_correct;
+
+extern int show_diskicon;
+extern int diskicon_readbytes;
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
diff --git a/frosted-doom/i_video_SDL.c b/frosted-doom/i_video_SDL.c
deleted file mode 100644 (file)
index 9d3ebb2..0000000
+++ /dev/null
@@ -1,756 +0,0 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
-//
-// $Id:$
-//
-// Copyright (C) 1993-1996 by id Software, Inc.
-//
-// This source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
-//
-// DESCRIPTION:
-//     DOOM graphics stuff for X11, UNIX.
-//
-//-----------------------------------------------------------------------------
-
-static const char
-rcsid[] = "$Id: i_x.c,v 1.6 1997/02/03 22:45:10 b1 Exp $";
-
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <stdarg.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <netinet/in.h>
-#include <errno.h>
-#include <signal.h>
-
-#include <SDL2/SDL.h>
-
-#include "doomstat.h"
-#include "i_system.h"
-#include "v_video.h"
-#include "m_argv.h"
-#include "d_main.h"
-
-#include "doomdef.h"
-
-SDL_Window *window = NULL;
-SDL_Surface *screen = NULL;
-SDL_Surface *rgbsurf = NULL;
-
-int            X_width;
-int            X_height;
-
-void I_ShutdownGraphics(void)
-{
-    printf("I_ShutdownGraphics\n");
-    // Always be sure to clean up
-    SDL_Quit();
-}
-
-
-//
-// I_StartFrame
-//
-void I_StartFrame (void)
-{
-    // er?
-
-}
-
-void I_GetEvent(void)
-{
-    /* An SDL_Event */
-    SDL_Event event;
-    while (SDL_PollEvent(&event))
-    {
-        /* If a quit event has been sent */
-        if (event.type == SDL_QUIT)
-        {
-            /* Quit the application */
-            I_Quit();
-        }
-        if (event.type == SDL_WINDOWEVENT)
-        {
-            switch (event.window.event)
-            {
-                case SDL_WINDOWEVENT_CLOSE:
-                    SDL_Log("Window %d closed", event.window.windowID);
-                    break;
-                default:
-                    break;
-            }
-        }
-    }
-    /*
-    event_t event;
-
-    // put event-grabbing stuff in here
-    XNextEvent(X_display, &X_event);
-    switch (X_event.type)
-    {
-      case KeyPress:
-       event.type = ev_keydown;
-       event.data1 = xlatekey();
-       D_PostEvent(&event);
-       // fprintf(stderr, "k");
-       break;
-      case KeyRelease:
-       event.type = ev_keyup;
-       event.data1 = xlatekey();
-       D_PostEvent(&event);
-       // fprintf(stderr, "ku");
-       break;
-      case ButtonPress:
-       event.type = ev_mouse;
-       event.data1 =
-           (X_event.xbutton.state & Button1Mask)
-           | (X_event.xbutton.state & Button2Mask ? 2 : 0)
-           | (X_event.xbutton.state & Button3Mask ? 4 : 0)
-           | (X_event.xbutton.button == Button1)
-           | (X_event.xbutton.button == Button2 ? 2 : 0)
-           | (X_event.xbutton.button == Button3 ? 4 : 0);
-       event.data2 = event.data3 = 0;
-       D_PostEvent(&event);
-       // fprintf(stderr, "b");
-       break;
-      case ButtonRelease:
-       event.type = ev_mouse;
-       event.data1 =
-           (X_event.xbutton.state & Button1Mask)
-           | (X_event.xbutton.state & Button2Mask ? 2 : 0)
-           | (X_event.xbutton.state & Button3Mask ? 4 : 0);
-       // suggest parentheses around arithmetic in operand of |
-       event.data1 =
-           event.data1
-           ^ (X_event.xbutton.button == Button1 ? 1 : 0)
-           ^ (X_event.xbutton.button == Button2 ? 2 : 0)
-           ^ (X_event.xbutton.button == Button3 ? 4 : 0);
-       event.data2 = event.data3 = 0;
-       D_PostEvent(&event);
-       // fprintf(stderr, "bu");
-       break;
-      case MotionNotify:
-       event.type = ev_mouse;
-       event.data1 =
-           (X_event.xmotion.state & Button1Mask)
-           | (X_event.xmotion.state & Button2Mask ? 2 : 0)
-           | (X_event.xmotion.state & Button3Mask ? 4 : 0);
-       event.data2 = (X_event.xmotion.x - lastmousex) << 2;
-       event.data3 = (lastmousey - X_event.xmotion.y) << 2;
-
-       if (event.data2 || event.data3)
-       {
-           lastmousex = X_event.xmotion.x;
-           lastmousey = X_event.xmotion.y;
-           if (X_event.xmotion.x != X_width/2 &&
-               X_event.xmotion.y != X_height/2)
-           {
-               D_PostEvent(&event);
-               // fprintf(stderr, "m");
-               mousemoved = false;
-           } else
-           {
-               mousemoved = true;
-           }
-       }
-       break;
-       
-      case Expose:
-      case ConfigureNotify:
-       break;
-       
-      default:
-       if (doShm && X_event.type == X_shmeventtype) shmFinished = true;
-       break;
-    }
-    */
-
-}
-
-// Cursor
-// createnullcursor
-// ( Display*  display,
-//   Window    root )
-// {
-//     Pixmap cursormask;
-//     XGCValues xgc;
-//     GC gc;
-//     XColor dummycolour;
-//     Cursor cursor;
-// 
-//     cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
-//     xgc.function = GXclear;
-//     gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
-//     XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
-//     dummycolour.pixel = 0;
-//     dummycolour.red = 0;
-//     dummycolour.flags = 04;
-//     cursor = XCreatePixmapCursor(display, cursormask, cursormask,
-//                              &dummycolour,&dummycolour, 0,0);
-//     XFreePixmap(display,cursormask);
-//     XFreeGC(display,gc);
-//     return cursor;
-// }
-
-//
-// I_StartTic
-//
-void I_StartTic (void)
-{
-
-    return;
-
-    /*
-
-    if (!X_display)
-       return;
-
-    while (XPending(X_display))
-       I_GetEvent();
-
-    // Warp the pointer back to the middle of the window
-    //  or it will wander off - that is, the game will
-    //  loose input focus within X11.
-    if (grabMouse)
-    {
-       if (!--doPointerWarp)
-       {
-           XWarpPointer( X_display,
-                         None,
-                         X_mainWindow,
-                         0, 0,
-                         0, 0,
-                         X_width/2, X_height/2);
-
-           doPointerWarp = POINTER_WARP_COUNTDOWN;
-       }
-    }
-
-    mousemoved = false;
-    */
-
-}
-
-
-//
-// I_UpdateNoBlit
-//
-void I_UpdateNoBlit (void)
-{
-    // what is this?
-}
-
-//
-// I_FinishUpdate
-//
-void I_FinishUpdate (void)
-{
-    static int lasttic;
-    int                tics;
-    int                i;
-
-    // draws little dots on the bottom of the screen
-    if (devparm)
-    {
-        i = I_GetTime();
-        tics = i - lasttic;
-        lasttic = i;
-        if (tics > 20) tics = 20;
-
-        for (i=0 ; i<tics*2 ; i+=2)
-            screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0xff;
-        for ( ; i<20*2 ; i+=2)
-            screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0;
-    }
-
-    /* DRAW SCREEN */
-    //if (multiply == 1)
-    {
-        unsigned char *line_out;
-        unsigned char *line_in;
-        int y;
-
-        line_in = (unsigned char *) screens[0];
-        line_out = (unsigned char *) rgbsurf->pixels;
-
-        y = SCREENHEIGHT;
-        while (y--)
-        {
-            memcpy(line_out, line_in, rgbsurf->w);
-            line_in += SCREENWIDTH;
-            line_out += rgbsurf->pitch;
-        }
-    }
-
-    /* LOCK SCREEN */
-    if (SDL_MUSTLOCK(screen)) {
-        if (SDL_LockSurface(screen) < 0) {
-            return;
-        }
-    }
-
-    /* BLIT to SCREEN */
-    SDL_BlitSurface(rgbsurf, NULL, screen, NULL); // blit it to the screen
-
-    /* UNLOCK SCREEN */
-    if ( SDL_MUSTLOCK(screen) ) {
-        SDL_UnlockSurface(screen);
-    }
-
-    SDL_UpdateWindowSurface(window);
-
-}
-
-
-//
-// I_ReadScreen
-//
-void I_ReadScreen (byte* scr)
-{
-    printf("I_ReadScreen\n");
-    memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT);
-    //memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT);
-}
-
-
-//
-// I_SetPalette
-//
-void I_SetPalette (byte* palette)
-{
-    SDL_Color colors[256];
-
-    printf("I_SetPalette\n");
-
-    for (int i=0; i<256; ++i ) {
-        colors[i].r = gammatable[usegamma][*palette++];
-        colors[i].g = gammatable[usegamma][*palette++];
-        colors[i].b = gammatable[usegamma][*palette++];
-    }
-
-    if(rgbsurf->format->BitsPerPixel!=8){
-        printf("Not an 8-bit surface.\n");
-        return;
-    }
-
-    int j = SDL_SetPaletteColors(rgbsurf->format->palette, colors, 0, 256);
-    printf("SDL_SetPaletteColors: %i\n", j);
-}
-
-void I_InitGraphics(void)
-{
-    uint32_t video_flags = 0;
-
-    //video_flags = (SDL_SWSURFACE|SDL_HWPALETTE);
-    if (M_CheckParm("-fullscreen"))
-        video_flags |= SDL_WINDOW_FULLSCREEN;
-
-    X_width = SCREENWIDTH;
-    X_height = SCREENHEIGHT;
-
-    printf("I_InitGraphics: w x h: %d x %d\n", X_width, X_height);
-
-    // Initialize SDL.
-    if (SDL_Init(SDL_INIT_VIDEO) < 0)
-    {
-        printf("SDL_Init failed\n");
-        return;
-    }
-
-    // Create the window where we will draw.
-    window = SDL_CreateWindow("fDOOM v1.0",
-            SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
-            X_width, X_height,
-            video_flags);
-
-    screen = SDL_GetWindowSurface(window);
-    rgbsurf = SDL_CreateRGBSurface(0,X_width,X_height,8,0,0,0,0);
-
-    screens[0] = (unsigned char *)screen->pixels;
-
-    /* Blit shit to the screen */
-    // image = SDL_LoadBMP("box.bmp"); // loads image
-    // SDL_BlitSurface(image, NULL, screen, NULL); // blit it to the screen
-    // SDL_FreeSurface(image);
-    // SDL_UpdateWindowSurface(window);
-    
-    signal(SIGINT, (void (*)(int)) I_Quit);
-
-    return;
-
-    /*
-    char*              displayname;
-    char*              d;
-    int                        n;
-    int                        pnum;
-    int                        x=0;
-    int                        y=0;
-    
-    // warning: char format, different type arg
-    char               xsign=' ';
-    char               ysign=' ';
-    
-    int                        oktodraw;
-    unsigned long      attribmask;
-    XSetWindowAttributes attribs;
-    XGCValues          xgcvalues;
-    int                        valuemask;
-    static int         firsttime=1;
-
-    if (!firsttime)
-       return;
-    firsttime = 0;
-
-    signal(SIGINT, (void (*)(int)) I_Quit);
-
-    if (M_CheckParm("-2"))
-       multiply = 2;
-
-    if (M_CheckParm("-3"))
-       multiply = 3;
-
-    if (M_CheckParm("-4"))
-       multiply = 4;
-
-    X_width = SCREENWIDTH * multiply;
-    X_height = SCREENHEIGHT * multiply;
-
-    // check for command-line display name
-    if ( (pnum=M_CheckParm("-disp")) ) // suggest parentheses around assignment
-       displayname = myargv[pnum+1];
-    else
-       displayname = 0;
-
-    // check if the user wants to grab the mouse (quite unnice)
-    grabMouse = !!M_CheckParm("-grabmouse");
-
-    // check for command-line geometry
-    if ( (pnum=M_CheckParm("-geom")) ) // suggest parentheses around assignment
-    {
-       // warning: char format, different type arg 3,5
-       n = sscanf(myargv[pnum+1], "%c%d%c%d", &xsign, &x, &ysign, &y);
-       
-       if (n==2)
-           x = y = 0;
-       else if (n==6)
-       {
-           if (xsign == '-')
-               x = -x;
-           if (ysign == '-')
-               y = -y;
-       }
-       else
-           I_Error("bad -geom parameter");
-    }
-
-    // open the display
-    X_display = XOpenDisplay(displayname);
-    if (!X_display)
-    {
-       if (displayname)
-           I_Error("Could not open display [%s]", displayname);
-       else
-           I_Error("Could not open display (DISPLAY=[%s])", getenv("DISPLAY"));
-    }
-
-    // use the default visual 
-    X_screen = DefaultScreen(X_display);
-    if (!XMatchVisualInfo(X_display, X_screen, 8, PseudoColor, &X_visualinfo))
-       I_Error("xdoom currently only supports 256-color PseudoColor screens");
-    X_visual = X_visualinfo.visual;
-
-    // check for the MITSHM extension
-    doShm = XShmQueryExtension(X_display);
-
-    // even if it's available, make sure it's a local connection
-    if (doShm)
-    {
-       if (!displayname) displayname = (char *) getenv("DISPLAY");
-       if (displayname)
-       {
-           d = displayname;
-           while (*d && (*d != ':')) d++;
-           if (*d) *d = 0;
-           if (!(!strcasecmp(displayname, "unix") || !*displayname)) doShm = false;
-       }
-    }
-
-    fprintf(stderr, "Using MITSHM extension\n");
-
-    // create the colormap
-    X_cmap = XCreateColormap(X_display, RootWindow(X_display,
-                                                  X_screen), X_visual, AllocAll);
-
-    // setup attributes for main window
-    attribmask = CWEventMask | CWColormap | CWBorderPixel;
-    attribs.event_mask =
-       KeyPressMask
-       | KeyReleaseMask
-       // | PointerMotionMask | ButtonPressMask | ButtonReleaseMask
-       | ExposureMask;
-
-    attribs.colormap = X_cmap;
-    attribs.border_pixel = 0;
-
-    // create the main window
-    X_mainWindow = XCreateWindow(      X_display,
-                                       RootWindow(X_display, X_screen),
-                                       x, y,
-                                       X_width, X_height,
-                                       0, // borderwidth
-                                       8, // depth
-                                       InputOutput,
-                                       X_visual,
-                                       attribmask,
-                                       &attribs );
-
-    XDefineCursor(X_display, X_mainWindow,
-                 createnullcursor( X_display, X_mainWindow ) );
-
-    // create the GC
-    valuemask = GCGraphicsExposures;
-    xgcvalues.graphics_exposures = False;
-    X_gc = XCreateGC(  X_display,
-                       X_mainWindow,
-                       valuemask,
-                       &xgcvalues );
-
-    // map the window
-    XMapWindow(X_display, X_mainWindow);
-
-    // wait until it is OK to draw
-    oktodraw = 0;
-    while (!oktodraw)
-    {
-       XNextEvent(X_display, &X_event);
-       if (X_event.type == Expose
-           && !X_event.xexpose.count)
-       {
-           oktodraw = 1;
-       }
-    }
-
-    // grabs the pointer so it is restricted to this window
-    if (grabMouse)
-       XGrabPointer(X_display, X_mainWindow, True,
-                    ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
-                    GrabModeAsync, GrabModeAsync,
-                    X_mainWindow, None, CurrentTime);
-
-    if (doShm)
-    {
-
-       X_shmeventtype = XShmGetEventBase(X_display) + ShmCompletion;
-
-       // create the image
-       image = XShmCreateImage(        X_display,
-                                       X_visual,
-                                       8,
-                                       ZPixmap,
-                                       0,
-                                       &X_shminfo,
-                                       X_width,
-                                       X_height );
-
-       grabsharedmemory(image->bytes_per_line * image->height);
-
-
-       // UNUSED
-       // create the shared memory segment
-       // X_shminfo.shmid = shmget (IPC_PRIVATE,
-       // image->bytes_per_line * image->height, IPC_CREAT | 0777);
-       // if (X_shminfo.shmid < 0)
-       // {
-       // perror("");
-       // I_Error("shmget() failed in InitGraphics()");
-       // }
-       // fprintf(stderr, "shared memory id=%d\n", X_shminfo.shmid);
-       // attach to the shared memory segment
-       // image->data = X_shminfo.shmaddr = shmat(X_shminfo.shmid, 0, 0);
-       
-
-       if (!image->data)
-       {
-           perror("");
-           I_Error("shmat() failed in InitGraphics()");
-       }
-
-       // get the X server to attach to it
-       if (!XShmAttach(X_display, &X_shminfo))
-           I_Error("XShmAttach() failed in InitGraphics()");
-
-    }
-    else
-    {
-       image = XCreateImage(   X_display,
-                               X_visual,
-                               8,
-                               ZPixmap,
-                               0,
-                               (char*)malloc(X_width * X_height),
-                               X_width, X_height,
-                               8,
-                               X_width );
-
-    }
-
-    if (multiply == 1)
-       screens[0] = (unsigned char *) (image->data);
-    else
-       screens[0] = (unsigned char *) malloc (SCREENWIDTH * SCREENHEIGHT);
-
-    */
-}
-
-
-void InitExpand (void)
-{
-    /*
-    int                i;
-       
-    for (i=0 ; i<256 ; i++)
-       exptable[i] = i | (i<<8) | (i<<16) | (i<<24);
-    */
-}
-
-
-void InitExpand2 (void)
-{
-    return;
-    /*
-    int                i;
-    int                j;
-    // UNUSED unsigned iexp, jexp;
-    double*    exp;
-    union
-    {
-       double          d;
-       unsigned        u[2];
-    } pixel;
-       
-    printf ("building exptable2...\n");
-    exp = exptable2;
-    for (i=0 ; i<256 ; i++)
-    {
-       pixel.u[0] = i | (i<<8) | (i<<16) | (i<<24);
-       for (j=0 ; j<256 ; j++)
-       {
-           pixel.u[1] = j | (j<<8) | (j<<16) | (j<<24);
-           *exp++ = pixel.d;
-       }
-    }
-    printf ("done.\n");
-    */
-}
-
-int    inited;
-
-void
-Expand4
-( unsigned*    lineptr,
-  double*      xline )
-{
-    return;
-    /*
-    double     dpixel;
-    unsigned   x;
-    unsigned   y;
-    unsigned   fourpixels;
-    unsigned   step;
-    double*    exp;
-       
-    exp = exptable2;
-    if (!inited)
-    {
-       inited = 1;
-       InitExpand2 ();
-    }
-               
-               
-    step = 3*SCREENWIDTH/2;
-       
-    y = SCREENHEIGHT-1;
-    do
-    {
-       x = SCREENWIDTH;
-
-       do
-       {
-           fourpixels = lineptr[0];
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
-           xline[0] = dpixel;
-           xline[160] = dpixel;
-           xline[320] = dpixel;
-           xline[480] = dpixel;
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
-           xline[1] = dpixel;
-           xline[161] = dpixel;
-           xline[321] = dpixel;
-           xline[481] = dpixel;
-
-           fourpixels = lineptr[1];
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
-           xline[2] = dpixel;
-           xline[162] = dpixel;
-           xline[322] = dpixel;
-           xline[482] = dpixel;
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
-           xline[3] = dpixel;
-           xline[163] = dpixel;
-           xline[323] = dpixel;
-           xline[483] = dpixel;
-
-           fourpixels = lineptr[2];
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
-           xline[4] = dpixel;
-           xline[164] = dpixel;
-           xline[324] = dpixel;
-           xline[484] = dpixel;
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
-           xline[5] = dpixel;
-           xline[165] = dpixel;
-           xline[325] = dpixel;
-           xline[485] = dpixel;
-
-           fourpixels = lineptr[3];
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
-           xline[6] = dpixel;
-           xline[166] = dpixel;
-           xline[326] = dpixel;
-           xline[486] = dpixel;
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
-           xline[7] = dpixel;
-           xline[167] = dpixel;
-           xline[327] = dpixel;
-           xline[487] = dpixel;
-
-           lineptr+=4;
-           xline+=8;
-       } while (x-=16);
-       xline += step;
-    } while (y--);
-    */
-}
-
-
diff --git a/frosted-doom/i_video_dummy.c b/frosted-doom/i_video_dummy.c
deleted file mode 100644 (file)
index 8981e2c..0000000
+++ /dev/null
@@ -1,919 +0,0 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
-//
-// $Id:$
-//
-// Copyright (C) 1993-1996 by id Software, Inc.
-//
-// This source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
-//
-// DESCRIPTION:
-//     DOOM graphics stuff for X11, UNIX.
-//
-//-----------------------------------------------------------------------------
-
-static const char
-rcsid[] = "$Id: i_x.c,v 1.6 1997/02/03 22:45:10 b1 Exp $";
-
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <stdarg.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <netinet/in.h>
-#include <errno.h>
-#include <signal.h>
-
-#include "doomstat.h"
-#include "i_system.h"
-#include "v_video.h"
-#include "m_argv.h"
-#include "d_main.h"
-
-#include "doomdef.h"
-
-#define POINTER_WARP_COUNTDOWN 1
-
-//Display*     X_display=0;
-//Window               X_mainWindow;
-//Colormap     X_cmap;
-//Visual*              X_visual;
-//GC           X_gc;
-//XEvent               X_event;
-//int              X_screen;
-//XVisualInfo  X_visualinfo;
-//XImage*              image;
-int            X_width;
-int            X_height;
-
-// MIT SHared Memory extension.
-boolean                doShm;
-
-//XShmSegmentInfo      X_shminfo;
-int            X_shmeventtype;
-
-// Fake mouse handling.
-// This cannot work properly w/o DGA.
-// Needs an invisible mouse cursor at least.
-boolean                grabMouse;
-int            doPointerWarp = POINTER_WARP_COUNTDOWN;
-
-// Blocky mode,
-// replace each 320x200 pixel with multiply*multiply pixels.
-// According to Dave Taylor, it still is a bonehead thing
-// to use ....
-static int     multiply=1;
-
-
-//
-//  Translates the key currently in X_event
-//
-
-int xlatekey(void)
-{
-
-    return 0;
-    /*
-    int rc;
-
-    switch(rc = XKeycodeToKeysym(X_display, X_event.xkey.keycode, 0))
-    {
-      case XK_Left:    rc = KEY_LEFTARROW;     break;
-      case XK_Right:   rc = KEY_RIGHTARROW;    break;
-      case XK_Down:    rc = KEY_DOWNARROW;     break;
-      case XK_Up:      rc = KEY_UPARROW;       break;
-      case XK_Escape:  rc = KEY_ESCAPE;        break;
-      case XK_Return:  rc = KEY_ENTER;         break;
-      case XK_Tab:     rc = KEY_TAB;           break;
-      case XK_F1:      rc = KEY_F1;            break;
-      case XK_F2:      rc = KEY_F2;            break;
-      case XK_F3:      rc = KEY_F3;            break;
-      case XK_F4:      rc = KEY_F4;            break;
-      case XK_F5:      rc = KEY_F5;            break;
-      case XK_F6:      rc = KEY_F6;            break;
-      case XK_F7:      rc = KEY_F7;            break;
-      case XK_F8:      rc = KEY_F8;            break;
-      case XK_F9:      rc = KEY_F9;            break;
-      case XK_F10:     rc = KEY_F10;           break;
-      case XK_F11:     rc = KEY_F11;           break;
-      case XK_F12:     rc = KEY_F12;           break;
-       
-      case XK_BackSpace:
-      case XK_Delete:  rc = KEY_BACKSPACE;     break;
-
-      case XK_Pause:   rc = KEY_PAUSE;         break;
-
-      case XK_KP_Equal:
-      case XK_equal:   rc = KEY_EQUALS;        break;
-
-      case XK_KP_Subtract:
-      case XK_minus:   rc = KEY_MINUS;         break;
-
-      case XK_Shift_L:
-      case XK_Shift_R:
-       rc = KEY_RSHIFT;
-       break;
-       
-      case XK_Control_L:
-      case XK_Control_R:
-       rc = KEY_RCTRL;
-       break;
-       
-      case XK_Alt_L:
-      case XK_Meta_L:
-      case XK_Alt_R:
-      case XK_Meta_R:
-       rc = KEY_RALT;
-       break;
-       
-      default:
-       if (rc >= XK_space && rc <= XK_asciitilde)
-           rc = rc - XK_space + ' ';
-       if (rc >= 'A' && rc <= 'Z')
-           rc = rc - 'A' + 'a';
-       break;
-    }
-
-    return rc;
-
-    */
-}
-
-void I_ShutdownGraphics(void)
-{
-    return;
-  /* 
-  // Detach from X server
-  if (!XShmDetach(X_display, &X_shminfo))
-           I_Error("XShmDetach() failed in I_ShutdownGraphics()");
-
-  // Release shared memory.
-  shmdt(X_shminfo.shmaddr);
-  shmctl(X_shminfo.shmid, IPC_RMID, 0);
-
-  // Paranoia.
-  image->data = NULL;
-  */
-}
-
-
-
-//
-// I_StartFrame
-//
-void I_StartFrame (void)
-{
-    // er?
-
-}
-
-static int     lastmousex = 0;
-static int     lastmousey = 0;
-boolean                mousemoved = false;
-boolean                shmFinished;
-
-void I_GetEvent(void)
-{
-
-    return;
-    /*
-    event_t event;
-
-    // put event-grabbing stuff in here
-    XNextEvent(X_display, &X_event);
-    switch (X_event.type)
-    {
-      case KeyPress:
-       event.type = ev_keydown;
-       event.data1 = xlatekey();
-       D_PostEvent(&event);
-       // fprintf(stderr, "k");
-       break;
-      case KeyRelease:
-       event.type = ev_keyup;
-       event.data1 = xlatekey();
-       D_PostEvent(&event);
-       // fprintf(stderr, "ku");
-       break;
-      case ButtonPress:
-       event.type = ev_mouse;
-       event.data1 =
-           (X_event.xbutton.state & Button1Mask)
-           | (X_event.xbutton.state & Button2Mask ? 2 : 0)
-           | (X_event.xbutton.state & Button3Mask ? 4 : 0)
-           | (X_event.xbutton.button == Button1)
-           | (X_event.xbutton.button == Button2 ? 2 : 0)
-           | (X_event.xbutton.button == Button3 ? 4 : 0);
-       event.data2 = event.data3 = 0;
-       D_PostEvent(&event);
-       // fprintf(stderr, "b");
-       break;
-      case ButtonRelease:
-       event.type = ev_mouse;
-       event.data1 =
-           (X_event.xbutton.state & Button1Mask)
-           | (X_event.xbutton.state & Button2Mask ? 2 : 0)
-           | (X_event.xbutton.state & Button3Mask ? 4 : 0);
-       // suggest parentheses around arithmetic in operand of |
-       event.data1 =
-           event.data1
-           ^ (X_event.xbutton.button == Button1 ? 1 : 0)
-           ^ (X_event.xbutton.button == Button2 ? 2 : 0)
-           ^ (X_event.xbutton.button == Button3 ? 4 : 0);
-       event.data2 = event.data3 = 0;
-       D_PostEvent(&event);
-       // fprintf(stderr, "bu");
-       break;
-      case MotionNotify:
-       event.type = ev_mouse;
-       event.data1 =
-           (X_event.xmotion.state & Button1Mask)
-           | (X_event.xmotion.state & Button2Mask ? 2 : 0)
-           | (X_event.xmotion.state & Button3Mask ? 4 : 0);
-       event.data2 = (X_event.xmotion.x - lastmousex) << 2;
-       event.data3 = (lastmousey - X_event.xmotion.y) << 2;
-
-       if (event.data2 || event.data3)
-       {
-           lastmousex = X_event.xmotion.x;
-           lastmousey = X_event.xmotion.y;
-           if (X_event.xmotion.x != X_width/2 &&
-               X_event.xmotion.y != X_height/2)
-           {
-               D_PostEvent(&event);
-               // fprintf(stderr, "m");
-               mousemoved = false;
-           } else
-           {
-               mousemoved = true;
-           }
-       }
-       break;
-       
-      case Expose:
-      case ConfigureNotify:
-       break;
-       
-      default:
-       if (doShm && X_event.type == X_shmeventtype) shmFinished = true;
-       break;
-    }
-    */
-
-}
-
-// Cursor
-// createnullcursor
-// ( Display*  display,
-//   Window    root )
-// {
-//     Pixmap cursormask;
-//     XGCValues xgc;
-//     GC gc;
-//     XColor dummycolour;
-//     Cursor cursor;
-// 
-//     cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
-//     xgc.function = GXclear;
-//     gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
-//     XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
-//     dummycolour.pixel = 0;
-//     dummycolour.red = 0;
-//     dummycolour.flags = 04;
-//     cursor = XCreatePixmapCursor(display, cursormask, cursormask,
-//                              &dummycolour,&dummycolour, 0,0);
-//     XFreePixmap(display,cursormask);
-//     XFreeGC(display,gc);
-//     return cursor;
-// }
-
-//
-// I_StartTic
-//
-void I_StartTic (void)
-{
-
-    return 0;
-
-    /*
-
-    if (!X_display)
-       return;
-
-    while (XPending(X_display))
-       I_GetEvent();
-
-    // Warp the pointer back to the middle of the window
-    //  or it will wander off - that is, the game will
-    //  loose input focus within X11.
-    if (grabMouse)
-    {
-       if (!--doPointerWarp)
-       {
-           XWarpPointer( X_display,
-                         None,
-                         X_mainWindow,
-                         0, 0,
-                         0, 0,
-                         X_width/2, X_height/2);
-
-           doPointerWarp = POINTER_WARP_COUNTDOWN;
-       }
-    }
-
-    mousemoved = false;
-    */
-
-}
-
-
-//
-// I_UpdateNoBlit
-//
-void I_UpdateNoBlit (void)
-{
-    // what is this?
-}
-
-//
-// I_FinishUpdate
-//
-void I_FinishUpdate (void)
-{
-
-    return;
-
-    /*
-    static int lasttic;
-    int                tics;
-    int                i;
-    // UNUSED static unsigned char *bigscreen=0;
-
-    // draws little dots on the bottom of the screen
-    if (devparm)
-    {
-
-       i = I_GetTime();
-       tics = i - lasttic;
-       lasttic = i;
-       if (tics > 20) tics = 20;
-
-       for (i=0 ; i<tics*2 ; i+=2)
-           screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0xff;
-       for ( ; i<20*2 ; i+=2)
-           screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0;
-    
-    }
-
-    // scales the screen size before blitting it
-    if (multiply == 2)
-    {
-       unsigned int *olineptrs[2];
-       unsigned int *ilineptr;
-       int x, y, i;
-       unsigned int twoopixels;
-       unsigned int twomoreopixels;
-       unsigned int fouripixels;
-
-       ilineptr = (unsigned int *) (screens[0]);
-       for (i=0 ; i<2 ; i++)
-           olineptrs[i] = (unsigned int *) &image->data[i*X_width];
-
-       y = SCREENHEIGHT;
-       while (y--)
-       {
-           x = SCREENWIDTH;
-           do
-           {
-               fouripixels = *ilineptr++;
-               twoopixels =    (fouripixels & 0xff000000)
-                   |   ((fouripixels>>8) & 0xffff00)
-                   |   ((fouripixels>>16) & 0xff);
-               twomoreopixels =        ((fouripixels<<16) & 0xff000000)
-                   |   ((fouripixels<<8) & 0xffff00)
-                   |   (fouripixels & 0xff);
-#ifdef __BIG_ENDIAN__
-               *olineptrs[0]++ = twoopixels;
-               *olineptrs[1]++ = twoopixels;
-               *olineptrs[0]++ = twomoreopixels;
-               *olineptrs[1]++ = twomoreopixels;
-#else
-               *olineptrs[0]++ = twomoreopixels;
-               *olineptrs[1]++ = twomoreopixels;
-               *olineptrs[0]++ = twoopixels;
-               *olineptrs[1]++ = twoopixels;
-#endif
-           } while (x-=4);
-           olineptrs[0] += X_width/4;
-           olineptrs[1] += X_width/4;
-       }
-
-    }
-    else if (multiply == 3)
-    {
-       unsigned int *olineptrs[3];
-       unsigned int *ilineptr;
-       int x, y, i;
-       unsigned int fouropixels[3];
-       unsigned int fouripixels;
-
-       ilineptr = (unsigned int *) (screens[0]);
-       for (i=0 ; i<3 ; i++)
-           olineptrs[i] = (unsigned int *) &image->data[i*X_width];
-
-       y = SCREENHEIGHT;
-       while (y--)
-       {
-           x = SCREENWIDTH;
-           do
-           {
-               fouripixels = *ilineptr++;
-               fouropixels[0] = (fouripixels & 0xff000000)
-                   |   ((fouripixels>>8) & 0xff0000)
-                   |   ((fouripixels>>16) & 0xffff);
-               fouropixels[1] = ((fouripixels<<8) & 0xff000000)
-                   |   (fouripixels & 0xffff00)
-                   |   ((fouripixels>>8) & 0xff);
-               fouropixels[2] = ((fouripixels<<16) & 0xffff0000)
-                   |   ((fouripixels<<8) & 0xff00)
-                   |   (fouripixels & 0xff);
-#ifdef __BIG_ENDIAN__
-               *olineptrs[0]++ = fouropixels[0];
-               *olineptrs[1]++ = fouropixels[0];
-               *olineptrs[2]++ = fouropixels[0];
-               *olineptrs[0]++ = fouropixels[1];
-               *olineptrs[1]++ = fouropixels[1];
-               *olineptrs[2]++ = fouropixels[1];
-               *olineptrs[0]++ = fouropixels[2];
-               *olineptrs[1]++ = fouropixels[2];
-               *olineptrs[2]++ = fouropixels[2];
-#else
-               *olineptrs[0]++ = fouropixels[2];
-               *olineptrs[1]++ = fouropixels[2];
-               *olineptrs[2]++ = fouropixels[2];
-               *olineptrs[0]++ = fouropixels[1];
-               *olineptrs[1]++ = fouropixels[1];
-               *olineptrs[2]++ = fouropixels[1];
-               *olineptrs[0]++ = fouropixels[0];
-               *olineptrs[1]++ = fouropixels[0];
-               *olineptrs[2]++ = fouropixels[0];
-#endif
-           } while (x-=4);
-           olineptrs[0] += 2*X_width/4;
-           olineptrs[1] += 2*X_width/4;
-           olineptrs[2] += 2*X_width/4;
-       }
-
-    }
-    else if (multiply == 4)
-    {
-       // Broken. Gotta fix this some day.
-       void Expand4(unsigned *, double *);
-       Expand4 ((unsigned *)(screens[0]), (double *) (image->data));
-    }
-
-    if (doShm)
-    {
-
-       if (!XShmPutImage(      X_display,
-                               X_mainWindow,
-                               X_gc,
-                               image,
-                               0, 0,
-                               0, 0,
-                               X_width, X_height,
-                               True ))
-           I_Error("XShmPutImage() failed\n");
-
-       // wait for it to finish and processes all input events
-       shmFinished = false;
-       do
-       {
-           I_GetEvent();
-       } while (!shmFinished);
-
-    }
-    else
-    {
-
-       // draw the image
-       XPutImage(      X_display,
-                       X_mainWindow,
-                       X_gc,
-                       image,
-                       0, 0,
-                       0, 0,
-                       X_width, X_height );
-
-       // sync up with server
-       XSync(X_display, False);
-
-    }
-
-    */
-}
-
-
-//
-// I_ReadScreen
-//
-void I_ReadScreen (byte* scr)
-{
-    //memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT);
-}
-
-
-//
-// Palette stuff.
-//
-//static XColor        colors[256];
-
-//
-// I_SetPalette
-//
-void I_SetPalette (byte* palette)
-{
-    //UploadNewPalette(X_cmap, palette);
-}
-
-
-void I_InitGraphics(void)
-{
-
-    return;
-
-    /*
-    char*              displayname;
-    char*              d;
-    int                        n;
-    int                        pnum;
-    int                        x=0;
-    int                        y=0;
-    
-    // warning: char format, different type arg
-    char               xsign=' ';
-    char               ysign=' ';
-    
-    int                        oktodraw;
-    unsigned long      attribmask;
-    XSetWindowAttributes attribs;
-    XGCValues          xgcvalues;
-    int                        valuemask;
-    static int         firsttime=1;
-
-    if (!firsttime)
-       return;
-    firsttime = 0;
-
-    signal(SIGINT, (void (*)(int)) I_Quit);
-
-    if (M_CheckParm("-2"))
-       multiply = 2;
-
-    if (M_CheckParm("-3"))
-       multiply = 3;
-
-    if (M_CheckParm("-4"))
-       multiply = 4;
-
-    X_width = SCREENWIDTH * multiply;
-    X_height = SCREENHEIGHT * multiply;
-
-    // check for command-line display name
-    if ( (pnum=M_CheckParm("-disp")) ) // suggest parentheses around assignment
-       displayname = myargv[pnum+1];
-    else
-       displayname = 0;
-
-    // check if the user wants to grab the mouse (quite unnice)
-    grabMouse = !!M_CheckParm("-grabmouse");
-
-    // check for command-line geometry
-    if ( (pnum=M_CheckParm("-geom")) ) // suggest parentheses around assignment
-    {
-       // warning: char format, different type arg 3,5
-       n = sscanf(myargv[pnum+1], "%c%d%c%d", &xsign, &x, &ysign, &y);
-       
-       if (n==2)
-           x = y = 0;
-       else if (n==6)
-       {
-           if (xsign == '-')
-               x = -x;
-           if (ysign == '-')
-               y = -y;
-       }
-       else
-           I_Error("bad -geom parameter");
-    }
-
-    // open the display
-    X_display = XOpenDisplay(displayname);
-    if (!X_display)
-    {
-       if (displayname)
-           I_Error("Could not open display [%s]", displayname);
-       else
-           I_Error("Could not open display (DISPLAY=[%s])", getenv("DISPLAY"));
-    }
-
-    // use the default visual 
-    X_screen = DefaultScreen(X_display);
-    if (!XMatchVisualInfo(X_display, X_screen, 8, PseudoColor, &X_visualinfo))
-       I_Error("xdoom currently only supports 256-color PseudoColor screens");
-    X_visual = X_visualinfo.visual;
-
-    // check for the MITSHM extension
-    doShm = XShmQueryExtension(X_display);
-
-    // even if it's available, make sure it's a local connection
-    if (doShm)
-    {
-       if (!displayname) displayname = (char *) getenv("DISPLAY");
-       if (displayname)
-       {
-           d = displayname;
-           while (*d && (*d != ':')) d++;
-           if (*d) *d = 0;
-           if (!(!strcasecmp(displayname, "unix") || !*displayname)) doShm = false;
-       }
-    }
-
-    fprintf(stderr, "Using MITSHM extension\n");
-
-    // create the colormap
-    X_cmap = XCreateColormap(X_display, RootWindow(X_display,
-                                                  X_screen), X_visual, AllocAll);
-
-    // setup attributes for main window
-    attribmask = CWEventMask | CWColormap | CWBorderPixel;
-    attribs.event_mask =
-       KeyPressMask
-       | KeyReleaseMask
-       // | PointerMotionMask | ButtonPressMask | ButtonReleaseMask
-       | ExposureMask;
-
-    attribs.colormap = X_cmap;
-    attribs.border_pixel = 0;
-
-    // create the main window
-    X_mainWindow = XCreateWindow(      X_display,
-                                       RootWindow(X_display, X_screen),
-                                       x, y,
-                                       X_width, X_height,
-                                       0, // borderwidth
-                                       8, // depth
-                                       InputOutput,
-                                       X_visual,
-                                       attribmask,
-                                       &attribs );
-
-    XDefineCursor(X_display, X_mainWindow,
-                 createnullcursor( X_display, X_mainWindow ) );
-
-    // create the GC
-    valuemask = GCGraphicsExposures;
-    xgcvalues.graphics_exposures = False;
-    X_gc = XCreateGC(  X_display,
-                       X_mainWindow,
-                       valuemask,
-                       &xgcvalues );
-
-    // map the window
-    XMapWindow(X_display, X_mainWindow);
-
-    // wait until it is OK to draw
-    oktodraw = 0;
-    while (!oktodraw)
-    {
-       XNextEvent(X_display, &X_event);
-       if (X_event.type == Expose
-           && !X_event.xexpose.count)
-       {
-           oktodraw = 1;
-       }
-    }
-
-    // grabs the pointer so it is restricted to this window
-    if (grabMouse)
-       XGrabPointer(X_display, X_mainWindow, True,
-                    ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
-                    GrabModeAsync, GrabModeAsync,
-                    X_mainWindow, None, CurrentTime);
-
-    if (doShm)
-    {
-
-       X_shmeventtype = XShmGetEventBase(X_display) + ShmCompletion;
-
-       // create the image
-       image = XShmCreateImage(        X_display,
-                                       X_visual,
-                                       8,
-                                       ZPixmap,
-                                       0,
-                                       &X_shminfo,
-                                       X_width,
-                                       X_height );
-
-       grabsharedmemory(image->bytes_per_line * image->height);
-
-
-       // UNUSED
-       // create the shared memory segment
-       // X_shminfo.shmid = shmget (IPC_PRIVATE,
-       // image->bytes_per_line * image->height, IPC_CREAT | 0777);
-       // if (X_shminfo.shmid < 0)
-       // {
-       // perror("");
-       // I_Error("shmget() failed in InitGraphics()");
-       // }
-       // fprintf(stderr, "shared memory id=%d\n", X_shminfo.shmid);
-       // attach to the shared memory segment
-       // image->data = X_shminfo.shmaddr = shmat(X_shminfo.shmid, 0, 0);
-       
-
-       if (!image->data)
-       {
-           perror("");
-           I_Error("shmat() failed in InitGraphics()");
-       }
-
-       // get the X server to attach to it
-       if (!XShmAttach(X_display, &X_shminfo))
-           I_Error("XShmAttach() failed in InitGraphics()");
-
-    }
-    else
-    {
-       image = XCreateImage(   X_display,
-                               X_visual,
-                               8,
-                               ZPixmap,
-                               0,
-                               (char*)malloc(X_width * X_height),
-                               X_width, X_height,
-                               8,
-                               X_width );
-
-    }
-
-    if (multiply == 1)
-       screens[0] = (unsigned char *) (image->data);
-    else
-       screens[0] = (unsigned char *) malloc (SCREENWIDTH * SCREENHEIGHT);
-
-    */
-}
-
-
-void InitExpand (void)
-{
-    /*
-    int                i;
-       
-    for (i=0 ; i<256 ; i++)
-       exptable[i] = i | (i<<8) | (i<<16) | (i<<24);
-    */
-}
-
-
-void InitExpand2 (void)
-{
-    return;
-    /*
-    int                i;
-    int                j;
-    // UNUSED unsigned iexp, jexp;
-    double*    exp;
-    union
-    {
-       double          d;
-       unsigned        u[2];
-    } pixel;
-       
-    printf ("building exptable2...\n");
-    exp = exptable2;
-    for (i=0 ; i<256 ; i++)
-    {
-       pixel.u[0] = i | (i<<8) | (i<<16) | (i<<24);
-       for (j=0 ; j<256 ; j++)
-       {
-           pixel.u[1] = j | (j<<8) | (j<<16) | (j<<24);
-           *exp++ = pixel.d;
-       }
-    }
-    printf ("done.\n");
-    */
-}
-
-int    inited;
-
-void
-Expand4
-( unsigned*    lineptr,
-  double*      xline )
-{
-    return;
-    /*
-    double     dpixel;
-    unsigned   x;
-    unsigned   y;
-    unsigned   fourpixels;
-    unsigned   step;
-    double*    exp;
-       
-    exp = exptable2;
-    if (!inited)
-    {
-       inited = 1;
-       InitExpand2 ();
-    }
-               
-               
-    step = 3*SCREENWIDTH/2;
-       
-    y = SCREENHEIGHT-1;
-    do
-    {
-       x = SCREENWIDTH;
-
-       do
-       {
-           fourpixels = lineptr[0];
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
-           xline[0] = dpixel;
-           xline[160] = dpixel;
-           xline[320] = dpixel;
-           xline[480] = dpixel;
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
-           xline[1] = dpixel;
-           xline[161] = dpixel;
-           xline[321] = dpixel;
-           xline[481] = dpixel;
-
-           fourpixels = lineptr[1];
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
-           xline[2] = dpixel;
-           xline[162] = dpixel;
-           xline[322] = dpixel;
-           xline[482] = dpixel;
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
-           xline[3] = dpixel;
-           xline[163] = dpixel;
-           xline[323] = dpixel;
-           xline[483] = dpixel;
-
-           fourpixels = lineptr[2];
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
-           xline[4] = dpixel;
-           xline[164] = dpixel;
-           xline[324] = dpixel;
-           xline[484] = dpixel;
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
-           xline[5] = dpixel;
-           xline[165] = dpixel;
-           xline[325] = dpixel;
-           xline[485] = dpixel;
-
-           fourpixels = lineptr[3];
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
-           xline[6] = dpixel;
-           xline[166] = dpixel;
-           xline[326] = dpixel;
-           xline[486] = dpixel;
-                       
-           dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
-           xline[7] = dpixel;
-           xline[167] = dpixel;
-           xline[327] = dpixel;
-           xline[487] = dpixel;
-
-           lineptr+=4;
-           xline+=8;
-       } while (x-=16);
-       xline += step;
-    } while (y--);
-    */
-}
-
-
index a18dd454807de667feb3276622d923ce0b201df9..e4adc47df7b8d9b923ce6127bfd7dd6242f67a57 100644 (file)
@@ -5,25 +5,38 @@
 //
 // Copyright (C) 1993-1996 by id Software, Inc.
 //
-// This source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
+// 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.
 //
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // $Log:$
 //
 // DESCRIPTION:
-//     DOOM graphics stuff for fbdev on Frosted
+//     DOOM graphics stuff for X11, UNIX.
 //
 //-----------------------------------------------------------------------------
 
 static const char
 rcsid[] = "$Id: i_x.c,v 1.6 1997/02/03 22:45:10 b1 Exp $";
 
+#include "config.h"
+#include "v_video.h"
+#include "m_argv.h"
+#include "d_event.h"
+#include "d_main.h"
+#include "i_video.h"
+#include "z_zone.h"
+
+#include "tables.h"
+#include "doomkeys.h"
+
+#include <stdbool.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -34,18 +47,6 @@ rcsid[] = "$Id: i_x.c,v 1.6 1997/02/03 22:45:10 b1 Exp $";
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 
-#include <netinet/in.h>
-#include <errno.h>
-#include <signal.h>
-
-#include "doomstat.h"
-#include "i_system.h"
-#include "v_video.h"
-#include "m_argv.h"
-#include "d_main.h"
-
-#include "doomdef.h"
-
 struct color {
     uint32_t b:8;
     uint32_t g:8;
@@ -53,7 +54,11 @@ struct color {
     uint32_t a:8;
 };
 
-struct color colors[256];
+static struct color colors[256];
+
+// The screen buffer; this is modified to draw things to the screen
+
+byte *I_VideoBuffer = NULL;
 
 /* framebuffer file descriptor */
 int fd_fb = 0;
@@ -61,160 +66,290 @@ int fd_fb = 0;
 int    X_width;
 int X_height;
 
+// If true, game is running as a screensaver
 
-void I_ShutdownGraphics(void)
-{
-    printf("I_ShutdownGraphics\n");
-    // Always be sure to clean up
-    //SDL_Quit();
-    close(fd_fb);
-}
+boolean screensaver_mode = false;
 
+// Flag indicating whether the screen is currently visible:
+// when the screen isnt visible, don't render the screen
 
+boolean screenvisible;
 
+// Mouse acceleration
 //
-// I_StartFrame
+// This emulates some of the behavior of DOS mouse drivers by increasing
+// the speed when the mouse is moved fast.
 //
-void I_StartFrame (void)
-{
-    // er?
+// The mouse input values are input directly to the game, but when
+// the values exceed the value of mouse_threshold, they are multiplied
+// by mouse_acceleration to increase the speed.
 
-}
+float mouse_acceleration = 2.0;
+int mouse_threshold = 10;
 
-void I_GetEvent(void)
-{
-    /*
-    event_t event;
+// Gamma correction level to use
 
-    // put event-grabbing stuff in here
-    XNextEvent(X_display, &X_event);
-    switch (X_event.type)
-    {
-      case KeyPress:
-       event.type = ev_keydown;
-       event.data1 = xlatekey();
-       D_PostEvent(&event);
-       // fprintf(stderr, "k");
-       break;
-      case KeyRelease:
-       event.type = ev_keyup;
-       event.data1 = xlatekey();
-       D_PostEvent(&event);
-       // fprintf(stderr, "ku");
-       break;
-      case ButtonPress:
-       event.type = ev_mouse;
-       event.data1 =
-           (X_event.xbutton.state & Button1Mask)
-           | (X_event.xbutton.state & Button2Mask ? 2 : 0)
-           | (X_event.xbutton.state & Button3Mask ? 4 : 0)
-           | (X_event.xbutton.button == Button1)
-           | (X_event.xbutton.button == Button2 ? 2 : 0)
-           | (X_event.xbutton.button == Button3 ? 4 : 0);
-       event.data2 = event.data3 = 0;
-       D_PostEvent(&event);
-       // fprintf(stderr, "b");
-       break;
-      case ButtonRelease:
-       event.type = ev_mouse;
-       event.data1 =
-           (X_event.xbutton.state & Button1Mask)
-           | (X_event.xbutton.state & Button2Mask ? 2 : 0)
-           | (X_event.xbutton.state & Button3Mask ? 4 : 0);
-       // suggest parentheses around arithmetic in operand of |
-       event.data1 =
-           event.data1
-           ^ (X_event.xbutton.button == Button1 ? 1 : 0)
-           ^ (X_event.xbutton.button == Button2 ? 2 : 0)
-           ^ (X_event.xbutton.button == Button3 ? 4 : 0);
-       event.data2 = event.data3 = 0;
-       D_PostEvent(&event);
-       // fprintf(stderr, "bu");
-       break;
-      case MotionNotify:
-       event.type = ev_mouse;
-       event.data1 =
-           (X_event.xmotion.state & Button1Mask)
-           | (X_event.xmotion.state & Button2Mask ? 2 : 0)
-           | (X_event.xmotion.state & Button3Mask ? 4 : 0);
-       event.data2 = (X_event.xmotion.x - lastmousex) << 2;
-       event.data3 = (lastmousey - X_event.xmotion.y) << 2;
-
-       if (event.data2 || event.data3)
-       {
-           lastmousex = X_event.xmotion.x;
-           lastmousey = X_event.xmotion.y;
-           if (X_event.xmotion.x != X_width/2 &&
-               X_event.xmotion.y != X_height/2)
-           {
-               D_PostEvent(&event);
-               // fprintf(stderr, "m");
-               mousemoved = false;
-           } else
-           {
-               mousemoved = true;
-           }
-       }
-       break;
-       
-      case Expose:
-      case ConfigureNotify:
-       break;
-       
-      default:
-       if (doShm && X_event.type == X_shmeventtype) shmFinished = true;
-       break;
-    }
-    */
+int usegamma = 0;
 
-}
+int usemouse = 0;
 
-//
-// I_StartTic
-//
-void I_StartTic (void)
+// If true, keyboard mapping is ignored, like in Vanilla Doom.
+// The sensible thing to do is to disable this if you have a non-US
+// keyboard.
+
+int vanilla_keyboard_mapping = true;
+
+
+typedef struct
 {
+       byte r;
+       byte g;
+       byte b;
+} col_t;
 
-    return;
+// Palette converted to RGB565
 
-    /*
+static uint16_t rgb565_palette[256];
 
-    if (!X_display)
-       return;
+// Last touch state
 
-    while (XPending(X_display))
-       I_GetEvent();
+//static touch_state_t last_touch_state;
+
+// Last button state
+
+//static bool last_button_state;
+
+// run state
+
+//static bool run;
 
-    // Warp the pointer back to the middle of the window
-    //  or it will wander off - that is, the game will
-    //  loose input focus within X11.
-    if (grabMouse)
+void I_InitGraphics (void)
+{
+//     gfx_image_t keys_img;
+//     gfx_coord_t coords;
+//
+//     gfx_init_img (&keys_img, 40, 320, GFX_PIXEL_FORMAT_RGB565, RGB565_BLACK);
+//     keys_img.pixel_data = (uint8_t*)img_keys;
+//     gfx_init_img_coord (&coords, &keys_img);
+//
+//     gfx_draw_img (&keys_img, &coords);
+//     lcd_refresh ();
+//
+//     gfx_draw_img (&keys_img, &coords);
+//     lcd_refresh ();
+
+    X_width = SCREENWIDTH;
+    X_height = SCREENHEIGHT;
+
+    printf("I_InitGraphics: w x h: %d x %d\n", X_width, X_height);
+
+    /* Open fbdev file descriptor */
+    fd_fb = open("/dev/fb0", O_RDWR);
+    if (fd_fb < 0)
     {
-       if (!--doPointerWarp)
-       {
-           XWarpPointer( X_display,
-                         None,
-                         X_mainWindow,
-                         0, 0,
-                         0, 0,
-                         X_width/2, X_height/2);
-
-           doPointerWarp = POINTER_WARP_COUNTDOWN;
-       }
+        printf("Could not open /dev/fb0");
+        exit(-1);
     }
 
-    mousemoved = false;
-    */
+    /* Allocate screen to draw to */
+    //screen_pixels = malloc(X_width * X_height);
+    //
+       I_VideoBuffer = (byte*)Z_Malloc (SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL);
+
+       screenvisible = true;
+
+    //screens[0] = (unsigned char *)screen_pixels;
+    //screens[0] = (unsigned char *)I_VideoBuffer;
+
+}
 
+void I_ShutdownGraphics (void)
+{
+       Z_Free (I_VideoBuffer);
 }
 
+void I_StartFrame (void)
+{
+
+}
 
+void I_GetEvent (void)
+{
+//     event_t event;
+//     bool button_state;
+//
+//     button_state = button_read ();
+//
+//     if (last_button_state != button_state)
+//     {
+//             last_button_state = button_state;
+//
+//             event.type = last_button_state ? ev_keydown : ev_keyup;
+//             event.data1 = KEY_FIRE;
+//             event.data2 = -1;
+//             event.data3 = -1;
+//
+//             D_PostEvent (&event);
+//     }
+//
+//     touch_main ();
+//
+//     if ((touch_state.x != last_touch_state.x) || (touch_state.y != last_touch_state.y) || (touch_state.status != last_touch_state.status))
+//     {
+//             last_touch_state = touch_state;
 //
-// I_UpdateNoBlit
+//             event.type = (touch_state.status == TOUCH_PRESSED) ? ev_keydown : ev_keyup;
+//             event.data1 = -1;
+//             event.data2 = -1;
+//             event.data3 = -1;
 //
+//             if ((touch_state.x > 49)
+//              && (touch_state.x < 72)
+//              && (touch_state.y > 104)
+//              && (touch_state.y < 143))
+//             {
+//                     // select weapon
+//                     if (touch_state.x < 60)
+//                     {
+//                             // lower row (5-7)
+//                             if (touch_state.y < 119)
+//                             {
+//                                     event.data1 = '5';
+//                             }
+//                             else if (touch_state.y < 131)
+//                             {
+//                                     event.data1 = '6';
+//                             }
+//                             else
+//                             {
+//                                     event.data1 = '1';
+//                             }
+//                     }
+//                     else
+//                     {
+//                             // upper row (2-4)
+//                             if (touch_state.y < 119)
+//                             {
+//                                     event.data1 = '2';
+//                             }
+//                             else if (touch_state.y < 131)
+//                             {
+//                                     event.data1 = '3';
+//                             }
+//                             else
+//                             {
+//                                     event.data1 = '4';
+//                             }
+//                     }
+//             }
+//             else if (touch_state.x < 40)
+//             {
+//                     // button bar at bottom screen
+//                     if (touch_state.y < 40)
+//                     {
+//                             // enter
+//                             event.data1 = KEY_ENTER;
+//                     }
+//                     else if (touch_state.y < 80)
+//                     {
+//                             // escape
+//                             event.data1 = KEY_ESCAPE;
+//                     }
+//                     else if (touch_state.y < 120)
+//                     {
+//                             // use
+//                             event.data1 = KEY_USE;
+//                     }
+//                     else if (touch_state.y < 160)
+//                     {
+//                             // map
+//                             event.data1 = KEY_TAB;
+//                     }
+//                     else if (touch_state.y < 200)
+//                     {
+//                             // pause
+//                             event.data1 = KEY_PAUSE;
+//                     }
+//                     else if (touch_state.y < 240)
+//                     {
+//                             // toggle run
+//                             if (touch_state.status == TOUCH_PRESSED)
+//                             {
+//                                     run = !run;
+//
+//                                     event.data1 = KEY_RSHIFT;
+//
+//                                     if (run)
+//                                     {
+//                                             event.type = ev_keydown;
+//                                     }
+//                                     else
+//                                     {
+//                                             event.type = ev_keyup;
+//                                     }
+//                             }
+//                             else
+//                             {
+//                                     return;
+//                             }
+//                     }
+//                     else if (touch_state.y < 280)
+//                     {
+//                             // save
+//                             event.data1 = KEY_F2;
+//                     }
+//                     else if (touch_state.y < 320)
+//                     {
+//                             // load
+//                             event.data1 = KEY_F3;
+//                     }
+//             }
+//             else
+//             {
+//                     // movement/menu navigation
+//                     if (touch_state.x < 100)
+//                     {
+//                             if (touch_state.y < 100)
+//                             {
+//                                     event.data1 = KEY_STRAFE_L;
+//                             }
+//                             else if (touch_state.y < 220)
+//                             {
+//                                     event.data1 = KEY_DOWNARROW;
+//                             }
+//                             else
+//                             {
+//                                     event.data1 = KEY_STRAFE_R;
+//                             }
+//                     }
+//                     else if (touch_state.x < 180)
+//                     {
+//                             if (touch_state.y < 160)
+//                             {
+//                                     event.data1 = KEY_LEFTARROW;
+//                             }
+//                             else
+//                             {
+//                                     event.data1 = KEY_RIGHTARROW;
+//                             }
+//                     }
+//                     else
+//                     {
+//                             event.data1 = KEY_UPARROW;
+//                     }
+//             }
+//
+//             D_PostEvent (&event);
+//     }
+}
+
+void I_StartTic (void)
+{
+       I_GetEvent();
+}
+
 void I_UpdateNoBlit (void)
 {
-    // what is this?
 }
 
 //
@@ -224,51 +359,34 @@ void I_UpdateNoBlit (void)
 #define FB_HEIGHT       (272)
 #define FB_BPP_RGB565    (16)
 
-unsigned char line_out[FB_WIDTH * (FB_BPP_RGB565/8)];
-
-void cmap_to_rgb565(uint16_t * out, uint8_t * in, int in_pixels)
-{
-    int i;
-    struct color c;
-    uint16_t r, g, b;
-
-    for (i = 0; i < in_pixels; i++)
-    {
-        c = colors[*in]; 
-        r = ((uint16_t)(c.r >> 3)) << 11;
-        g = ((uint16_t)(c.g >> 2)) << 5;
-        b = ((uint16_t)(c.b >> 3)) << 0;
-        *out = (r | g | b);
-
-        in++;
-        out++;
-    }
-}
-
 void I_FinishUpdate (void)
 {
+       //int x, y;
+    int y;
     unsigned char *line_in;
-    static int lasttic;
-    int                tics;
-    int                i;
-    int         y;
+       //byte index;
 
-    // draws little dots on the bottom of the screen
-    if (devparm)
-    {
-        i = I_GetTime();
-        tics = i - lasttic;
-        lasttic = i;
-        if (tics > 20) tics = 20;
-
-        for (i=0 ; i<tics*2 ; i+=2)
-            screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0xff;
-        for ( ; i<20*2 ; i+=2)
-            screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0;
-    }
+       //lcd_vsync = false;
+
+       //for (y = 0; y < SCREENHEIGHT; y++)
+       //{
+       //      for (x = 0; x < SCREENWIDTH; x++)
+       //      {
+       //              index = I_VideoBuffer[y * SCREENWIDTH + x];
+
+       //              ((uint16_t*)lcd_frame_buffer)[x * GFX_MAX_WIDTH + (GFX_MAX_WIDTH - y - 1)] = rgb565_palette[index];
+       //      }
+       //}
+
+       //lcd_refresh ();
+
+       //lcd_vsync = true;
+    //
+    //
+    
 
     /* DRAW SCREEN */
-    line_in = (unsigned char *) screens[0];
+    line_in = (unsigned char *) I_VideoBuffer;
     lseek(fd_fb, 0, SEEK_SET);
     y = SCREENHEIGHT;
 
@@ -288,35 +406,42 @@ void I_FinishUpdate (void)
         line_in += SCREENWIDTH;
     }
 #endif
-}
 
+}
 
 //
 // I_ReadScreen
 //
 void I_ReadScreen (byte* scr)
 {
-    /* Our framebuffer is not the same resolution, so makes reading difficult */
-    //lseek(fd_fb, 0, SEEK_SET);
-    //int left = SCREENWIDTH * SCREENHEIGHT;
-    //while (left)
-    //{
-    //    int rd = read(fd_fb, scr, left);
-    //    if (rd > 0)
-    //        left -= rd;
-    //}
-    memcpy(scr, screens[0], SCREENWIDTH * SCREENHEIGHT);
+    memcpy (scr, I_VideoBuffer, SCREENWIDTH * SCREENHEIGHT);
 }
 
-
 //
 // I_SetPalette
 //
+#define GFX_RGB565(r, g, b)                    ((((r & 0xF8) >> 3) << 11) | (((g & 0xFC) >> 2) << 5) | ((b & 0xF8) >> 3))
+#define GFX_RGB565_R(color)                    ((0xF800 & color) >> 11)
+#define GFX_RGB565_G(color)                    ((0x07E0 & color) >> 5)
+#define GFX_RGB565_B(color)                    (0x001F & color)
+
 void I_SetPalette (byte* palette)
 {
-    //printf("I_SetPalette\n");
+       int i;
+       //col_t* c;
+
+       //for (i = 0; i < 256; i++)
+       //{
+       //      c = (col_t*)palette;
 
-    for (int i=0; i<256; ++i ) {
+       //      rgb565_palette[i] = GFX_RGB565(gammatable[usegamma][c->r],
+       //                                                                 gammatable[usegamma][c->g],
+       //                                                                 gammatable[usegamma][c->b]);
+
+       //      palette += 3;
+       //}
+    
+    for (i=0; i<256; ++i ) {
         colors[i].a = 0;
         colors[i].r = gammatable[usegamma][*palette++];
         colors[i].g = gammatable[usegamma][*palette++];
@@ -327,27 +452,76 @@ void I_SetPalette (byte* palette)
     ioctl(fd_fb, IOCTL_FB_PUTCMAP, colors);
 }
 
-void I_InitGraphics(void)
+// Given an RGB value, find the closest matching palette index.
+
+int I_GetPaletteIndex (int r, int g, int b)
 {
-    unsigned char * screen_pixels;
+    int best, best_diff, diff;
+    int i;
+    col_t color;
 
-    X_width = SCREENWIDTH;
-    X_height = SCREENHEIGHT;
+    //printf("I_GetPaletteIndex\n");
 
-    printf("I_InitGraphics: w x h: %d x %d\n", X_width, X_height);
+    best = 0;
+    best_diff = INT_MAX;
 
-    /* Open fbdev file descriptor */
-    fd_fb = open("/dev/fb0", O_RDWR);
-    if (fd_fb < 0)
+    for (i = 0; i < 256; ++i)
     {
-        printf("Could not open /dev/fb0");
-        exit(-1);
+       color.r = GFX_RGB565_R(rgb565_palette[i]);
+       color.g = GFX_RGB565_G(rgb565_palette[i]);
+       color.b = GFX_RGB565_B(rgb565_palette[i]);
+
+        diff = (r - color.r) * (r - color.r)
+             + (g - color.g) * (g - color.g)
+             + (b - color.b) * (b - color.b);
+
+        if (diff < best_diff)
+        {
+            best = i;
+            best_diff = diff;
+        }
+
+        if (diff == 0)
+        {
+            break;
+        }
     }
 
-    /* Allocate screen to draw to */
-    screen_pixels = malloc(X_width * X_height);
+    return best;
+}
+
+void I_BeginRead (void)
+{
+}
+
+void I_EndRead (void)
+{
+}
+
+void I_SetWindowTitle (char *title)
+{
+}
+
+void I_GraphicsCheckCommandLine (void)
+{
+}
+
+void I_SetGrabMouseCallback (grabmouse_callback_t func)
+{
+}
 
-    screens[0] = (unsigned char *)screen_pixels;
+void I_EnableLoadingDisk(void)
+{
+}
+
+void I_BindVideoVariables (void)
+{
 }
 
+void I_DisplayFPSDots (boolean dots_on)
+{
+}
 
+void I_CheckIsScreensaver (void)
+{
+}
diff --git a/frosted-doom/icon.c b/frosted-doom/icon.c
new file mode 100644 (file)
index 0000000..14c607c
--- /dev/null
@@ -0,0 +1,262 @@
+static int icon_w = 32;
+static int icon_h = 32;
+
+static unsigned char icon_data[] = {
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0xa2,0x86,0x73,  
+    0xa9,0x8d,0x7a,  0xbd,0xa0,0x8c,  0xda,0xba,0xa0,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0xbd,0x8d,0x67,  0xd7,0xb9,0xa5,  0xeb,0xd8,0xcd,  0xd3,0xbf,0xae,  
+    0xbd,0xa0,0x8c,  0xeb,0xd8,0xcd,  0xc2,0x9d,0x86,  0x95,0x5d,0x38,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x9b,0x7e,0x66,  
+    0xc5,0x9e,0x81,  0xd3,0xb3,0x99,  0xd4,0xac,0x8e,  0xee,0xdc,0xd1,  
+    0xb9,0x93,0x76,  0xad,0x71,0x45,  0xd4,0xac,0x8e,  0xb9,0x93,0x76,  
+    0xa3,0x77,0x58,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x39,0x1d,0x2d,  0x55,0x20,0x22,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0xda,0xb4,0x9c,  0xd3,0xa3,0x83,  
+    0xaf,0x91,0x78,  0xa7,0x83,0x6d,  0xc4,0xa7,0x93,  0xee,0xe2,0xd5,  
+    0xeb,0xd8,0xcd,  0x8c,0x60,0x3d,  0x9b,0x7e,0x66,  0xce,0x9f,0x7e,  
+    0x84,0x54,0x33,  0xba,0x83,0x5b,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x24,0x1c,0x35,  0x00,0x0f,0x32,  0x29,0x18,0x2e,  0x55,0x20,0x22,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0xd3,0xb3,0x99,  0xca,0x93,0x6f,  0xc4,0x94,0x6e,  
+    0x98,0x66,0x45,  0x78,0x50,0x2d,  0xd7,0xb9,0xa5,  0xee,0xdc,0xd1,  
+    0xc4,0x9b,0x79,  0xa1,0x6d,0x45,  0x66,0x40,0x24,  0xb8,0x7a,0x4f,  
+    0xcf,0xa6,0x83,  0x98,0x6d,0x4e,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x30,0x1c,0x2f,  0x08,0x13,0x30,  0x00,0x0f,0x32,  0x00,0x0f,0x32,  
+    0x39,0x1d,0x2d,  0x52,0x1c,0x1a,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x9e,0x7b,0x65,  0xb9,0x89,0x64,  0xaa,0x7d,0x5e,  0x9e,0x72,0x53,  
+    0x88,0x5e,0x40,  0xc4,0xa7,0x93,  0xb9,0x89,0x64,  0x90,0x6c,0x51,  
+    0x7f,0x50,0x2f,  0x90,0x5e,0x37,  0x75,0x4d,0x30,  0x7f,0x50,0x2f,  
+    0xd3,0xa3,0x83,  0xd4,0xac,0x8e,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x29,0x18,0x2e,  0x08,0x13,0x30,  0x08,0x13,0x30,  0x08,0x13,0x30,  
+    0x00,0x0f,0x32,  0x08,0x13,0x30,  0x49,0x1e,0x2b,  0x49,0x1a,0x16,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0xda,0xba,0xa0,  
+    0xd4,0xac,0x8e,  0xc4,0x9b,0x79,  0xaa,0x7d,0x5e,  0xaa,0x7d,0x5e,  
+    0xbd,0xa0,0x8c,  0x8c,0x60,0x3d,  0x70,0x49,0x2c,  0x89,0x60,0x42,  
+    0x57,0x38,0x20,  0x6c,0x45,0x29,  0x66,0x40,0x24,  0x51,0x35,0x21,  
+    0x7e,0x55,0x38,  0xce,0x9f,0x7e,  0xc2,0x8a,0x61,  0x00,0x00,0x00,  
+    0x30,0x1c,0x2f,  0x00,0x0f,0x32,  0x00,0x0f,0x32,  0x08,0x13,0x30,  
+    0x00,0x0f,0x32,  0x00,0x0f,0x32,  0x08,0x13,0x30,  0x08,0x13,0x30,  
+    0x59,0x25,0x2b,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0xcb,0x9a,0x74,  
+    0xb7,0x81,0x58,  0x8c,0x60,0x3d,  0x79,0x4b,0x2b,  0x89,0x58,0x31,  
+    0x89,0x58,0x31,  0x7f,0x50,0x2f,  0x9e,0x64,0x39,  0x75,0x4c,0x2a,  
+    0x51,0x35,0x21,  0x84,0x54,0x33,  0x54,0x36,0x1d,  0x98,0x6d,0x4e,  
+    0xb4,0x7f,0x5c,  0xba,0x83,0x5b,  0xb8,0x7a,0x4f,  0x00,0x00,0x00,  
+    0x3e,0x28,0x36,  0x08,0x13,0x30,  0x00,0x0f,0x32,  0x08,0x13,0x30,  
+    0x00,0x0f,0x32,  0x00,0x0f,0x32,  0x00,0x0f,0x32,  0x08,0x13,0x30,  
+    0x20,0x1f,0x36,  0x35,0x19,0x12,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0xc2,0x8a,0x61,  
+    0x89,0x60,0x42,  0x84,0x54,0x33,  0x7f,0x50,0x2f,  0x86,0x56,0x35,  
+    0x8d,0x5b,0x35,  0x75,0x4c,0x2a,  0x8d,0x5b,0x35,  0x5c,0x38,0x22,  
+    0x5e,0x3f,0x27,  0x75,0x4d,0x30,  0x9d,0x64,0x3f,  0x75,0x4c,0x2a,  
+    0x78,0x50,0x2d,  0x7f,0x50,0x2f,  0xb7,0x81,0x58,  0x00,0x00,0x00,  
+    0x46,0x35,0x42,  0x04,0x18,0x3a,  0x08,0x13,0x30,  0x5d,0x30,0x28,  
+    0x20,0x1f,0x36,  0x08,0x13,0x30,  0x08,0x13,0x30,  0x04,0x18,0x3a,  
+    0x19,0x1c,0x37,  0x3a,0x1d,0x16,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x91,0x5f,0x3e,  
+    0x84,0x54,0x33,  0x89,0x58,0x31,  0x7e,0x6e,0x64,  0xc4,0x94,0x6e,  
+    0x78,0x50,0x2d,  0x92,0x6f,0x59,  0xa1,0x7c,0x60,  0x9c,0x6f,0x4b,  
+    0x8d,0x5b,0x35,  0xbc,0x7f,0x53,  0xad,0x71,0x45,  0x75,0x4d,0x30,  
+    0x51,0x35,0x21,  0x4b,0x2f,0x1c,  0x70,0x49,0x2c,  0x00,0x00,0x00,  
+    0x59,0x44,0x4d,  0x1e,0x28,0x42,  0x1e,0x28,0x42,  0x48,0x19,0x10,  
+    0x42,0x19,0x12,  0x53,0x2b,0x30,  0x0c,0x26,0x48,  0x1e,0x28,0x42,  
+    0x24,0x2d,0x48,  0x5f,0x2c,0x1d,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x89,0x58,0x31,  
+    0xa1,0x84,0x6c,  0xc4,0x94,0x6e,  0x88,0x64,0x44,  0xb5,0x8f,0x73,  
+    0x9e,0x72,0x53,  0xa1,0x6d,0x45,  0x93,0x60,0x3a,  0xad,0x71,0x45,  
+    0xb4,0x7f,0x5c,  0xbd,0x8d,0x67,  0xc2,0x8a,0x61,  0xb3,0x76,0x4b,  
+    0xb8,0x7a,0x4f,  0x88,0x64,0x44,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x61,0x50,0x52,  0x1c,0x34,0x52,  0x1c,0x34,0x52,  0x54,0x27,0x16,  
+    0x29,0x17,0x09,  0x5d,0x30,0x28,  0x1c,0x34,0x52,  0x1c,0x34,0x52,  
+    0x24,0x35,0x4f,  0x69,0x34,0x24,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0xa7,0x83,0x6d,  
+    0xac,0x86,0x6a,  0x74,0x47,0x2d,  0x84,0x54,0x33,  0x5c,0x38,0x22,  
+    0x54,0x36,0x1d,  0x6c,0x45,0x29,  0x96,0x63,0x3c,  0xa3,0x6e,0x41,  
+    0xb3,0x76,0x4b,  0xb3,0x76,0x4b,  0xa2,0x68,0x3d,  0x7c,0x4e,0x2d,  
+    0x63,0x3e,0x27,  0x96,0x63,0x3c,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x6b,0x5d,0x59,  0x22,0x42,0x5f,  0x22,0x42,0x5f,  0x5d,0x34,0x1a,  
+    0x38,0x23,0x0f,  0x5c,0x38,0x22,  0x22,0x42,0x5f,  0x22,0x42,0x5f,  
+    0x2c,0x45,0x5e,  0x6f,0x3e,0x2b,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0xb7,0x81,0x58,  
+    0x98,0x74,0x59,  0x6c,0x45,0x29,  0x4b,0x35,0x25,  0x78,0x50,0x2d,  
+    0x78,0x50,0x2d,  0x78,0x50,0x2d,  0x7f,0x50,0x2f,  0x84,0x54,0x33,  
+    0x8d,0x5b,0x35,  0x96,0x63,0x3c,  0x74,0x47,0x2d,  0x65,0x45,0x26,  
+    0x65,0x45,0x26,  0x7c,0x4e,0x2d,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x77,0x69,0x64,  0x30,0x4e,0x6d,  0x32,0x52,0x6b,  0x69,0x42,0x26,  
+    0x49,0x31,0x11,  0x6c,0x47,0x2f,  0x27,0x4f,0x6d,  0x27,0x4f,0x6d,  
+    0x32,0x52,0x6b,  0x70,0x49,0x2c,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0xb7,0x81,0x58,  
+    0x8a,0x5a,0x39,  0x8a,0x5a,0x39,  0x91,0x5f,0x3e,  0x5e,0x3f,0x27,  
+    0x5c,0x38,0x22,  0x89,0x58,0x31,  0x89,0x58,0x31,  0x95,0x5d,0x38,  
+    0x9d,0x64,0x3f,  0x65,0x45,0x26,  0x4b,0x2f,0x1c,  0x7f,0x50,0x2f,  
+    0x78,0x50,0x2d,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x77,0x69,0x64,  0x36,0x5c,0x7a,  0x3e,0x5e,0x78,  0x76,0x52,0x2e,  
+    0x5d,0x42,0x22,  0x75,0x4d,0x30,  0x36,0x5c,0x7a,  0x36,0x5c,0x7a,  
+    0x3e,0x5e,0x78,  0x74,0x47,0x2d,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x89,0x58,0x31,  0x63,0x3e,0x27,  0xa8,0x6d,0x42,  0x4b,0x2f,0x1c,  
+    0x65,0x45,0x26,  0x70,0x49,0x2c,  0x51,0x35,0x21,  0x78,0x50,0x2d,  
+    0x42,0x30,0x14,  0x49,0x31,0x11,  0x59,0x44,0x22,  0x7c,0x5c,0x2a,  
+    0x8a,0x71,0x27,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x71,0x67,0x5c,  0x37,0x52,0x66,  0x3f,0x55,0x64,  0x80,0x55,0x27,  
+    0x64,0x4c,0x1f,  0x7e,0x59,0x2e,  0x37,0x52,0x66,  0x37,0x52,0x66,  
+    0x3f,0x55,0x64,  0x6c,0x47,0x2f,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x70,0x49,0x2c,  0x65,0x45,0x26,  0x65,0x45,0x26,  0x63,0x3e,0x27,  
+    0x76,0x4d,0x25,  0x5d,0x42,0x22,  0x5e,0x3f,0x27,  0x4e,0x43,0x18,  
+    0x4e,0x43,0x18,  0x6a,0x5b,0x1c,  0x4e,0x43,0x18,  0x5f,0x51,0x19,  
+    0x8a,0x76,0x2a,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x63,0x38,0x19,  0x34,0x11,0x04,  0x32,0x0f,0x00,  0x86,0x58,0x1e,  
+    0x74,0x59,0x25,  0x86,0x58,0x1e,  0x34,0x15,0x00,  0x32,0x0f,0x00,  
+    0x34,0x15,0x00,  0x4e,0x31,0x18,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x7e,0x6c,0x27,  0x5a,0x4d,0x1c,  
+    0x4d,0x3e,0x15,  0x67,0x58,0x21,  0x5a,0x4d,0x1c,  0x57,0x4b,0x1a,  
+    0x5f,0x51,0x19,  0x64,0x55,0x1e,  0x5a,0x4d,0x1c,  0x8a,0x71,0x27,  
+    0x8e,0x79,0x26,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x63,0x38,0x19,  0x34,0x11,0x04,  0x32,0x0f,0x00,  0x8d,0x63,0x1f,  
+    0x83,0x66,0x2c,  0x8d,0x63,0x1f,  0x32,0x0f,0x00,  0x35,0x19,0x12,  
+    0x34,0x11,0x04,  0x53,0x3a,0x20,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0xac,0x93,0x39,  0x76,0x65,0x20,  
+    0x6a,0x5b,0x1c,  0x6a,0x5b,0x1c,  0x67,0x58,0x21,  0x4e,0x43,0x18,  
+    0x4e,0x43,0x18,  0x9b,0x85,0x32,  0xb8,0x9e,0x3c,  0xb1,0x8d,0x36,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x63,0x38,0x19,  0x34,0x15,0x00,  0x32,0x0f,0x00,  0x8d,0x63,0x1f,  
+    0x83,0x66,0x2c,  0x8d,0x63,0x1f,  0x32,0x0f,0x00,  0x32,0x0f,0x00,  
+    0x34,0x15,0x00,  0x53,0x3a,0x20,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0xb0,0x96,0x34,  0x76,0x65,0x20,  
+    0x7e,0x66,0x23,  0x8e,0x79,0x26,  0x8a,0x71,0x27,  0x7e,0x6c,0x27,  
+    0x8a,0x71,0x27,  0x8a,0x71,0x27,  0xb0,0x96,0x34,  0x98,0x82,0x2f,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x75,0x4c,0x2a,  0x38,0x19,0x05,  0x38,0x19,0x05,  0x99,0x6d,0x22,  
+    0x96,0x70,0x2a,  0x99,0x6d,0x22,  0x38,0x19,0x05,  0x38,0x19,0x05,  
+    0x38,0x19,0x05,  0x59,0x3f,0x25,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0xac,0x93,0x39,  0x8a,0x76,0x2a,  
+    0x7e,0x66,0x23,  0x76,0x65,0x20,  0x93,0x7d,0x2a,  0x82,0x6f,0x23,  
+    0x9f,0x88,0x35,  0xb8,0xa0,0x4c,  0xb8,0xa0,0x4c,  0xc4,0xa8,0x3f,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x7c,0x5c,0x2a,  0x52,0x2e,0x0d,  0x52,0x2e,0x0d,  0xa4,0x7b,0x27,  
+    0xa1,0x80,0x37,  0x9f,0x77,0x1a,  0x52,0x2e,0x0d,  0x52,0x2e,0x0d,  
+    0x52,0x2e,0x0d,  0x5f,0x4e,0x2a,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x86,0x72,0x26,  
+    0xac,0x93,0x39,  0x97,0x82,0x36,  0xb1,0x8d,0x36,  0xac,0x93,0x39,  
+    0x97,0x82,0x36,  0xa4,0x8c,0x32,  0xbd,0xa2,0x41,  0x8a,0x71,0x27,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x8b,0x6d,0x32,  0x66,0x44,0x14,  0x6d,0x4a,0x20,  0xab,0x86,0x29,  
+    0xb1,0x8d,0x36,  0xa4,0x7b,0x27,  0x66,0x44,0x14,  0x66,0x44,0x14,  
+    0x66,0x44,0x14,  0x69,0x56,0x2c,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0xac,0x93,0x31,  
+    0x7e,0x6c,0x27,  0x9f,0x88,0x35,  0x97,0x82,0x36,  0x7e,0x66,0x23,  
+    0x7e,0x66,0x23,  0xb2,0x99,0x3f,  0xbd,0xa2,0x41,  0x8a,0x76,0x2a,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x99,0x7a,0x38,  0x86,0x58,0x1e,  0x7f,0x59,0x22,  0xb2,0x8b,0x1c,  
+    0x94,0x6e,0x21,  0x7f,0x59,0x22,  0x7f,0x59,0x22,  0x7f,0x59,0x22,  
+    0x7f,0x59,0x22,  0x69,0x56,0x2c,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0xac,0x93,0x39,  
+    0x8a,0x71,0x27,  0xb4,0x9c,0x48,  0x7e,0x66,0x23,  0xac,0x93,0x39,  
+    0x9c,0x87,0x3a,  0x9c,0x87,0x3a,  0xbd,0xa2,0x41,  0x8e,0x79,0x26,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0xa8,0x86,0x3d,  0x96,0x70,0x2a,  0x96,0x70,0x2a,  0x96,0x70,0x2a,  
+    0x96,0x70,0x2a,  0x96,0x70,0x2a,  0x96,0x70,0x2a,  0x96,0x70,0x2a,  
+    0xa1,0x80,0x37,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0xb4,0x9c,0x48,  
+    0xac,0x93,0x31,  0x93,0x7d,0x2a,  0xbd,0xa3,0x48,  0x93,0x7d,0x2a,  
+    0xb8,0xa0,0x4c,  0xb4,0x9c,0x48,  0xcc,0xa5,0x4e,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0xa8,0x86,0x3d,  0xaf,0x85,0x31,  0xaf,0x85,0x31,  0xaf,0x85,0x31,  
+    0xaf,0x85,0x31,  0xaf,0x85,0x31,  0xaf,0x85,0x31,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x97,0x82,0x36,  0xb4,0x9c,0x48,  0xb2,0x99,0x3f,  0xb4,0x9c,0x48,  
+    0xb0,0x96,0x34,  0xc1,0xa7,0x4c,  0x9b,0x84,0x2a,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0xbd,0x9e,0x4c,  0xc7,0x9a,0x3f,  0xc7,0x9a,0x3f,  0xc7,0x9a,0x3f,  
+    0xc7,0x9a,0x3f,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x9b,0x85,0x32,  0xa7,0x8e,0x2c,  0xac,0x93,0x39,  0xb5,0x91,0x41,  
+    0x76,0x65,0x20,  0xa7,0x8e,0x2c,  0xb4,0x9a,0x38,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0xcc,0xa5,0x4e,  0xe0,0xaf,0x45,  0xe0,0xaf,0x45,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0xa4,0x8c,0x32,  0xb8,0x9e,0x44,  0x86,0x72,0x26,  0x9f,0x88,0x35,  
+    0xbd,0xa3,0x48,  0x9b,0x85,0x32,  0xa3,0x81,0x32,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0xd1,0xae,0x4e,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0xb0,0x97,0x3c,  0xb4,0x9a,0x38,  0xac,0x94,0x41,  0xb2,0x99,0x3f,  
+    0xb4,0x9a,0x38,  0xb8,0x9e,0x3c,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0xcc,0xa5,0x4e,  0xa6,0x8f,0x3c,  0xb2,0x99,0x3f,  0xb4,0x9c,0x48,  
+    0xa8,0x90,0x36,  0x9f,0x88,0x35,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  0x00,0x00,0x00,  
+    
+};
index 72a7362a85fa419a3e901d66e66885d1caef2571..9389e84f08408b8b424f52f48e7866439da9ec21 100644 (file)
@@ -1,38 +1,30 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Thing frame/state LUT,
 //     generated by multigen utilitiy.
 //     This one is the original DOOM version, preserved.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: info.c,v 1.3 1997/01/26 07:45:00 b1 Exp $";
+#include <stdio.h>
+#include <stdlib.h>
 
 // Data.
 #include "sounds.h"
 #include "m_fixed.h"
 
-#ifdef __GNUG__
-#pragma implementation "info.h"
-#endif
 #include "info.h"
 
 #include "p_mobj.h"
@@ -51,7 +43,7 @@ char *sprnames[] = {
     "POL3","POL1","POL6","GOR2","GOR3","GOR4","GOR5","SMIT","COL1","COL2",
     "COL3","COL4","CAND","CBRA","COL6","TRE1","TRE2","ELEC","CEYE","FSKU",
     "COL5","TBLU","TGRN","TRED","SMBT","SMGT","SMRT","HDB1","HDB2","HDB3",
-    "HDB4","HDB5","HDB6","POB1","POB2","BRS1","TLMP","TLP2",NULL,"DUMM"
+    "HDB4","HDB5","HDB6","POB1","POB2","BRS1","TLMP","TLP2", NULL
 };
 
 
index cc35e3340ba2dc8cd9d42e1b3798762574871459..648b518889501d315d1e487e020ea62be4f98f28 100644 (file)
@@ -1,25 +1,22 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Thing frame/state LUT,
 //     generated by multigen utilitiy.
 //     This one is the original DOOM version, preserved.
 //
-//-----------------------------------------------------------------------------
 
 #ifndef __INFO__
 #define __INFO__
@@ -1146,20 +1143,19 @@ typedef enum
 
 typedef struct
 {
-  spritenum_t  sprite;
-  long                 frame;
-  long                 tics;
-  // void              (*action) ();
-  actionf_t                    action;
-  statenum_t                   nextstate;
-  long                 misc1, misc2;
+    spritenum_t sprite;
+    int frame;
+    int tics;
+    // void (*action) ();
+    actionf_t action;
+    statenum_t nextstate;
+    int misc1;
+    int misc2;
 } state_t;
 
 extern state_t states[NUMSTATES];
 extern char *sprnames[];
 
-
-
 typedef enum {
     MT_PLAYER,
     MT_POSSESSED,
@@ -1333,8 +1329,3 @@ typedef struct
 extern mobjinfo_t mobjinfo[NUMMOBJTYPES];
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 15956711a796bce2f58361b4bb02f4765f5b16f7..1582450feb63631182998f2b823f848403594864 100644 (file)
@@ -1,31 +1,31 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //
-//-----------------------------------------------------------------------------
-
-static const char
-rcsid[] = "$Id: m_argv.c,v 1.1 1997/02/03 22:45:10 b1 Exp $";
 
 
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
+#include "doomtype.h"
+#include "i_system.h"
+#include "m_misc.h"
+#include "m_argv.h"  // haleyjd 20110212: warning fix
+
 int            myargc;
 char**         myargv;
 
@@ -38,19 +38,228 @@ char**             myargv;
 // in the program's command line arguments.
 // Returns the argument number (1 to argc-1)
 // or 0 if not present
-int M_CheckParm (char *check)
+//
+
+int M_CheckParmWithArgs(char *check, int num_args)
 {
-    int                i;
+    int i;
 
-    for (i = 1;i<myargc;i++)
+    for (i = 1; i < myargc - num_args; i++)
     {
-       if ( !strcasecmp(check, myargv[i]) )
+       if (!strcasecmp(check, myargv[i]))
            return i;
     }
 
     return 0;
 }
 
+//
+// M_ParmExists
+//
+// Returns true if the given parameter exists in the program's command
+// line arguments, false if not.
+//
+
+boolean M_ParmExists(char *check)
+{
+    return M_CheckParm(check) != 0;
+}
+
+int M_CheckParm(char *check)
+{
+    return M_CheckParmWithArgs(check, 0);
+}
+
+#define MAXARGVS        100
+
+static void LoadResponseFile(int argv_index)
+{
+#if ORIGCODE
+    FILE *handle;
+    int size;
+    char *infile;
+    char *file;
+    char *response_filename;
+    char **newargv;
+    int newargc;
+    int i, k;
+
+    response_filename = myargv[argv_index] + 1;
+
+    // Read the response file into memory
+    handle = fopen(response_filename, "rb");
+
+    if (handle == NULL)
+    {
+        printf ("\nNo such response file!");
+#if ORIGCODE
+        exit(1);
+#endif
+    }
+
+    printf("Found response file %s!\n", response_filename);
+
+    size = M_FileLength(handle);
+
+    // Read in the entire file
+    // Allocate one byte extra - this is in case there is an argument
+    // at the end of the response file, in which case a '\0' will be
+    // needed.
+
+    file = malloc(size + 1);
+
+    i = 0;
+
+    while (i < size)
+    {
+        k = fread(file + i, 1, size - i, handle);
+
+        if (k < 0)
+        {
+            I_Error("Failed to read full contents of '%s'", response_filename);
+        }
+
+        i += k;
+    }
+
+    fclose(handle);
+
+    // Create new arguments list array
+
+    newargv = malloc(sizeof(char *) * MAXARGVS);
+    newargc = 0;
+    memset(newargv, 0, sizeof(char *) * MAXARGVS);
+
+    // Copy all the arguments in the list up to the response file
+
+    for (i=0; i<argv_index; ++i)
+    {
+        newargv[i] = myargv[i];
+        ++newargc;
+    }
+
+    infile = file;
+    k = 0;
+
+    while(k < size)
+    {
+        // Skip past space characters to the next argument
+
+        while(k < size && isspace((int)infile[k]))
+        {
+            ++k;
+        }
 
+        if (k >= size)
+        {
+            break;
+        }
 
+        // If the next argument is enclosed in quote marks, treat
+        // the contents as a single argument.  This allows long filenames
+        // to be specified.
+
+        if (infile[k] == '\"')
+        {
+            // Skip the first character(")
+            ++k;
+
+            newargv[newargc++] = &infile[k];
+
+            // Read all characters between quotes
+
+            while (k < size && infile[k] != '\"' && infile[k] != '\n')
+            {
+                ++k;
+            }
+
+            if (k >= size || infile[k] == '\n')
+            {
+                I_Error("Quotes unclosed in response file '%s'",
+                        response_filename);
+            }
+
+            // Cut off the string at the closing quote
+
+            infile[k] = '\0';
+            ++k;
+        }
+        else
+        {
+            // Read in the next argument until a space is reached
+
+            newargv[newargc++] = &infile[k];
+
+            while(k < size && !isspace((int)infile[k]))
+            {
+                ++k;
+            }
+
+            // Cut off the end of the argument at the first space
+
+            infile[k] = '\0';
+
+            ++k;
+        }
+    }
+
+    // Add arguments following the response file argument
+
+    for (i=argv_index + 1; i<myargc; ++i)
+    {
+        newargv[newargc] = myargv[i];
+        ++newargc;
+    }
+
+    myargv = newargv;
+    myargc = newargc;
+
+#if 0
+    // Disabled - Vanilla Doom does not do this.
+    // Display arguments
+
+    printf("%d command-line args:\n", myargc);
+
+    for (k=1; k<myargc; k++)
+    {
+        printf("'%s'\n", myargv[k]);
+    }
+#endif
+#endif
+}
+
+//
+// Find a Response File
+//
+
+void M_FindResponseFile(void)
+{
+    int             i;
+
+    for (i = 1; i < myargc; i++)
+    {
+        if (myargv[i][0] == '@')
+        {
+            LoadResponseFile(i);
+        }
+    }
+}
+
+// Return the name of the executable used to start the program:
+
+char *M_GetExecutableName(void)
+{
+    char *sep;
+
+    sep = strrchr(myargv[0], DIR_SEPARATOR);
+
+    if (sep == NULL)
+    {
+        return myargv[0];
+    }
+    else
+    {
+        return sep + 1;
+    }
+}
 
index b1bb1047b9ebbbf4ba6fec3b167f3317acdcea35..b576f6cedccc293d9f69c3618ee75230d742a830 100644 (file)
@@ -1,28 +1,27 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //  Nil.
 //    
-//-----------------------------------------------------------------------------
 
 
 #ifndef __M_ARGV__
 #define __M_ARGV__
 
+#include "doomtype.h"
+
 //
 // MISC
 //
@@ -33,10 +32,18 @@ extern  char**      myargv;
 // in the arg list (0 if not found).
 int M_CheckParm (char* check);
 
+// Same as M_CheckParm, but checks that num_args arguments are available
+// following the specified argument.
+int M_CheckParmWithArgs(char *check, int num_args);
+
+void M_FindResponseFile(void);
+
+// Parameter has been specified?
+
+boolean M_ParmExists(char *check);
+
+// Get name of executable used to run this program:
+
+char *M_GetExecutableName(void);
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 2b6abab15ef5a8c90c79a8cbc56b37c6d2165e38..fb3f270d1b4d2cebe109e2def7815ef050ee58b2 100644 (file)
@@ -1,20 +1,16 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Main loop menu stuff.
 //     Default Config File.
 //     PCX Screenshots.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $";
 
 
-#ifdef __GNUG__
-#pragma implementation "m_bbox.h"
-#endif
 #include "m_bbox.h"
 
 
@@ -38,8 +28,8 @@ rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $";
 
 void M_ClearBox (fixed_t *box)
 {
-    box[BOXTOP] = box[BOXRIGHT] = MININT;
-    box[BOXBOTTOM] = box[BOXLEFT] = MAXINT;
+    box[BOXTOP] = box[BOXRIGHT] = INT_MIN;
+    box[BOXBOTTOM] = box[BOXLEFT] = INT_MAX;
 }
 
 void
index 66be2fbd51d332a0b59af4ad9857f38a57d4d8bd..5a7af57c458da777d2a4105cad51c391de1f104e 100644 (file)
@@ -1,29 +1,26 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //    Nil.
 //    
-//-----------------------------------------------------------------------------
 
 
 #ifndef __M_BBOX__
 #define __M_BBOX__
 
-#include <values.h>
+#include <limits.h>
 
 #include "m_fixed.h"
 
@@ -48,8 +45,3 @@ M_AddToBox
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index e5d428404887879ef895adf316889c6a67a6a91d..1565f9ef5e3b5091842e4297bb448806634be993 100644 (file)
@@ -1,40 +1,32 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Cheat sequence checking.
 //
-//-----------------------------------------------------------------------------
 
 
-static const char
-rcsid[] = "$Id: m_cheat.c,v 1.1 1997/02/03 21:24:34 b1 Exp $";
 
+#include <string.h>
+
+#include "doomtype.h"
 #include "m_cheat.h"
 
 //
 // CHEAT SEQUENCE PACKAGE
 //
 
-static int             firsttime = 1;
-static unsigned char   cheat_xlate_table[256];
-
-
 //
 // Called in st_stuff module, which handles the input.
 // Returns a 1 if the cheat was successful, 0 if failed.
@@ -44,34 +36,46 @@ cht_CheckCheat
 ( cheatseq_t*  cht,
   char         key )
 {
-    int i;
-    int rc = 0;
+    // if we make a short sequence on a cheat with parameters, this 
+    // will not work in vanilla doom.  behave the same.
 
-    if (firsttime)
+    if (cht->parameter_chars > 0 && strlen(cht->sequence) < cht->sequence_len)
+        return false;
+    
+    if (cht->chars_read < strlen(cht->sequence))
     {
-       firsttime = 0;
-       for (i=0;i<256;i++) cheat_xlate_table[i] = SCRAMBLE(i);
+        // still reading characters from the cheat code
+        // and verifying.  reset back to the beginning 
+        // if a key is wrong
+
+        if (key == cht->sequence[cht->chars_read])
+            ++cht->chars_read;
+        else
+            cht->chars_read = 0;
+        
+        cht->param_chars_read = 0;
+    }
+    else if (cht->param_chars_read < cht->parameter_chars)
+    {
+        // we have passed the end of the cheat sequence and are 
+        // entering parameters now 
+        
+        cht->parameter_buf[cht->param_chars_read] = key;
+        
+        ++cht->param_chars_read;
     }
 
-    if (!cht->p)
-       cht->p = cht->sequence; // initialize if first time
-
-    if (*cht->p == 0)
-       *(cht->p++) = key;
-    else if
-       (cheat_xlate_table[(unsigned char)key] == *cht->p) cht->p++;
-    else
-       cht->p = cht->sequence;
-
-    if (*cht->p == 1)
-       cht->p++;
-    else if (*cht->p == 0xff) // end of sequence character
+    if (cht->chars_read >= strlen(cht->sequence)
+     && cht->param_chars_read >= cht->parameter_chars)
     {
-       cht->p = cht->sequence;
-       rc = 1;
+        cht->chars_read = cht->param_chars_read = 0;
+
+        return true;
     }
+    
+    // cheat not matched yet
 
-    return rc;
+    return false;
 }
 
 void
@@ -79,23 +83,7 @@ cht_GetParam
 ( cheatseq_t*  cht,
   char*                buffer )
 {
-
-    unsigned char *p, c;
-
-    p = cht->sequence;
-    while (*(p++) != 1);
-    
-    do
-    {
-       c = *p;
-       *(buffer++) = c;
-       *(p++) = 0;
-    }
-    while (c && *p!=0xff );
-
-    if (*p==0xff)
-       *buffer = 0;
-
+    memcpy(buffer, cht->parameter_buf, cht->parameter_chars);
 }
 
 
index 36463689e6c2076b3fa7470af843b7c327bfe859..6775e709e4165581ebade229da62097eb57d97f7 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Cheat code checking.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __M_CHEAT__
 // CHEAT SEQUENCE PACKAGE
 //
 
-#define SCRAMBLE(a) \
-((((a)&1)<<7) + (((a)&2)<<5) + ((a)&4) + (((a)&8)<<1) \
- + (((a)&16)>>1) + ((a)&32) + (((a)&64)>>5) + (((a)&128)>>7))
+// declaring a cheat
+
+#define CHEAT(value, parameters) \
+    { value, sizeof(value) - 1, parameters, 0, 0, "" }
+
+#define MAX_CHEAT_LEN 25
+#define MAX_CHEAT_PARAMS 5
 
 typedef struct
 {
-    unsigned char*     sequence;
-    unsigned char*     p;
-    
+    // settings for this cheat
+
+    char sequence[MAX_CHEAT_LEN];
+    size_t sequence_len;
+    int parameter_chars;
+
+    // state used during the game
+
+    size_t chars_read;
+    int param_chars_read;
+    char parameter_buf[MAX_CHEAT_PARAMS];
 } cheatseq_t;
 
 int
@@ -51,8 +60,3 @@ cht_GetParam
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
diff --git a/frosted-doom/m_config.c b/frosted-doom/m_config.c
new file mode 100644 (file)
index 0000000..31ac7a6
--- /dev/null
@@ -0,0 +1,2150 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// 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.
+//
+// DESCRIPTION:
+//    Configuration file interface.
+//
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "config.h"
+
+#include "doomtype.h"
+#include "doomkeys.h"
+#include "doomfeatures.h"
+#include "i_system.h"
+#include "m_argv.h"
+#include "m_misc.h"
+
+#include "z_zone.h"
+
+//
+// DEFAULTS
+//
+
+// Location where all configuration data is stored - 
+// default.cfg, savegames, etc.
+
+char *configdir;
+
+// Default filenames for configuration files.
+
+static char *default_main_config;
+static char *default_extra_config;
+
+typedef enum 
+{
+    DEFAULT_INT,
+    DEFAULT_INT_HEX,
+    DEFAULT_STRING,
+    DEFAULT_FLOAT,
+    DEFAULT_KEY,
+} default_type_t;
+
+typedef struct
+{
+    // Name of the variable
+    char *name;
+
+    // Pointer to the location in memory of the variable
+    void *location;
+
+    // Type of the variable
+    default_type_t type;
+
+    // If this is a key value, the original integer scancode we read from
+    // the config file before translating it to the internal key value.
+    // If zero, we didn't read this value from a config file.
+    int untranslated;
+
+    // The value we translated the scancode into when we read the 
+    // config file on startup.  If the variable value is different from
+    // this, it has been changed and needs to be converted; otherwise,
+    // use the 'untranslated' value.
+    int original_translated;
+
+    // If true, this config variable has been bound to a variable
+    // and is being used.
+    boolean bound;
+} default_t;
+
+typedef struct
+{
+    default_t *defaults;
+    int numdefaults;
+    char *filename;
+} default_collection_t;
+
+#define CONFIG_VARIABLE_GENERIC(name, type) \
+    { #name, NULL, type, 0, 0, false }
+
+#define CONFIG_VARIABLE_KEY(name) \
+    CONFIG_VARIABLE_GENERIC(name, DEFAULT_KEY)
+#define CONFIG_VARIABLE_INT(name) \
+    CONFIG_VARIABLE_GENERIC(name, DEFAULT_INT)
+#define CONFIG_VARIABLE_INT_HEX(name) \
+    CONFIG_VARIABLE_GENERIC(name, DEFAULT_INT_HEX)
+#define CONFIG_VARIABLE_FLOAT(name) \
+    CONFIG_VARIABLE_GENERIC(name, DEFAULT_FLOAT)
+#define CONFIG_VARIABLE_STRING(name) \
+    CONFIG_VARIABLE_GENERIC(name, DEFAULT_STRING)
+
+//! @begin_config_file default
+
+static default_t       doom_defaults_list[] =
+{
+    //!
+    // Mouse sensitivity.  This value is used to multiply input mouse
+    // movement to control the effect of moving the mouse.
+    //
+    // The "normal" maximum value available for this through the
+    // in-game options menu is 9. A value of 31 or greater will cause
+    // the game to crash when entering the options menu.
+    //
+
+    CONFIG_VARIABLE_INT(mouse_sensitivity),
+
+    //!
+    // Volume of sound effects, range 0-15.
+    //
+
+    CONFIG_VARIABLE_INT(sfx_volume),
+
+    //!
+    // Volume of in-game music, range 0-15.
+    //
+
+    CONFIG_VARIABLE_INT(music_volume),
+
+    //!
+    // @game strife
+    //
+    // If non-zero, dialogue text is displayed over characters' pictures
+    // when engaging actors who have voices.
+    //
+
+    CONFIG_VARIABLE_INT(show_talk),
+
+    //!
+    // @game strife
+    //
+    // Volume of voice sound effects, range 0-15.
+    //
+
+    CONFIG_VARIABLE_INT(voice_volume),
+
+    //!
+    // @game doom
+    //
+    // If non-zero, messages are displayed on the heads-up display
+    // in the game ("picked up a clip", etc).  If zero, these messages
+    // are not displayed.
+    //
+
+    CONFIG_VARIABLE_INT(show_messages),
+
+    //!
+    // Keyboard key to turn right.
+    //
+
+    CONFIG_VARIABLE_KEY(key_right),
+
+    //!
+    // Keyboard key to turn left.
+    //
+
+    CONFIG_VARIABLE_KEY(key_left),
+
+    //!
+    // Keyboard key to move forward.
+    //
+
+    CONFIG_VARIABLE_KEY(key_up),
+
+    //!
+    // Keyboard key to move backward.
+    //
+
+    CONFIG_VARIABLE_KEY(key_down),
+
+    //!
+    // Keyboard key to strafe left.
+    //
+
+    CONFIG_VARIABLE_KEY(key_strafeleft),
+
+    //!
+    // Keyboard key to strafe right.
+    //
+
+    CONFIG_VARIABLE_KEY(key_straferight),
+
+    //!
+    // @game strife
+    //
+    // Keyboard key to use health.
+    //
+
+    CONFIG_VARIABLE_KEY(key_useHealth),
+
+    //!
+    // @game hexen
+    //
+    // Keyboard key to jump.
+    //
+
+    CONFIG_VARIABLE_KEY(key_jump),
+
+    //!
+    // @game heretic hexen
+    //
+    // Keyboard key to fly upward.
+    //
+
+    CONFIG_VARIABLE_KEY(key_flyup),
+
+    //!
+    // @game heretic hexen
+    //
+    // Keyboard key to fly downwards.
+    //
+
+    CONFIG_VARIABLE_KEY(key_flydown),
+
+    //!
+    // @game heretic hexen
+    //
+    // Keyboard key to center flying.
+    //
+
+    CONFIG_VARIABLE_KEY(key_flycenter),
+
+    //!
+    // @game heretic hexen
+    //
+    // Keyboard key to look up.
+    //
+
+    CONFIG_VARIABLE_KEY(key_lookup),
+
+    //!
+    // @game heretic hexen
+    //
+    // Keyboard key to look down.
+    //
+
+    CONFIG_VARIABLE_KEY(key_lookdown),
+
+    //!
+    // @game heretic hexen
+    //
+    // Keyboard key to center the view.
+    //
+
+    CONFIG_VARIABLE_KEY(key_lookcenter),
+
+    //!
+    // @game strife
+    //
+    // Keyboard key to query inventory.
+    //
+
+    CONFIG_VARIABLE_KEY(key_invquery),
+
+    //!
+    // @game strife
+    //
+    // Keyboard key to display mission objective.
+    //
+
+    CONFIG_VARIABLE_KEY(key_mission),
+
+    //!
+    // @game strife
+    //
+    // Keyboard key to display inventory popup.
+    //
+
+    CONFIG_VARIABLE_KEY(key_invPop),
+
+    //!
+    // @game strife
+    //
+    // Keyboard key to display keys popup.
+    //
+
+    CONFIG_VARIABLE_KEY(key_invKey),
+
+    //!
+    // @game strife
+    //
+    // Keyboard key to jump to start of inventory.
+    //
+
+    CONFIG_VARIABLE_KEY(key_invHome),
+
+    //!
+    // @game strife
+    //
+    // Keyboard key to jump to end of inventory.
+    //
+
+    CONFIG_VARIABLE_KEY(key_invEnd),
+
+    //!
+    // @game heretic hexen
+    //
+    // Keyboard key to scroll left in the inventory.
+    //
+
+    CONFIG_VARIABLE_KEY(key_invleft),
+
+    //!
+    // @game heretic hexen
+    //
+    // Keyboard key to scroll right in the inventory.
+    //
+
+    CONFIG_VARIABLE_KEY(key_invright),
+
+    //!
+    // @game strife
+    //
+    // Keyboard key to scroll left in the inventory.
+    //
+
+    CONFIG_VARIABLE_KEY(key_invLeft),
+
+    //!
+    // @game strife
+    //
+    // Keyboard key to scroll right in the inventory.
+    //
+
+    CONFIG_VARIABLE_KEY(key_invRight),
+
+    //!
+    // @game heretic hexen
+    //
+    // Keyboard key to use the current item in the inventory.
+    //
+
+    CONFIG_VARIABLE_KEY(key_useartifact),
+
+    //!
+    // @game strife
+    //
+    // Keyboard key to use inventory item.
+    //
+
+    CONFIG_VARIABLE_KEY(key_invUse),
+
+    //!
+    // @game strife
+    //
+    // Keyboard key to drop an inventory item.
+    //
+
+    CONFIG_VARIABLE_KEY(key_invDrop),
+
+    //!
+    // @game strife
+    //
+    // Keyboard key to look up.
+    //
+
+    CONFIG_VARIABLE_KEY(key_lookUp),
+
+    //!
+    // @game strife
+    //
+    // Keyboard key to look down.
+    //
+
+    CONFIG_VARIABLE_KEY(key_lookDown),
+
+    //!
+    // Keyboard key to fire the currently selected weapon.
+    //
+
+    CONFIG_VARIABLE_KEY(key_fire),
+
+    //!
+    // Keyboard key to "use" an object, eg. a door or switch.
+    //
+
+    CONFIG_VARIABLE_KEY(key_use),
+
+    //!
+    // Keyboard key to turn on strafing.  When held down, pressing the
+    // key to turn left or right causes the player to strafe left or
+    // right instead.
+    //
+
+    CONFIG_VARIABLE_KEY(key_strafe),
+
+    //!
+    // Keyboard key to make the player run.
+    //
+
+    CONFIG_VARIABLE_KEY(key_speed),
+
+    //!
+    // If non-zero, mouse input is enabled.  If zero, mouse input is
+    // disabled.
+    //
+
+    CONFIG_VARIABLE_INT(use_mouse),
+
+    //!
+    // Mouse button to fire the currently selected weapon.
+    //
+
+    CONFIG_VARIABLE_INT(mouseb_fire),
+
+    //!
+    // Mouse button to turn on strafing.  When held down, the player
+    // will strafe left and right instead of turning left and right.
+    //
+
+    CONFIG_VARIABLE_INT(mouseb_strafe),
+
+    //!
+    // Mouse button to move forward.
+    //
+
+    CONFIG_VARIABLE_INT(mouseb_forward),
+
+    //!
+    // @game hexen strife
+    //
+    // Mouse button to jump.
+    //
+
+    CONFIG_VARIABLE_INT(mouseb_jump),
+
+    //!
+    // If non-zero, joystick input is enabled.
+    //
+
+    CONFIG_VARIABLE_INT(use_joystick),
+
+    //!
+    // Joystick virtual button that fires the current weapon.
+    //
+
+    CONFIG_VARIABLE_INT(joyb_fire),
+
+    //!
+    // Joystick virtual button that makes the player strafe while
+    // held down.
+    //
+
+    CONFIG_VARIABLE_INT(joyb_strafe),
+
+    //!
+    // Joystick virtual button to "use" an object, eg. a door or switch.
+    //
+
+    CONFIG_VARIABLE_INT(joyb_use),
+
+    //!
+    // Joystick virtual button that makes the player run while held
+    // down.
+    //
+    // If this has a value of 20 or greater, the player will always run,
+    // even if use_joystick is 0.
+    //
+
+    CONFIG_VARIABLE_INT(joyb_speed),
+
+    //!
+    // @game hexen strife
+    //
+    // Joystick virtual button that makes the player jump.
+    //
+
+    CONFIG_VARIABLE_INT(joyb_jump),
+
+    //!
+    // @game doom heretic hexen
+    //
+    // Screen size, range 3-11.
+    //
+    // A value of 11 gives a full-screen view with the status bar not
+    // displayed.  A value of 10 gives a full-screen view with the
+    // status bar displayed.
+    //
+
+    CONFIG_VARIABLE_INT(screenblocks),
+
+    //!
+    // @game strife
+    //
+    // Screen size, range 3-11.
+    //
+    // A value of 11 gives a full-screen view with the status bar not
+    // displayed.  A value of 10 gives a full-screen view with the
+    // status bar displayed.
+    //
+
+    CONFIG_VARIABLE_INT(screensize),
+
+    //!
+    // @game doom
+    //
+    // Screen detail.  Zero gives normal "high detail" mode, while
+    // a non-zero value gives "low detail" mode.
+    //
+
+    CONFIG_VARIABLE_INT(detaillevel),
+
+    //!
+    // Number of sounds that will be played simultaneously.
+    //
+
+    CONFIG_VARIABLE_INT(snd_channels),
+
+    //!
+    // Music output device.  A non-zero value gives MIDI sound output,
+    // while a value of zero disables music.
+    //
+
+    CONFIG_VARIABLE_INT(snd_musicdevice),
+
+    //!
+    // Sound effects device.  A value of zero disables in-game sound
+    // effects, a value of 1 enables PC speaker sound effects, while
+    // a value in the range 2-9 enables the "normal" digital sound
+    // effects.
+    //
+
+    CONFIG_VARIABLE_INT(snd_sfxdevice),
+
+    //!
+    // SoundBlaster I/O port. Unused.
+    //
+
+    CONFIG_VARIABLE_INT(snd_sbport),
+
+    //!
+    // SoundBlaster IRQ.  Unused.
+    //
+
+    CONFIG_VARIABLE_INT(snd_sbirq),
+
+    //!
+    // SoundBlaster DMA channel.  Unused.
+    //
+
+    CONFIG_VARIABLE_INT(snd_sbdma),
+
+    //!
+    // Output port to use for OPL MIDI playback.  Unused.
+    //
+
+    CONFIG_VARIABLE_INT(snd_mport),
+
+    //!
+    // Gamma correction level.  A value of zero disables gamma
+    // correction, while a value in the range 1-4 gives increasing
+    // levels of gamma correction.
+    //
+
+    CONFIG_VARIABLE_INT(usegamma),
+
+    //!
+    // @game hexen
+    //
+    // Directory in which to store savegames.
+    //
+
+    CONFIG_VARIABLE_STRING(savedir),
+
+    //!
+    // @game hexen
+    //
+    // Controls whether messages are displayed in the heads-up display.
+    // If this has a non-zero value, messages are displayed.
+    //
+
+    CONFIG_VARIABLE_INT(messageson),
+
+    //!
+    // @game strife
+    //
+    // Name of background flat used by view border.
+    //
+
+    CONFIG_VARIABLE_STRING(back_flat),
+
+    //!
+    // @game strife
+    //
+    // Multiplayer nickname (?).
+    //
+
+    CONFIG_VARIABLE_STRING(nickname),
+
+    //!
+    // Multiplayer chat macro: message to send when alt+0 is pressed.
+    //
+
+    CONFIG_VARIABLE_STRING(chatmacro0),
+
+    //!
+    // Multiplayer chat macro: message to send when alt+1 is pressed.
+    //
+
+    CONFIG_VARIABLE_STRING(chatmacro1),
+
+    //!
+    // Multiplayer chat macro: message to send when alt+2 is pressed.
+    //
+
+    CONFIG_VARIABLE_STRING(chatmacro2),
+
+    //!
+    // Multiplayer chat macro: message to send when alt+3 is pressed.
+    //
+
+    CONFIG_VARIABLE_STRING(chatmacro3),
+
+    //!
+    // Multiplayer chat macro: message to send when alt+4 is pressed.
+    //
+
+    CONFIG_VARIABLE_STRING(chatmacro4),
+
+    //!
+    // Multiplayer chat macro: message to send when alt+5 is pressed.
+    //
+
+    CONFIG_VARIABLE_STRING(chatmacro5),
+
+    //!
+    // Multiplayer chat macro: message to send when alt+6 is pressed.
+    //
+
+    CONFIG_VARIABLE_STRING(chatmacro6),
+
+    //!
+    // Multiplayer chat macro: message to send when alt+7 is pressed.
+    //
+
+    CONFIG_VARIABLE_STRING(chatmacro7),
+
+    //!
+    // Multiplayer chat macro: message to send when alt+8 is pressed.
+    //
+
+    CONFIG_VARIABLE_STRING(chatmacro8),
+
+    //!
+    // Multiplayer chat macro: message to send when alt+9 is pressed.
+    //
+
+    CONFIG_VARIABLE_STRING(chatmacro9),
+
+    //!
+    // @game strife
+    //
+    // Serial port number to use for SERSETUP.EXE (unused).
+    //
+
+    CONFIG_VARIABLE_INT(comport),
+};
+
+static default_collection_t doom_defaults =
+{
+    doom_defaults_list,
+    arrlen(doom_defaults_list),
+    NULL,
+};
+
+//! @begin_config_file extended
+
+static default_t extra_defaults_list[] =
+{
+    //!
+    // @game heretic hexen strife
+    //
+    // If non-zero, display the graphical startup screen.
+    //
+
+    CONFIG_VARIABLE_INT(graphical_startup),
+
+    //!
+    // If non-zero, video settings will be autoadjusted to a valid
+    // configuration when the screen_width and screen_height variables
+    // do not match any valid configuration.
+    //
+
+    CONFIG_VARIABLE_INT(autoadjust_video_settings),
+
+    //!
+    // If non-zero, the game will run in full screen mode.  If zero,
+    // the game will run in a window.
+    //
+
+    CONFIG_VARIABLE_INT(fullscreen),
+
+    //!
+    // If non-zero, the screen will be stretched vertically to display
+    // correctly on a square pixel video mode.
+    //
+
+    CONFIG_VARIABLE_INT(aspect_ratio_correct),
+
+    //!
+    // Number of milliseconds to wait on startup after the video mode
+    // has been set, before the game will start.  This allows the
+    // screen to settle on some monitors that do not display an image
+    // for a brief interval after changing video modes.
+    //
+
+    CONFIG_VARIABLE_INT(startup_delay),
+
+    //!
+    // Screen width in pixels.  If running in full screen mode, this is
+    // the X dimension of the video mode to use.  If running in
+    // windowed mode, this is the width of the window in which the game
+    // will run.
+    //
+
+    CONFIG_VARIABLE_INT(screen_width),
+
+    //!
+    // Screen height in pixels.  If running in full screen mode, this is
+    // the Y dimension of the video mode to use.  If running in
+    // windowed mode, this is the height of the window in which the game
+    // will run.
+    //
+
+    CONFIG_VARIABLE_INT(screen_height),
+
+    //!
+    // Color depth of the screen, in bits.
+    // If this is set to zero, the color depth will be automatically set
+    // on startup to the machine's default/native color depth.
+    //
+
+    CONFIG_VARIABLE_INT(screen_bpp),
+
+    //!
+    // If this is non-zero, the mouse will be "grabbed" when running
+    // in windowed mode so that it can be used as an input device.
+    // When running full screen, this has no effect.
+    //
+
+    CONFIG_VARIABLE_INT(grabmouse),
+
+    //!
+    // If non-zero, all vertical mouse movement is ignored.  This
+    // emulates the behavior of the "novert" tool available under DOS
+    // that performs the same function.
+    //
+
+    CONFIG_VARIABLE_INT(novert),
+
+    //!
+    // Mouse acceleration factor.  When the speed of mouse movement
+    // exceeds the threshold value (mouse_threshold), the speed is
+    // multiplied by this value.
+    //
+
+    CONFIG_VARIABLE_FLOAT(mouse_acceleration),
+
+    //!
+    // Mouse acceleration threshold.  When the speed of mouse movement
+    // exceeds this threshold value, the speed is multiplied by an
+    // acceleration factor (mouse_acceleration).
+    //
+
+    CONFIG_VARIABLE_INT(mouse_threshold),
+
+    //!
+    // Sound output sample rate, in Hz.  Typical values to use are
+    // 11025, 22050, 44100 and 48000.
+    //
+
+    CONFIG_VARIABLE_INT(snd_samplerate),
+
+    //!
+    // Maximum number of bytes to allocate for caching converted sound
+    // effects in memory. If set to zero, there is no limit applied.
+    //
+
+    CONFIG_VARIABLE_INT(snd_cachesize),
+
+    //!
+    // Maximum size of the output sound buffer size in milliseconds.
+    // Sound output is generated periodically in slices. Higher values
+    // might be more efficient but will introduce latency to the
+    // sound output. The default is 28ms (one slice per tic with the
+    // 35fps timer).
+
+    CONFIG_VARIABLE_INT(snd_maxslicetime_ms),
+
+    //!
+    // External command to invoke to perform MIDI playback. If set to
+    // the empty string, SDL_mixer's internal MIDI playback is used.
+    // This only has any effect when snd_musicdevice is set to General
+    // MIDI output.
+
+    CONFIG_VARIABLE_STRING(snd_musiccmd),
+
+    //!
+    // The I/O port to use to access the OPL chip.  Only relevant when
+    // using native OPL music playback.
+    //
+
+    CONFIG_VARIABLE_INT_HEX(opl_io_port),
+
+    //!
+    // @game doom heretic strife
+    //
+    // If non-zero, the ENDOOM text screen is displayed when exiting the
+    // game. If zero, the ENDOOM screen is not displayed.
+    //
+
+    CONFIG_VARIABLE_INT(show_endoom),
+
+    //!
+    // If non-zero, save screenshots in PNG format.
+    //
+
+    CONFIG_VARIABLE_INT(png_screenshots),
+
+    //!
+    // @game doom strife
+    //
+    // If non-zero, the Vanilla savegame limit is enforced; if the
+    // savegame exceeds 180224 bytes in size, the game will exit with
+    // an error.  If this has a value of zero, there is no limit to
+    // the size of savegames.
+    //
+
+    CONFIG_VARIABLE_INT(vanilla_savegame_limit),
+
+    //!
+    // @game doom strife
+    //
+    // If non-zero, the Vanilla demo size limit is enforced; the game
+    // exits with an error when a demo exceeds the demo size limit
+    // (128KiB by default).  If this has a value of zero, there is no
+    // limit to the size of demos.
+    //
+
+    CONFIG_VARIABLE_INT(vanilla_demo_limit),
+
+    //!
+    // If non-zero, the game behaves like Vanilla Doom, always assuming
+    // an American keyboard mapping.  If this has a value of zero, the
+    // native keyboard mapping of the keyboard is used.
+    //
+
+    CONFIG_VARIABLE_INT(vanilla_keyboard_mapping),
+
+    //!
+    // Name of the SDL video driver to use.  If this is an empty string,
+    // the default video driver is used.
+    //
+
+    CONFIG_VARIABLE_STRING(video_driver),
+
+    //!
+    // Position of the window on the screen when running in windowed
+    // mode. Accepted values are: "" (empty string) - don't care,
+    // "center" - place window at center of screen, "x,y" - place
+    // window at the specified coordinates.
+
+    CONFIG_VARIABLE_STRING(window_position),
+
+#ifdef FEATURE_MULTIPLAYER
+
+    //!
+    // Name to use in network games for identification.  This is only
+    // used on the "waiting" screen while waiting for the game to start.
+    //
+
+    CONFIG_VARIABLE_STRING(player_name),
+
+#endif
+
+    //!
+    // Joystick number to use; '0' is the first joystick.  A negative
+    // value ('-1') indicates that no joystick is configured.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_index),
+
+    //!
+    // Joystick axis to use to for horizontal (X) movement.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_x_axis),
+
+    //!
+    // If non-zero, movement on the horizontal joystick axis is inverted.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_x_invert),
+
+    //!
+    // Joystick axis to use to for vertical (Y) movement.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_y_axis),
+
+    //!
+    // If non-zero, movement on the vertical joystick axis is inverted.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_y_invert),
+
+    //!
+    // Joystick axis to use to for strafing movement.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_strafe_axis),
+
+    //!
+    // If non-zero, movement on the joystick axis used for strafing
+    // is inverted.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_strafe_invert),
+
+    //!
+    // The physical joystick button that corresponds to joystick
+    // virtual button #0.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_physical_button0),
+
+    //!
+    // The physical joystick button that corresponds to joystick
+    // virtual button #1.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_physical_button1),
+
+    //!
+    // The physical joystick button that corresponds to joystick
+    // virtual button #2.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_physical_button2),
+
+    //!
+    // The physical joystick button that corresponds to joystick
+    // virtual button #3.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_physical_button3),
+
+    //!
+    // The physical joystick button that corresponds to joystick
+    // virtual button #4.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_physical_button4),
+
+    //!
+    // The physical joystick button that corresponds to joystick
+    // virtual button #5.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_physical_button5),
+
+    //!
+    // The physical joystick button that corresponds to joystick
+    // virtual button #6.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_physical_button6),
+
+    //!
+    // The physical joystick button that corresponds to joystick
+    // virtual button #7.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_physical_button7),
+
+    //!
+    // The physical joystick button that corresponds to joystick
+    // virtual button #8.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_physical_button8),
+
+    //!
+    // The physical joystick button that corresponds to joystick
+    // virtual button #9.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_physical_button9),
+
+    //!
+    // Joystick virtual button to make the player strafe left.
+    //
+
+    CONFIG_VARIABLE_INT(joyb_strafeleft),
+
+    //!
+    // Joystick virtual button to make the player strafe right.
+    //
+
+    CONFIG_VARIABLE_INT(joyb_straferight),
+
+    //!
+    // Joystick virtual button to activate the menu.
+    //
+
+    CONFIG_VARIABLE_INT(joyb_menu_activate),
+
+    //!
+    // Joystick virtual button that cycles to the previous weapon.
+    //
+
+    CONFIG_VARIABLE_INT(joyb_prevweapon),
+
+    //!
+    // Joystick virtual button that cycles to the next weapon.
+    //
+
+    CONFIG_VARIABLE_INT(joyb_nextweapon),
+
+    //!
+    // Mouse button to strafe left.
+    //
+
+    CONFIG_VARIABLE_INT(mouseb_strafeleft),
+
+    //!
+    // Mouse button to strafe right.
+    //
+
+    CONFIG_VARIABLE_INT(mouseb_straferight),
+
+    //!
+    // Mouse button to "use" an object, eg. a door or switch.
+    //
+
+    CONFIG_VARIABLE_INT(mouseb_use),
+
+    //!
+    // Mouse button to move backwards.
+    //
+
+    CONFIG_VARIABLE_INT(mouseb_backward),
+
+    //!
+    // Mouse button to cycle to the previous weapon.
+    //
+
+    CONFIG_VARIABLE_INT(mouseb_prevweapon),
+
+    //!
+    // Mouse button to cycle to the next weapon.
+    //
+
+    CONFIG_VARIABLE_INT(mouseb_nextweapon),
+
+    //!
+    // If non-zero, double-clicking a mouse button acts like pressing
+    // the "use" key to use an object in-game, eg. a door or switch.
+    //
+
+    CONFIG_VARIABLE_INT(dclick_use),
+
+#ifdef FEATURE_SOUND
+
+    //!
+    // Controls whether libsamplerate support is used for performing
+    // sample rate conversions of sound effects.  Support for this
+    // must be compiled into the program.
+    //
+    // If zero, libsamplerate support is disabled.  If non-zero,
+    // libsamplerate is enabled. Increasing values roughly correspond
+    // to higher quality conversion; the higher the quality, the
+    // slower the conversion process.  Linear conversion = 1;
+    // Zero order hold = 2; Fast Sinc filter = 3; Medium quality
+    // Sinc filter = 4; High quality Sinc filter = 5.
+    //
+
+    CONFIG_VARIABLE_INT(use_libsamplerate),
+
+    //!
+    // Scaling factor used by libsamplerate. This is used when converting
+    // sounds internally back into integer form; normally it should not
+    // be necessary to change it from the default value. The only time
+    // it might be needed is if a PWAD file is loaded that contains very
+    // loud sounds, in which case the conversion may cause sound clipping
+    // and the scale factor should be reduced. The lower the value, the
+    // quieter the sound effects become, so it should be set as high as is
+    // possible without clipping occurring.
+
+    CONFIG_VARIABLE_FLOAT(libsamplerate_scale),
+
+    //!
+    // Full path to a Timidity configuration file to use for MIDI
+    // playback. The file will be evaluated from the directory where
+    // it is evaluated, so there is no need to add "dir" commands
+    // into it.
+    //
+
+    CONFIG_VARIABLE_STRING(timidity_cfg_path),
+
+    //!
+    // Path to GUS patch files to use when operating in GUS emulation
+    // mode.
+    //
+
+    CONFIG_VARIABLE_STRING(gus_patch_path),
+
+    //!
+    // Number of kilobytes of RAM to use in GUS emulation mode. Valid
+    // values are 256, 512, 768 or 1024.
+    //
+
+    CONFIG_VARIABLE_INT(gus_ram_kb),
+
+#endif
+
+    //!
+    // Key to pause or unpause the game.
+    //
+
+    CONFIG_VARIABLE_KEY(key_pause),
+
+    //!
+    // Key that activates the menu when pressed.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_activate),
+
+    //!
+    // Key that moves the cursor up on the menu.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_up),
+
+    //!
+    // Key that moves the cursor down on the menu.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_down),
+
+    //!
+    // Key that moves the currently selected slider on the menu left.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_left),
+
+    //!
+    // Key that moves the currently selected slider on the menu right.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_right),
+
+    //!
+    // Key to go back to the previous menu.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_back),
+
+    //!
+    // Key to activate the currently selected menu item.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_forward),
+
+    //!
+    // Key to answer 'yes' to a question in the menu.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_confirm),
+
+    //!
+    // Key to answer 'no' to a question in the menu.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_abort),
+
+    //!
+    // Keyboard shortcut to bring up the help screen.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_help),
+
+    //!
+    // Keyboard shortcut to bring up the save game menu.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_save),
+
+    //!
+    // Keyboard shortcut to bring up the load game menu.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_load),
+
+    //!
+    // Keyboard shortcut to bring up the sound volume menu.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_volume),
+
+    //!
+    // Keyboard shortcut to toggle the detail level.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_detail),
+
+    //!
+    // Keyboard shortcut to quicksave the current game.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_qsave),
+
+    //!
+    // Keyboard shortcut to end the game.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_endgame),
+
+    //!
+    // Keyboard shortcut to toggle heads-up messages.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_messages),
+
+    //!
+    // Keyboard shortcut to load the last quicksave.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_qload),
+
+    //!
+    // Keyboard shortcut to quit the game.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_quit),
+
+    //!
+    // Keyboard shortcut to toggle the gamma correction level.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_gamma),
+
+    //!
+    // Keyboard shortcut to switch view in multiplayer.
+    //
+
+    CONFIG_VARIABLE_KEY(key_spy),
+
+    //!
+    // Keyboard shortcut to increase the screen size.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_incscreen),
+
+    //!
+    // Keyboard shortcut to decrease the screen size.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_decscreen),
+
+    //!
+    // Keyboard shortcut to save a screenshot.
+    //
+
+    CONFIG_VARIABLE_KEY(key_menu_screenshot),
+
+    //!
+    // Key to toggle the map view.
+    //
+
+    CONFIG_VARIABLE_KEY(key_map_toggle),
+
+    //!
+    // Key to pan north when in the map view.
+    //
+
+    CONFIG_VARIABLE_KEY(key_map_north),
+
+    //!
+    // Key to pan south when in the map view.
+    //
+
+    CONFIG_VARIABLE_KEY(key_map_south),
+
+    //!
+    // Key to pan east when in the map view.
+    //
+
+    CONFIG_VARIABLE_KEY(key_map_east),
+
+    //!
+    // Key to pan west when in the map view.
+    //
+
+    CONFIG_VARIABLE_KEY(key_map_west),
+
+    //!
+    // Key to zoom in when in the map view.
+    //
+
+    CONFIG_VARIABLE_KEY(key_map_zoomin),
+
+    //!
+    // Key to zoom out when in the map view.
+    //
+
+    CONFIG_VARIABLE_KEY(key_map_zoomout),
+
+    //!
+    // Key to zoom out the maximum amount when in the map view.
+    //
+
+    CONFIG_VARIABLE_KEY(key_map_maxzoom),
+
+    //!
+    // Key to toggle follow mode when in the map view.
+    //
+
+    CONFIG_VARIABLE_KEY(key_map_follow),
+
+    //!
+    // Key to toggle the grid display when in the map view.
+    //
+
+    CONFIG_VARIABLE_KEY(key_map_grid),
+
+    //!
+    // Key to set a mark when in the map view.
+    //
+
+    CONFIG_VARIABLE_KEY(key_map_mark),
+
+    //!
+    // Key to clear all marks when in the map view.
+    //
+
+    CONFIG_VARIABLE_KEY(key_map_clearmark),
+
+    //!
+    // Key to select weapon 1.
+    //
+
+    CONFIG_VARIABLE_KEY(key_weapon1),
+
+    //!
+    // Key to select weapon 2.
+    //
+
+    CONFIG_VARIABLE_KEY(key_weapon2),
+
+    //!
+    // Key to select weapon 3.
+    //
+
+    CONFIG_VARIABLE_KEY(key_weapon3),
+
+    //!
+    // Key to select weapon 4.
+    //
+
+    CONFIG_VARIABLE_KEY(key_weapon4),
+
+    //!
+    // Key to select weapon 5.
+    //
+
+    CONFIG_VARIABLE_KEY(key_weapon5),
+
+    //!
+    // Key to select weapon 6.
+    //
+
+    CONFIG_VARIABLE_KEY(key_weapon6),
+
+    //!
+    // Key to select weapon 7.
+    //
+
+    CONFIG_VARIABLE_KEY(key_weapon7),
+
+    //!
+    // Key to select weapon 8.
+    //
+
+    CONFIG_VARIABLE_KEY(key_weapon8),
+
+    //!
+    // Key to cycle to the previous weapon.
+    //
+
+    CONFIG_VARIABLE_KEY(key_prevweapon),
+
+    //!
+    // Key to cycle to the next weapon.
+    //
+
+    CONFIG_VARIABLE_KEY(key_nextweapon),
+
+    //!
+    // @game hexen
+    //
+    // Key to use one of each artifact.
+    //
+
+    CONFIG_VARIABLE_KEY(key_arti_all),
+
+    //!
+    // @game hexen
+    //
+    // Key to use "quartz flask" artifact.
+    //
+
+    CONFIG_VARIABLE_KEY(key_arti_health),
+
+    //!
+    // @game hexen
+    //
+    // Key to use "flechette" artifact.
+    //
+
+    CONFIG_VARIABLE_KEY(key_arti_poisonbag),
+
+    //!
+    // @game hexen
+    //
+    // Key to use "disc of repulsion" artifact.
+    //
+
+    CONFIG_VARIABLE_KEY(key_arti_blastradius),
+
+    //!
+    // @game hexen
+    //
+    // Key to use "chaos device" artifact.
+    //
+
+    CONFIG_VARIABLE_KEY(key_arti_teleport),
+
+    //!
+    // @game hexen
+    //
+    // Key to use "banishment device" artifact.
+    //
+
+    CONFIG_VARIABLE_KEY(key_arti_teleportother),
+
+    //!
+    // @game hexen
+    //
+    // Key to use "porkalator" artifact.
+    //
+
+    CONFIG_VARIABLE_KEY(key_arti_egg),
+
+    //!
+    // @game hexen
+    //
+    // Key to use "icon of the defender" artifact.
+    //
+
+    CONFIG_VARIABLE_KEY(key_arti_invulnerability),
+
+    //!
+    // Key to re-display last message.
+    //
+
+    CONFIG_VARIABLE_KEY(key_message_refresh),
+
+    //!
+    // Key to quit the game when recording a demo.
+    //
+
+    CONFIG_VARIABLE_KEY(key_demo_quit),
+
+    //!
+    // Key to send a message during multiplayer games.
+    //
+
+    CONFIG_VARIABLE_KEY(key_multi_msg),
+
+    //!
+    // Key to send a message to player 1 during multiplayer games.
+    //
+
+    CONFIG_VARIABLE_KEY(key_multi_msgplayer1),
+
+    //!
+    // Key to send a message to player 2 during multiplayer games.
+    //
+
+    CONFIG_VARIABLE_KEY(key_multi_msgplayer2),
+
+    //!
+    // Key to send a message to player 3 during multiplayer games.
+    //
+
+    CONFIG_VARIABLE_KEY(key_multi_msgplayer3),
+
+    //!
+    // Key to send a message to player 4 during multiplayer games.
+    //
+
+    CONFIG_VARIABLE_KEY(key_multi_msgplayer4),
+
+    //!
+    // @game hexen strife
+    //
+    // Key to send a message to player 5 during multiplayer games.
+    //
+
+    CONFIG_VARIABLE_KEY(key_multi_msgplayer5),
+
+    //!
+    // @game hexen strife
+    //
+    // Key to send a message to player 6 during multiplayer games.
+    //
+
+    CONFIG_VARIABLE_KEY(key_multi_msgplayer6),
+
+    //!
+    // @game hexen strife
+    //
+    // Key to send a message to player 7 during multiplayer games.
+    //
+
+    CONFIG_VARIABLE_KEY(key_multi_msgplayer7),
+
+    //!
+    // @game hexen strife
+    //
+    // Key to send a message to player 8 during multiplayer games.
+    //
+
+    CONFIG_VARIABLE_KEY(key_multi_msgplayer8),
+};
+
+static default_collection_t extra_defaults =
+{
+    extra_defaults_list,
+    arrlen(extra_defaults_list),
+    NULL,
+};
+
+// Search a collection for a variable
+
+static default_t *SearchCollection(default_collection_t *collection, char *name)
+{
+    int i;
+
+    for (i=0; i<collection->numdefaults; ++i) 
+    {
+        if (!strcmp(name, collection->defaults[i].name))
+        {
+            return &collection->defaults[i];
+        }
+    }
+
+    return NULL;
+}
+
+// Mapping from DOS keyboard scan code to internal key code (as defined
+// in doomkey.h). I think I (fraggle) reused this from somewhere else
+// but I can't find where. Anyway, notes:
+//  * KEY_PAUSE is wrong - it's in the KEY_NUMLOCK spot. This shouldn't
+//    matter in terms of Vanilla compatibility because neither of
+//    those were valid for key bindings.
+//  * There is no proper scan code for PrintScreen (on DOS machines it
+//    sends an interrupt). So I added a fake scan code of 126 for it.
+//    The presence of this is important so we can bind PrintScreen as
+//    a screenshot key.
+static const int scantokey[128] =
+{
+    0  ,    27,     '1',    '2',    '3',    '4',    '5',    '6',
+    '7',    '8',    '9',    '0',    '-',    '=',    KEY_BACKSPACE, 9,
+    'q',    'w',    'e',    'r',    't',    'y',    'u',    'i',
+    'o',    'p',    '[',    ']',    13,                KEY_RCTRL, 'a',    's',
+    'd',    'f',    'g',    'h',    'j',    'k',    'l',    ';',
+    '\'',   '`',    KEY_RSHIFT,'\\',   'z',    'x',    'c',    'v',
+    'b',    'n',    'm',    ',',    '.',    '/',    KEY_RSHIFT,KEYP_MULTIPLY,
+    KEY_RALT,  ' ',  KEY_CAPSLOCK,KEY_F1,  KEY_F2,   KEY_F3,   KEY_F4,   KEY_F5,
+    KEY_F6,   KEY_F7,   KEY_F8,   KEY_F9,   KEY_F10,  /*KEY_NUMLOCK?*/KEY_PAUSE,KEY_SCRLCK,KEY_HOME,
+    KEY_UPARROW,KEY_PGUP,KEY_MINUS,KEY_LEFTARROW,KEYP_5,KEY_RIGHTARROW,KEYP_PLUS,KEY_END,
+    KEY_DOWNARROW,KEY_PGDN,KEY_INS,KEY_DEL,0,   0,      0,      KEY_F11,
+    KEY_F12,  0,      0,      0,      0,      0,      0,      0,
+    0,      0,      0,      0,      0,      0,      0,      0,
+    0,      0,      0,      0,      0,      0,      0,      0,
+    0,      0,      0,      0,      0,      0,      0,      0,
+    0,      0,      0,      0,      0,      0,      KEY_PRTSCR, 0
+};
+
+
+static void SaveDefaultCollection(default_collection_t *collection)
+{
+#if ORIGCODE
+    default_t *defaults;
+    int i, v;
+    FILE *f;
+       
+    f = fopen (collection->filename, "w");
+    if (!f)
+       return; // can't write the file, but don't complain
+
+    defaults = collection->defaults;
+               
+    for (i=0 ; i<collection->numdefaults ; i++)
+    {
+        int chars_written;
+
+        // Ignore unbound variables
+
+        if (!defaults[i].bound)
+        {
+            continue;
+        }
+
+        // Print the name and line up all values at 30 characters
+
+        chars_written = fprintf(f, "%s ", defaults[i].name);
+
+        for (; chars_written < 30; ++chars_written)
+            fprintf(f, " ");
+
+        // Print the value
+
+        switch (defaults[i].type) 
+        {
+            case DEFAULT_KEY:
+
+                // use the untranslated version if we can, to reduce
+                // the possibility of screwing up the user's config
+                // file
+                
+                v = * (int *) defaults[i].location;
+
+                if (v == KEY_RSHIFT)
+                {
+                    // Special case: for shift, force scan code for
+                    // right shift, as this is what Vanilla uses.
+                    // This overrides the change check below, to fix
+                    // configuration files made by old versions that
+                    // mistakenly used the scan code for left shift.
+
+                    v = 54;
+                }
+                else if (defaults[i].untranslated
+                      && v == defaults[i].original_translated)
+                {
+                    // Has not been changed since the last time we
+                    // read the config file.
+
+                    v = defaults[i].untranslated;
+                }
+                else
+                {
+                    // search for a reverse mapping back to a scancode
+                    // in the scantokey table
+
+                    int s;
+
+                    for (s=0; s<128; ++s)
+                    {
+                        if (scantokey[s] == v)
+                        {
+                            v = s;
+                            break;
+                        }
+                    }
+                }
+
+               fprintf(f, "%i", v);
+                break;
+
+            case DEFAULT_INT:
+               fprintf(f, "%i", * (int *) defaults[i].location);
+                break;
+
+            case DEFAULT_INT_HEX:
+               fprintf(f, "0x%x", * (int *) defaults[i].location);
+                break;
+
+            case DEFAULT_FLOAT:
+                fprintf(f, "%f", * (float *) defaults[i].location);
+                break;
+
+            case DEFAULT_STRING:
+               fprintf(f,"\"%s\"", * (char **) (defaults[i].location));
+                break;
+        }
+
+        fprintf(f, "\n");
+    }
+
+    fclose (f);
+#endif
+}
+
+// Parses integer values in the configuration file
+
+static int ParseIntParameter(char *strparm)
+{
+    int parm;
+
+    if (strparm[0] == '0' && strparm[1] == 'x')
+        sscanf(strparm+2, "%x", &parm);
+    else
+        sscanf(strparm, "%i", &parm);
+
+    return parm;
+}
+
+static void SetVariable(default_t *def, char *value)
+{
+    int intparm;
+
+    // parameter found
+
+    switch (def->type)
+    {
+        case DEFAULT_STRING:
+            * (char **) def->location = strdup(value);
+            break;
+
+        case DEFAULT_INT:
+        case DEFAULT_INT_HEX:
+            * (int *) def->location = ParseIntParameter(value);
+            break;
+
+        case DEFAULT_KEY:
+
+            // translate scancodes read from config
+            // file (save the old value in untranslated)
+
+            intparm = ParseIntParameter(value);
+            def->untranslated = intparm;
+            if (intparm >= 0 && intparm < 128)
+            {
+                intparm = scantokey[intparm];
+            }
+            else
+            {
+                intparm = 0;
+            }
+
+            def->original_translated = intparm;
+            * (int *) def->location = intparm;
+            break;
+
+        case DEFAULT_FLOAT:
+            * (float *) def->location = (float) atof(value);
+            break;
+    }
+}
+
+static void LoadDefaultCollection(default_collection_t *collection)
+{
+#if ORIGCODE
+    FILE *f;
+    default_t *def;
+    char defname[80];
+    char strparm[100];
+
+    // read the file in, overriding any set defaults
+    f = fopen(collection->filename, "r");
+
+    if (f == NULL)
+    {
+        // File not opened, but don't complain. 
+        // It's probably just the first time they ran the game.
+
+        return;
+    }
+
+    while (!feof(f))
+    {
+        if (fscanf(f, "%79s %99[^\n]\n", defname, strparm) != 2)
+        {
+            // This line doesn't match
+
+            continue;
+        }
+
+        // Find the setting in the list
+
+        def = SearchCollection(collection, defname);
+
+        if (def == NULL || !def->bound)
+        {
+            // Unknown variable?  Unbound variables are also treated
+            // as unknown.
+
+            continue;
+        }
+
+        // Strip off trailing non-printable characters (\r characters
+        // from DOS text files)
+
+        while (strlen(strparm) > 0 && !isprint(strparm[strlen(strparm)-1]))
+        {
+            strparm[strlen(strparm)-1] = '\0';
+        }
+
+        // Surrounded by quotes? If so, remove them.
+        if (strlen(strparm) >= 2
+         && strparm[0] == '"' && strparm[strlen(strparm) - 1] == '"')
+        {
+            strparm[strlen(strparm) - 1] = '\0';
+            memmove(strparm, strparm + 1, sizeof(strparm) - 1);
+        }
+
+        SetVariable(def, strparm);
+    }
+
+    fclose (f);
+#endif
+}
+
+// Set the default filenames to use for configuration files.
+
+void M_SetConfigFilenames(char *main_config, char *extra_config)
+{
+    default_main_config = main_config;
+    default_extra_config = extra_config;
+}
+
+//
+// M_SaveDefaults
+//
+
+void M_SaveDefaults (void)
+{
+    SaveDefaultCollection(&doom_defaults);
+    SaveDefaultCollection(&extra_defaults);
+}
+
+//
+// Save defaults to alternate filenames
+//
+
+void M_SaveDefaultsAlternate(char *main, char *extra)
+{
+    char *orig_main;
+    char *orig_extra;
+
+    // Temporarily change the filenames
+
+    orig_main = doom_defaults.filename;
+    orig_extra = extra_defaults.filename;
+
+    doom_defaults.filename = main;
+    extra_defaults.filename = extra;
+
+    M_SaveDefaults();
+
+    // Restore normal filenames
+
+    doom_defaults.filename = orig_main;
+    extra_defaults.filename = orig_extra;
+}
+
+//
+// M_LoadDefaults
+//
+
+void M_LoadDefaults (void)
+{
+    int i;
+    // check for a custom default file
+
+    //!
+    // @arg <file>
+    // @vanilla
+    //
+    // Load main configuration from the specified file, instead of the
+    // default.
+    //
+
+    i = M_CheckParmWithArgs("-config", 1);
+
+    if (i)
+    {
+       doom_defaults.filename = myargv[i+1];
+       printf ("       default file: %s\n",doom_defaults.filename);
+    }
+    else
+    {
+        doom_defaults.filename
+            = M_StringJoin(configdir, default_main_config, NULL);
+    }
+
+    printf("saving config in %s\n", doom_defaults.filename);
+
+    //!
+    // @arg <file>
+    //
+    // Load additional configuration from the specified file, instead of
+    // the default.
+    //
+
+    i = M_CheckParmWithArgs("-extraconfig", 1);
+
+    if (i)
+    {
+        extra_defaults.filename = myargv[i+1];
+        printf("        extra configuration file: %s\n", 
+               extra_defaults.filename);
+    }
+    else
+    {
+        extra_defaults.filename
+            = M_StringJoin(configdir, default_extra_config, NULL);
+    }
+
+    LoadDefaultCollection(&doom_defaults);
+    LoadDefaultCollection(&extra_defaults);
+}
+
+// Get a configuration file variable by its name
+
+static default_t *GetDefaultForName(char *name)
+{
+    default_t *result;
+
+    // Try the main list and the extras
+
+    result = SearchCollection(&doom_defaults, name);
+
+    if (result == NULL)
+    {
+        result = SearchCollection(&extra_defaults, name);
+    }
+
+    // Not found? Internal error.
+
+    if (result == NULL)
+    {
+        I_Error("Unknown configuration variable: '%s'", name);
+    }
+
+    return result;
+}
+
+//
+// Bind a variable to a given configuration file variable, by name.
+//
+
+void M_BindVariable(char *name, void *location)
+{
+    default_t *variable;
+
+    variable = GetDefaultForName(name);
+
+    variable->location = location;
+    variable->bound = true;
+}
+
+// Set the value of a particular variable; an API function for other
+// parts of the program to assign values to config variables by name.
+
+boolean M_SetVariable(char *name, char *value)
+{
+    default_t *variable;
+
+    variable = GetDefaultForName(name);
+
+    if (variable == NULL || !variable->bound)
+    {
+        return false;
+    }
+
+    SetVariable(variable, value);
+
+    return true;
+}
+
+// Get the value of a variable.
+
+int M_GetIntVariable(char *name)
+{
+    default_t *variable;
+
+    variable = GetDefaultForName(name);
+
+    if (variable == NULL || !variable->bound
+     || (variable->type != DEFAULT_INT && variable->type != DEFAULT_INT_HEX))
+    {
+        return 0;
+    }
+
+    return *((int *) variable->location);
+}
+
+const char *M_GetStrVariable(char *name)
+{
+    default_t *variable;
+
+    variable = GetDefaultForName(name);
+
+    if (variable == NULL || !variable->bound
+     || variable->type != DEFAULT_STRING)
+    {
+        return NULL;
+    }
+
+    return *((const char **) variable->location);
+}
+
+float M_GetFloatVariable(char *name)
+{
+    default_t *variable;
+
+    variable = GetDefaultForName(name);
+
+    if (variable == NULL || !variable->bound
+     || variable->type != DEFAULT_FLOAT)
+    {
+        return 0;
+    }
+
+    return *((float *) variable->location);
+}
+
+// Get the path to the default configuration dir to use, if NULL
+// is passed to M_SetConfigDir.
+
+static char *GetDefaultConfigDir(void)
+{
+#if !defined(_WIN32) || defined(_WIN32_WCE)
+
+    // Configuration settings are stored in ~/.chocolate-doom/,
+    // except on Windows, where we behave like Vanilla Doom and
+    // save in the current directory.
+
+    char *homedir;
+    char *result;
+
+    // frosted HACK - homedir = getenv("HOME");
+    homedir = "/mnt";
+
+    if (homedir != NULL)
+    {
+        // put all configuration in a config directory off the
+        // homedir
+
+        result = M_StringJoin(homedir, DIR_SEPARATOR_S,
+                              "." PACKAGE_TARNAME, DIR_SEPARATOR_S, NULL);
+
+        return result;
+    }
+    else
+#endif /* #ifndef _WIN32 */
+    {
+        return strdup(FILES_DIR"/");
+    }
+}
+
+// 
+// SetConfigDir:
+//
+// Sets the location of the configuration directory, where configuration
+// files are stored - default.cfg, chocolate-doom.cfg, savegames, etc.
+//
+
+void M_SetConfigDir(char *dir)
+{
+    // Use the directory that was passed, or find the default.
+
+    if (dir != NULL)
+    {
+        configdir = dir;
+    }
+    else
+    {
+        configdir = GetDefaultConfigDir();
+    }
+
+    if (strcmp(configdir, "") != 0)
+    {
+        printf("Using %s for configuration and saves\n", configdir);
+    }
+
+    // Make the directory if it doesn't already exist:
+
+    M_MakeDirectory(configdir);
+}
+
+//
+// Calculate the path to the directory to use to store save games.
+// Creates the directory as necessary.
+//
+
+char *M_GetSaveGameDir(char *iwadname)
+{
+    char *savegamedir;
+#if ORIGCODE
+    char *topdir;
+#endif
+
+    // If not "doing" a configuration directory (Windows), don't "do"
+    // a savegame directory, either.
+
+    if (!strcmp(configdir, ""))
+    {
+       savegamedir = strdup("");
+    }
+    else
+    {
+#if ORIGCODE
+        // ~/.chocolate-doom/savegames
+
+        topdir = M_StringJoin(configdir, "savegame", NULL);
+        M_MakeDirectory(topdir);
+
+        // eg. ~/.chocolate-doom/savegames/doom2.wad/
+
+        savegamedir = M_StringJoin(topdir, DIR_SEPARATOR_S, iwadname,
+                                   DIR_SEPARATOR_S, NULL);
+
+        M_MakeDirectory(savegamedir);
+
+        free(topdir);
+#else
+        savegamedir = M_StringJoin(configdir, "savegame/", NULL);
+
+        M_MakeDirectory(savegamedir);
+
+        printf ("Using %s for savegames\n", savegamedir);
+#endif
+    }
+
+    return savegamedir;
+}
+
diff --git a/frosted-doom/m_config.h b/frosted-doom/m_config.h
new file mode 100644 (file)
index 0000000..a17de2b
--- /dev/null
@@ -0,0 +1,39 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//      Configuration file interface.
+//    
+
+
+#ifndef __M_CONFIG__
+#define __M_CONFIG__
+
+#include "doomtype.h"
+
+void M_LoadDefaults(void);
+void M_SaveDefaults(void);
+void M_SaveDefaultsAlternate(char *main, char *extra);
+void M_SetConfigDir(char *dir);
+void M_BindVariable(char *name, void *variable);
+boolean M_SetVariable(char *name, char *value);
+int M_GetIntVariable(char *name);
+const char *M_GetStrVariable(char *name);
+float M_GetFloatVariable(char *name);
+void M_SetConfigFilenames(char *main_config, char *extra_config);
+char *M_GetSaveGameDir(char *iwadname);
+
+extern char *configdir;
+
+#endif
diff --git a/frosted-doom/m_controls.c b/frosted-doom/m_controls.c
new file mode 100644 (file)
index 0000000..f0ffa01
--- /dev/null
@@ -0,0 +1,398 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// 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.
+//
+
+#include <stdio.h>
+
+#include "doomtype.h"
+#include "doomkeys.h"
+
+#include "m_config.h"
+#include "m_misc.h"
+
+//
+// Keyboard controls
+//
+
+int key_right = KEY_RIGHTARROW;
+int key_left = KEY_LEFTARROW;
+int key_up = KEY_UPARROW;
+int key_down = KEY_DOWNARROW; 
+int key_strafeleft = KEY_STRAFE_L;
+int key_straferight = KEY_STRAFE_R;
+int key_fire = KEY_FIRE;
+int key_use = KEY_USE;
+int key_strafe = KEY_RALT;
+int key_speed = KEY_RSHIFT; 
+
+// 
+// Heretic keyboard controls
+//
+int key_flyup = KEY_PGUP;
+int key_flydown = KEY_INS;
+int key_flycenter = KEY_HOME;
+
+int key_lookup = KEY_PGDN;
+int key_lookdown = KEY_DEL;
+int key_lookcenter = KEY_END;
+
+int key_invleft = '[';
+int key_invright = ']';
+int key_useartifact = KEY_ENTER;
+
+//
+// Hexen key controls
+//
+
+int key_jump = '/';
+
+int key_arti_all             = KEY_BACKSPACE;
+int key_arti_health          = '\\';
+int key_arti_poisonbag       = '0';
+int key_arti_blastradius     = '9';
+int key_arti_teleport        = '8';
+int key_arti_teleportother   = '7';
+int key_arti_egg             = '6';
+int key_arti_invulnerability = '5';
+
+//
+// Strife key controls
+//
+// haleyjd 09/01/10
+//
+
+// Note: Strife also uses key_invleft, key_invright, key_jump, key_lookup, and
+// key_lookdown, but with different default values.
+
+int key_usehealth = 'h';
+int key_invquery  = 'q';
+int key_mission   = 'w';
+int key_invpop    = 'z';
+int key_invkey    = 'k';
+int key_invhome   = KEY_HOME;
+int key_invend    = KEY_END;
+int key_invuse    = KEY_ENTER;
+int key_invdrop   = KEY_BACKSPACE;
+
+
+//
+// Mouse controls
+//
+
+int mousebfire = 0;
+int mousebstrafe = 1;
+int mousebforward = 2;
+
+int mousebjump = -1;
+
+int mousebstrafeleft = -1;
+int mousebstraferight = -1;
+int mousebbackward = -1;
+int mousebuse = -1;
+
+int mousebprevweapon = -1;
+int mousebnextweapon = -1;
+
+
+int key_message_refresh = KEY_ENTER;
+int key_pause = KEY_PAUSE;
+int key_demo_quit = 'q';
+int key_spy = KEY_F12;
+
+// Multiplayer chat keys:
+
+int key_multi_msg = 't';
+int key_multi_msgplayer[8];
+
+// Weapon selection keys:
+
+int key_weapon1 = '1';
+int key_weapon2 = '2';
+int key_weapon3 = '3';
+int key_weapon4 = '4';
+int key_weapon5 = '5';
+int key_weapon6 = '6';
+int key_weapon7 = '7';
+int key_weapon8 = '8';
+int key_prevweapon = 0;
+int key_nextweapon = 0;
+
+// Map control keys:
+
+int key_map_north     = KEY_UPARROW;
+int key_map_south     = KEY_DOWNARROW;
+int key_map_east      = KEY_RIGHTARROW;
+int key_map_west      = KEY_LEFTARROW;
+int key_map_zoomin    = '=';
+int key_map_zoomout   = '-';
+int key_map_toggle    = KEY_TAB;
+int key_map_maxzoom   = '0';
+int key_map_follow    = 'f';
+int key_map_grid      = 'g';
+int key_map_mark      = 'm';
+int key_map_clearmark = 'c';
+
+// menu keys:
+
+int key_menu_activate  = KEY_ESCAPE;
+int key_menu_up        = KEY_UPARROW;
+int key_menu_down      = KEY_DOWNARROW;
+int key_menu_left      = KEY_LEFTARROW;
+int key_menu_right     = KEY_RIGHTARROW;
+int key_menu_back      = KEY_BACKSPACE;
+int key_menu_forward   = KEY_ENTER;
+int key_menu_confirm   = 'y';
+int key_menu_abort     = 'n';
+
+int key_menu_help      = KEY_F1;
+int key_menu_save      = KEY_F2;
+int key_menu_load      = KEY_F3;
+int key_menu_volume    = KEY_F4;
+int key_menu_detail    = KEY_F5;
+int key_menu_qsave     = KEY_F6;
+int key_menu_endgame   = KEY_F7;
+int key_menu_messages  = KEY_F8;
+int key_menu_qload     = KEY_F9;
+int key_menu_quit      = KEY_F10;
+int key_menu_gamma     = KEY_F11;
+
+int key_menu_incscreen = KEY_EQUALS;
+int key_menu_decscreen = KEY_MINUS;
+int key_menu_screenshot = 0;
+
+//
+// Joystick controls
+//
+
+int joybfire = 0;
+int joybstrafe = 1;
+int joybuse = 3;
+int joybspeed = 2;
+
+int joybstrafeleft = -1;
+int joybstraferight = -1;
+
+int joybjump = -1;
+
+int joybprevweapon = -1;
+int joybnextweapon = -1;
+
+int joybmenu = -1;
+
+// Control whether if a mouse button is double clicked, it acts like 
+// "use" has been pressed
+
+int dclick_use = 1;
+// 
+// Bind all of the common controls used by Doom and all other games.
+//
+
+void M_BindBaseControls(void)
+{
+    M_BindVariable("key_right",          &key_right);
+    M_BindVariable("key_left",           &key_left);
+    M_BindVariable("key_up",             &key_up);
+    M_BindVariable("key_down",           &key_down);
+    M_BindVariable("key_strafeleft",     &key_strafeleft);
+    M_BindVariable("key_straferight",    &key_straferight);
+    M_BindVariable("key_fire",           &key_fire);
+    M_BindVariable("key_use",            &key_use);
+    M_BindVariable("key_strafe",         &key_strafe);
+    M_BindVariable("key_speed",          &key_speed);
+
+    M_BindVariable("mouseb_fire",        &mousebfire);
+    M_BindVariable("mouseb_strafe",      &mousebstrafe);
+    M_BindVariable("mouseb_forward",     &mousebforward);
+
+    M_BindVariable("joyb_fire",          &joybfire);
+    M_BindVariable("joyb_strafe",        &joybstrafe);
+    M_BindVariable("joyb_use",           &joybuse);
+    M_BindVariable("joyb_speed",         &joybspeed);
+
+    M_BindVariable("joyb_menu_activate", &joybmenu);
+
+    // Extra controls that are not in the Vanilla versions:
+
+    M_BindVariable("joyb_strafeleft",    &joybstrafeleft);
+    M_BindVariable("joyb_straferight",   &joybstraferight);
+    M_BindVariable("mouseb_strafeleft",  &mousebstrafeleft);
+    M_BindVariable("mouseb_straferight", &mousebstraferight);
+    M_BindVariable("mouseb_use",         &mousebuse);
+    M_BindVariable("mouseb_backward",    &mousebbackward);
+    M_BindVariable("dclick_use",         &dclick_use);
+    M_BindVariable("key_pause",          &key_pause);
+    M_BindVariable("key_message_refresh", &key_message_refresh);
+}
+
+void M_BindHereticControls(void)
+{
+    M_BindVariable("key_flyup",          &key_flyup);
+    M_BindVariable("key_flydown",        &key_flydown);
+    M_BindVariable("key_flycenter",      &key_flycenter);
+
+    M_BindVariable("key_lookup",         &key_lookup);
+    M_BindVariable("key_lookdown",       &key_lookdown);
+    M_BindVariable("key_lookcenter",     &key_lookcenter);
+
+    M_BindVariable("key_invleft",        &key_invleft);
+    M_BindVariable("key_invright",       &key_invright);
+    M_BindVariable("key_useartifact",    &key_useartifact);
+}
+
+void M_BindHexenControls(void)
+{
+    M_BindVariable("key_jump",           &key_jump);
+    M_BindVariable("mouseb_jump",        &mousebjump);
+    M_BindVariable("joyb_jump",          &joybjump);
+
+    M_BindVariable("key_arti_all",             &key_arti_all);
+    M_BindVariable("key_arti_health",          &key_arti_health);
+    M_BindVariable("key_arti_poisonbag",       &key_arti_poisonbag);
+    M_BindVariable("key_arti_blastradius",     &key_arti_blastradius);
+    M_BindVariable("key_arti_teleport",        &key_arti_teleport);
+    M_BindVariable("key_arti_teleportother",   &key_arti_teleportother);
+    M_BindVariable("key_arti_egg",             &key_arti_egg);
+    M_BindVariable("key_arti_invulnerability", &key_arti_invulnerability);
+}
+
+void M_BindStrifeControls(void)
+{
+    // These are shared with all games, but have different defaults:
+    key_message_refresh = '/';
+
+    // These keys are shared with Heretic/Hexen but have different defaults:
+    key_jump     = 'a';
+    key_lookup   = KEY_PGUP;
+    key_lookdown = KEY_PGDN;
+    key_invleft  = KEY_INS;
+    key_invright = KEY_DEL;
+
+    M_BindVariable("key_jump",           &key_jump);
+    M_BindVariable("key_lookUp",         &key_lookup);
+    M_BindVariable("key_lookDown",       &key_lookdown);
+    M_BindVariable("key_invLeft",        &key_invleft);
+    M_BindVariable("key_invRight",       &key_invright);
+
+    // Custom Strife-only Keys:
+    M_BindVariable("key_useHealth",      &key_usehealth);
+    M_BindVariable("key_invquery",       &key_invquery);
+    M_BindVariable("key_mission",        &key_mission);
+    M_BindVariable("key_invPop",         &key_invpop);
+    M_BindVariable("key_invKey",         &key_invkey);
+    M_BindVariable("key_invHome",        &key_invhome);
+    M_BindVariable("key_invEnd",         &key_invend);
+    M_BindVariable("key_invUse",         &key_invuse);
+    M_BindVariable("key_invDrop",        &key_invdrop);
+
+    // Strife also supports jump on mouse and joystick, and in the exact same
+    // manner as Hexen!
+    M_BindVariable("mouseb_jump",        &mousebjump);
+    M_BindVariable("joyb_jump",          &joybjump);
+}
+
+void M_BindWeaponControls(void)
+{
+    M_BindVariable("key_weapon1",        &key_weapon1);
+    M_BindVariable("key_weapon2",        &key_weapon2);
+    M_BindVariable("key_weapon3",        &key_weapon3);
+    M_BindVariable("key_weapon4",        &key_weapon4);
+    M_BindVariable("key_weapon5",        &key_weapon5);
+    M_BindVariable("key_weapon6",        &key_weapon6);
+    M_BindVariable("key_weapon7",        &key_weapon7);
+    M_BindVariable("key_weapon8",        &key_weapon8);
+
+    M_BindVariable("key_prevweapon",     &key_prevweapon);
+    M_BindVariable("key_nextweapon",     &key_nextweapon);
+
+    M_BindVariable("joyb_prevweapon",    &joybprevweapon);
+    M_BindVariable("joyb_nextweapon",    &joybnextweapon);
+
+    M_BindVariable("mouseb_prevweapon",  &mousebprevweapon);
+    M_BindVariable("mouseb_nextweapon",  &mousebnextweapon);
+}
+
+void M_BindMapControls(void)
+{
+    M_BindVariable("key_map_north",      &key_map_north);
+    M_BindVariable("key_map_south",      &key_map_south);
+    M_BindVariable("key_map_east",       &key_map_east);
+    M_BindVariable("key_map_west",       &key_map_west);
+    M_BindVariable("key_map_zoomin",     &key_map_zoomin);
+    M_BindVariable("key_map_zoomout",    &key_map_zoomout);
+    M_BindVariable("key_map_toggle",     &key_map_toggle);
+    M_BindVariable("key_map_maxzoom",    &key_map_maxzoom);
+    M_BindVariable("key_map_follow",     &key_map_follow);
+    M_BindVariable("key_map_grid",       &key_map_grid);
+    M_BindVariable("key_map_mark",       &key_map_mark);
+    M_BindVariable("key_map_clearmark",  &key_map_clearmark);
+}
+
+void M_BindMenuControls(void)
+{
+    M_BindVariable("key_menu_activate",  &key_menu_activate);
+    M_BindVariable("key_menu_up",        &key_menu_up);
+    M_BindVariable("key_menu_down",      &key_menu_down);
+    M_BindVariable("key_menu_left",      &key_menu_left);
+    M_BindVariable("key_menu_right",     &key_menu_right);
+    M_BindVariable("key_menu_back",      &key_menu_back);
+    M_BindVariable("key_menu_forward",   &key_menu_forward);
+    M_BindVariable("key_menu_confirm",   &key_menu_confirm);
+    M_BindVariable("key_menu_abort",     &key_menu_abort);
+
+    M_BindVariable("key_menu_help",      &key_menu_help);
+    M_BindVariable("key_menu_save",      &key_menu_save);
+    M_BindVariable("key_menu_load",      &key_menu_load);
+    M_BindVariable("key_menu_volume",    &key_menu_volume);
+    M_BindVariable("key_menu_detail",    &key_menu_detail);
+    M_BindVariable("key_menu_qsave",     &key_menu_qsave);
+    M_BindVariable("key_menu_endgame",   &key_menu_endgame);
+    M_BindVariable("key_menu_messages",  &key_menu_messages);
+    M_BindVariable("key_menu_qload",     &key_menu_qload);
+    M_BindVariable("key_menu_quit",      &key_menu_quit);
+    M_BindVariable("key_menu_gamma",     &key_menu_gamma);
+
+    M_BindVariable("key_menu_incscreen", &key_menu_incscreen);
+    M_BindVariable("key_menu_decscreen", &key_menu_decscreen);
+    M_BindVariable("key_menu_screenshot",&key_menu_screenshot);
+    M_BindVariable("key_demo_quit",      &key_demo_quit);
+    M_BindVariable("key_spy",            &key_spy);
+}
+
+void M_BindChatControls(unsigned int num_players)
+{
+    char name[32];  // haleyjd: 20 not large enough - Thank you, come again!
+    unsigned int i; // haleyjd: signedness conflict
+
+    M_BindVariable("key_multi_msg",     &key_multi_msg);
+
+    for (i=0; i<num_players; ++i)
+    {
+        M_snprintf(name, sizeof(name), "key_multi_msgplayer%i", i + 1);
+        M_BindVariable(name, &key_multi_msgplayer[i]);
+    }
+}
+
+//
+// Apply custom patches to the default values depending on the
+// platform we are running on.
+//
+
+void M_ApplyPlatformDefaults(void)
+{
+    // no-op. Add your platform-specific patches here.
+}
+
diff --git a/frosted-doom/m_controls.h b/frosted-doom/m_controls.h
new file mode 100644 (file)
index 0000000..aa07a7e
--- /dev/null
@@ -0,0 +1,168 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// 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 __M_CONTROLS_H__
+#define __M_CONTROLS_H__
+extern int key_right;
+extern int key_left;
+
+extern int key_up;
+extern int key_down;
+extern int key_strafeleft;
+extern int key_straferight;
+extern int key_fire;
+extern int key_use;
+extern int key_strafe;
+extern int key_speed;
+
+extern int key_jump;
+extern int key_flyup;
+extern int key_flydown;
+extern int key_flycenter;
+extern int key_lookup;
+extern int key_lookdown;
+extern int key_lookcenter;
+extern int key_invleft;
+extern int key_invright;
+extern int key_useartifact;
+
+// villsa [STRIFE] strife keys
+extern int key_usehealth;
+extern int key_invquery;
+extern int key_mission;
+extern int key_invpop;
+extern int key_invkey;
+extern int key_invhome;
+extern int key_invend;
+extern int key_invuse;
+extern int key_invdrop;
+
+extern int key_message_refresh;
+extern int key_pause;
+
+extern int key_multi_msg;
+extern int key_multi_msgplayer[8];
+
+extern int key_weapon1;
+extern int key_weapon2;
+extern int key_weapon3;
+extern int key_weapon4;
+extern int key_weapon5;
+extern int key_weapon6;
+extern int key_weapon7;
+extern int key_weapon8;
+
+extern int key_arti_all;
+extern int key_arti_health;
+extern int key_arti_poisonbag;
+extern int key_arti_blastradius;
+extern int key_arti_teleport;
+extern int key_arti_teleportother;
+extern int key_arti_egg;
+extern int key_arti_invulnerability;
+
+extern int key_demo_quit;
+extern int key_spy;
+extern int key_prevweapon;
+extern int key_nextweapon;
+
+extern int key_map_north;
+extern int key_map_south;
+extern int key_map_east;
+extern int key_map_west;
+extern int key_map_zoomin;
+extern int key_map_zoomout;
+extern int key_map_toggle;
+extern int key_map_maxzoom;
+extern int key_map_follow;
+extern int key_map_grid;
+extern int key_map_mark;
+extern int key_map_clearmark;
+
+// menu keys:
+
+extern int key_menu_activate;
+extern int key_menu_up;
+extern int key_menu_down;
+extern int key_menu_left;
+extern int key_menu_right;
+extern int key_menu_back;
+extern int key_menu_forward;
+extern int key_menu_confirm;
+extern int key_menu_abort;
+
+extern int key_menu_help;
+extern int key_menu_save;
+extern int key_menu_load;
+extern int key_menu_volume;
+extern int key_menu_detail;
+extern int key_menu_qsave;
+extern int key_menu_endgame;
+extern int key_menu_messages;
+extern int key_menu_qload;
+extern int key_menu_quit;
+extern int key_menu_gamma;
+
+extern int key_menu_incscreen;
+extern int key_menu_decscreen;
+extern int key_menu_screenshot;
+
+extern int mousebfire;
+extern int mousebstrafe;
+extern int mousebforward;
+
+extern int mousebjump;
+
+extern int mousebstrafeleft;
+extern int mousebstraferight;
+extern int mousebbackward;
+extern int mousebuse;
+
+extern int mousebprevweapon;
+extern int mousebnextweapon;
+
+extern int joybfire;
+extern int joybstrafe;
+extern int joybuse;
+extern int joybspeed;
+
+extern int joybjump;
+
+extern int joybstrafeleft;
+extern int joybstraferight;
+
+extern int joybprevweapon;
+extern int joybnextweapon;
+
+extern int joybmenu;
+
+extern int dclick_use;
+
+void M_BindBaseControls(void);
+void M_BindHereticControls(void);
+void M_BindHexenControls(void);
+void M_BindStrifeControls(void);
+void M_BindWeaponControls(void);
+void M_BindMapControls(void);
+void M_BindMenuControls(void);
+void M_BindChatControls(unsigned int num_players);
+
+void M_ApplyPlatformDefaults(void);
+
+#endif /* #ifndef __M_CONTROLS_H__ */
+
index 4e0792d603319680615c01615a70ed4fadb43ee5..23f6ff3091fd13250bbd9bc968cac2b07800dd44 100644 (file)
@@ -1,38 +1,28 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Fixed point implementation.
 //
-//-----------------------------------------------------------------------------
 
 
-static const char
-rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $";
 
 #include "stdlib.h"
 
 #include "doomtype.h"
 #include "i_system.h"
 
-#ifdef __GNUG__
-#pragma implementation "m_fixed.h"
-#endif
 #include "m_fixed.h"
 
 
@@ -45,7 +35,7 @@ FixedMul
 ( fixed_t      a,
   fixed_t      b )
 {
-    return ((long long) a * (long long) b) >> FRACBITS;
+    return ((int64_t) a * (int64_t) b) >> FRACBITS;
 }
 
 
@@ -54,34 +44,19 @@ FixedMul
 // FixedDiv, C version.
 //
 
-fixed_t
-FixedDiv
-( fixed_t      a,
-  fixed_t      b )
+fixed_t FixedDiv(fixed_t a, fixed_t b)
 {
-    if ( (abs(a)>>14) >= abs(b))
-       return (a^b)<0 ? MININT : MAXINT;
-    return FixedDiv2 (a,b);
+    if ((abs(a) >> 14) >= abs(b))
+    {
+       return (a^b) < 0 ? INT_MIN : INT_MAX;
+    }
+    else
+    {
+       int64_t result;
+
+       result = ((int64_t) a << 16) / b;
+
+       return (fixed_t) result;
+    }
 }
 
-
-
-fixed_t
-FixedDiv2
-( fixed_t      a,
-  fixed_t      b )
-{
-#if 0
-    long long c;
-    c = ((long long)a<<16) / ((long long)b);
-    return (fixed_t) c;
-#endif
-
-    double c;
-
-    c = ((double)a) / ((double)b) * FRACUNIT;
-
-    if (c >= 2147483648.0 || c < -2147483648.0)
-       I_Error("FixedDiv: divide by zero");
-    return (fixed_t) c;
-}
index 7cd7c66631c7e4adde2b58c2d0cf95c6193d48f0..733b2901ce88c2f2d051ea00052483ab4818c5e6 100644 (file)
@@ -1,32 +1,26 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Fixed point arithemtics, implementation.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __M_FIXED__
 #define __M_FIXED__
 
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 
 //
@@ -39,13 +33,7 @@ typedef int fixed_t;
 
 fixed_t FixedMul       (fixed_t a, fixed_t b);
 fixed_t FixedDiv       (fixed_t a, fixed_t b);
-fixed_t FixedDiv2      (fixed_t a, fixed_t b);
 
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 6055d47c895504824bf5052bbf08aea3dc805048..5347522901808a807df5762be1fa83e80f9973fb 100644 (file)
@@ -1,48 +1,42 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     DOOM selection menu, options, episode etc.
 //     Sliders and icons. Kinda widget stuff.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: m_menu.c,v 1.7 1997/02/03 22:45:10 b1 Exp $";
 
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
 #include <stdlib.h>
 #include <ctype.h>
 
 
 #include "doomdef.h"
+#include "doomkeys.h"
 #include "dstrings.h"
 
 #include "d_main.h"
+#include "deh_main.h"
 
+#include "i_swap.h"
 #include "i_system.h"
+#include "i_timer.h"
 #include "i_video.h"
-#include "z_zone.h"
+#include "m_misc.h"
 #include "v_video.h"
 #include "w_wad.h"
+#include "z_zone.h"
 
 #include "r_local.h"
 
@@ -52,7 +46,8 @@ rcsid[] = "$Id: m_menu.c,v 1.7 1997/02/03 22:45:10 b1 Exp $";
 #include "g_game.h"
 
 #include "m_argv.h"
-#include "m_swap.h"
+#include "m_controls.h"
+#include "p_saveg.h"
 
 #include "s_sound.h"
 
@@ -64,7 +59,6 @@ rcsid[] = "$Id: m_menu.c,v 1.7 1997/02/03 22:45:10 b1 Exp $";
 #include "m_menu.h"
 
 
-
 extern patch_t*                hu_font[HU_FONTSIZE];
 extern boolean         message_dontfuckwithme;
 
@@ -73,39 +67,37 @@ extern boolean              chat_on;                // in heads-up code
 //
 // defaulted values
 //
-int                    mouseSensitivity;       // has default
+int                    mouseSensitivity = 5;
 
 // Show messages has default, 0 = off, 1 = on
-int                    showMessages;
+int                    showMessages = 1;
        
 
 // Blocky mode, has default, 0 = high, 1 = normal
-int                    detailLevel;            
-int                    screenblocks;           // has default
+int                    detailLevel = 0;
+int                    screenblocks = 9;
 
 // temp for screenblocks (0-9)
-int                    screenSize;             
+int                    screenSize;
 
 // -1 = no quicksave slot picked!
-int                    quickSaveSlot;          
+int                    quickSaveSlot;
 
  // 1 = message to be printed
 int                    messageToPrint;
 // ...and here is the message string!
-char*                  messageString;          
+char*                  messageString;
 
 // message x & y
-int                    messx;                  
+int                    messx;
 int                    messy;
 int                    messageLastMenuActive;
 
 // timed message = no input from user
-boolean                        messageNeedsInput;     
+boolean                        messageNeedsInput;
 
 void    (*messageRoutine)(int response);
 
-#define SAVESTRINGSIZE         24
-
 char gammamsg[5][26] =
 {
     GAMMALVL0,
@@ -133,6 +125,7 @@ char                        savegamestrings[10][SAVESTRINGSIZE];
 
 char   endstring[160];
 
+//static boolean opldev;
 
 //
 // MENU TYPEDEFS
@@ -172,7 +165,7 @@ short               whichSkull;             // which skull to draw
 
 // graphic name of skulls
 // warning: initializer-string for array of chars is too long
-char    skullName[2][/*8*/9] = {"M_SKULL1","M_SKULL2"};
+char    *skullName[2] = {"M_SKULL1","M_SKULL2"};
 
 // current menudef
 menu_t*        currentMenu;                          
@@ -225,7 +218,6 @@ void M_DrawSelCell(menu_t *menu,int item);
 void M_WriteText(int x, int y, char *string);
 int  M_StringWidth(char *string);
 int  M_StringHeight(char *string);
-void M_StartControlPanel(void);
 void M_StartMessage(char *string,void *routine,boolean input);
 void M_StopMessage(void);
 void M_ClearMenus (void);
@@ -355,9 +347,9 @@ menuitem_t OptionsMenu[]=
     {1,"M_MESSG",      M_ChangeMessages,'m'},
     {1,"M_DETAIL",     M_ChangeDetail,'g'},
     {2,"M_SCRNSZ",     M_SizeDisplay,'s'},
-    {-1,"",0},
+    {-1,"",0,'\0'},
     {2,"M_MSENS",      M_ChangeSensitivity,'m'},
-    {-1,"",0},
+    {-1,"",0,'\0'},
     {1,"M_SVOL",       M_Sound,'s'}
 };
 
@@ -431,9 +423,9 @@ enum
 menuitem_t SoundMenu[]=
 {
     {2,"M_SFXVOL",M_SfxVol,'s'},
-    {-1,"",0},
+    {-1,"",0,'\0'},
     {2,"M_MUSVOL",M_MusicVol,'m'},
-    {-1,"",0}
+    {-1,"",0,'\0'}
 };
 
 menu_t  SoundDef =
@@ -510,28 +502,23 @@ menu_t  SaveDef =
 //
 void M_ReadSaveStrings(void)
 {
-    int             handle;
-    //int             count;
-    int             i;
+    FILE   *handle;
+    int     i;
     char    name[256];
-       
+
     for (i = 0;i < load_end;i++)
     {
-       if (M_CheckParm("-cdrom"))
-           sprintf(name,"c:\\doomdata\\"SAVEGAMENAME"%d.dsg",i);
-       else
-           sprintf(name,SAVEGAMENAME"%d.dsg",i);
-
-       handle = open (name, O_RDONLY | 0, 0666);
-       if (handle == -1)
-       {
-           strcpy(&savegamestrings[i][0],EMPTYSTRING);
-           LoadMenu[i].status = 0;
-           continue;
-       }
-       //count = read (handle, &savegamestrings[i], SAVESTRINGSIZE);
-       read (handle, &savegamestrings[i], SAVESTRINGSIZE);
-       close (handle);
+        M_StringCopy(name, P_SaveGameFile(i), sizeof(name));
+
+       handle = fopen(name, "rb");
+        if (handle == NULL)
+        {
+            M_StringCopy(savegamestrings[i], EMPTYSTRING, SAVESTRINGSIZE);
+            LoadMenu[i].status = 0;
+            continue;
+        }
+       fread(&savegamestrings[i], 1, SAVESTRINGSIZE, handle);
+       fclose(handle);
        LoadMenu[i].status = 1;
     }
 }
@@ -544,7 +531,9 @@ void M_DrawLoad(void)
 {
     int             i;
        
-    V_DrawPatchDirect (72,28,0,W_CacheLumpName("M_LOADG",PU_CACHE));
+    V_DrawPatchDirect(72, 28, 
+                      W_CacheLumpName(DEH_String("M_LOADG"), PU_CACHE));
+
     for (i = 0;i < load_end; i++)
     {
        M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
@@ -561,15 +550,18 @@ void M_DrawSaveLoadBorder(int x,int y)
 {
     int             i;
        
-    V_DrawPatchDirect (x-8,y+7,0,W_CacheLumpName("M_LSLEFT",PU_CACHE));
+    V_DrawPatchDirect(x - 8, y + 7,
+                      W_CacheLumpName(DEH_String("M_LSLEFT"), PU_CACHE));
        
     for (i = 0;i < 24;i++)
     {
-       V_DrawPatchDirect (x,y+7,0,W_CacheLumpName("M_LSCNTR",PU_CACHE));
+       V_DrawPatchDirect(x, y + 7,
+                          W_CacheLumpName(DEH_String("M_LSCNTR"), PU_CACHE));
        x += 8;
     }
 
-    V_DrawPatchDirect (x,y+7,0,W_CacheLumpName("M_LSRGHT",PU_CACHE));
+    V_DrawPatchDirect(x, y + 7, 
+                      W_CacheLumpName(DEH_String("M_LSRGHT"), PU_CACHE));
 }
 
 
@@ -581,10 +573,8 @@ void M_LoadSelect(int choice)
 {
     char    name[256];
        
-    if (M_CheckParm("-cdrom"))
-       sprintf(name,"c:\\doomdata\\"SAVEGAMENAME"%d.dsg",choice);
-    else
-       sprintf(name,SAVEGAMENAME"%d.dsg",choice);
+    M_StringCopy(name, P_SaveGameFile(choice), sizeof(name));
+
     G_LoadGame (name);
     M_ClearMenus ();
 }
@@ -596,7 +586,7 @@ void M_LoadGame (int choice)
 {
     if (netgame)
     {
-       M_StartMessage(LOADNET,NULL,false);
+       M_StartMessage(DEH_String(LOADNET),NULL,false);
        return;
     }
        
@@ -612,7 +602,7 @@ void M_DrawSave(void)
 {
     int             i;
        
-    V_DrawPatchDirect (72,28,0,W_CacheLumpName("M_SAVEG",PU_CACHE));
+    V_DrawPatchDirect(72, 28, W_CacheLumpName(DEH_String("M_SAVEG"), PU_CACHE));
     for (i = 0;i < load_end; i++)
     {
        M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
@@ -648,8 +638,8 @@ void M_SaveSelect(int choice)
     saveStringEnter = 1;
     
     saveSlot = choice;
-    strcpy(saveOldString,savegamestrings[choice]);
-    if (!strcmp(savegamestrings[choice],EMPTYSTRING))
+    M_StringCopy(saveOldString,savegamestrings[choice], SAVESTRINGSIZE);
+    if (!strcmp(savegamestrings[choice], EMPTYSTRING))
        savegamestrings[choice][0] = 0;
     saveCharIndex = strlen(savegamestrings[choice]);
 }
@@ -661,7 +651,7 @@ void M_SaveGame (int choice)
 {
     if (!usergame)
     {
-       M_StartMessage(SAVEDEAD,NULL,false);
+       M_StartMessage(DEH_String(SAVEDEAD),NULL,false);
        return;
     }
        
@@ -679,9 +669,9 @@ void M_SaveGame (int choice)
 //
 char    tempstring[80];
 
-void M_QuickSaveResponse(int ch)
+void M_QuickSaveResponse(int key)
 {
-    if (ch == 'y')
+    if (key == key_menu_confirm)
     {
        M_DoSave(quickSaveSlot);
        S_StartSound(NULL,sfx_swtchx);
@@ -707,7 +697,7 @@ void M_QuickSave(void)
        quickSaveSlot = -2;     // means to pick a slot now
        return;
     }
-    sprintf(tempstring,QSPROMPT,savegamestrings[quickSaveSlot]);
+    DEH_snprintf(tempstring, 80, QSPROMPT, savegamestrings[quickSaveSlot]);
     M_StartMessage(tempstring,M_QuickSaveResponse,true);
 }
 
@@ -716,9 +706,9 @@ void M_QuickSave(void)
 //
 // M_QuickLoad
 //
-void M_QuickLoadResponse(int ch)
+void M_QuickLoadResponse(int key)
 {
-    if (ch == 'y')
+    if (key == key_menu_confirm)
     {
        M_LoadSelect(quickSaveSlot);
        S_StartSound(NULL,sfx_swtchx);
@@ -730,16 +720,16 @@ void M_QuickLoad(void)
 {
     if (netgame)
     {
-       M_StartMessage(QLOADNET,NULL,false);
+       M_StartMessage(DEH_String(QLOADNET),NULL,false);
        return;
     }
        
     if (quickSaveSlot < 0)
     {
-       M_StartMessage(QSAVESPOT,NULL,false);
+       M_StartMessage(DEH_String(QSAVESPOT),NULL,false);
        return;
     }
-    sprintf(tempstring,QLPROMPT,savegamestrings[quickSaveSlot]);
+    DEH_snprintf(tempstring, 80, QLPROMPT, savegamestrings[quickSaveSlot]);
     M_StartMessage(tempstring,M_QuickLoadResponse,true);
 }
 
@@ -752,21 +742,74 @@ void M_QuickLoad(void)
 //
 void M_DrawReadThis1(void)
 {
+    char *lumpname = "CREDIT";
+    int skullx = 330, skully = 175;
+
     inhelpscreens = true;
-    switch ( gamemode )
+    
+    // Different versions of Doom 1.9 work differently
+
+    switch (gameversion)
     {
-      case commercial:
-       V_DrawPatchDirect (0,0,0,W_CacheLumpName("HELP",PU_CACHE));
-       break;
-      case shareware:
-      case registered:
-      case retail:
-       V_DrawPatchDirect (0,0,0,W_CacheLumpName("HELP1",PU_CACHE));
-       break;
-      default:
-       break;
+        case exe_doom_1_666:
+        case exe_doom_1_7:
+        case exe_doom_1_8:
+        case exe_doom_1_9:
+        case exe_hacx:
+
+            if (gamemode == commercial)
+            {
+                // Doom 2
+
+                lumpname = "HELP";
+
+                skullx = 330;
+                skully = 165;
+            }
+            else
+            {
+                // Doom 1
+                // HELP2 is the first screen shown in Doom 1
+                
+                lumpname = "HELP2";
+
+                skullx = 280;
+                skully = 185;
+            }
+            break;
+
+        case exe_ultimate:
+        case exe_chex:
+
+            // Ultimate Doom always displays "HELP1".
+
+            // Chex Quest version also uses "HELP1", even though it is based
+            // on Final Doom.
+
+            lumpname = "HELP1";
+
+            break;
+
+        case exe_final:
+        case exe_final2:
+
+            // Final Doom always displays "HELP".
+
+            lumpname = "HELP";
+
+            break;
+
+        default:
+            I_Error("Unhandled game version");
+            break;
     }
-    return;
+
+    lumpname = DEH_String(lumpname);
+    
+    V_DrawPatchDirect (0, 0, W_CacheLumpName(lumpname, PU_CACHE));
+
+    ReadDef1.x = skullx;
+    ReadDef1.y = skully;
 }
 
 
@@ -777,21 +820,11 @@ void M_DrawReadThis1(void)
 void M_DrawReadThis2(void)
 {
     inhelpscreens = true;
-    switch ( gamemode )
-    {
-      case retail:
-      case commercial:
-       // This hack keeps us from having to change menus.
-       V_DrawPatchDirect (0,0,0,W_CacheLumpName("CREDIT",PU_CACHE));
-       break;
-      case shareware:
-      case registered:
-       V_DrawPatchDirect (0,0,0,W_CacheLumpName("HELP2",PU_CACHE));
-       break;
-      default:
-       break;
-    }
-    return;
+
+    // We only ever draw the second page if this is 
+    // gameversion == exe_doom_1_9 and gamemode == registered
+
+    V_DrawPatchDirect(0, 0, W_CacheLumpName(DEH_String("HELP1"), PU_CACHE));
 }
 
 
@@ -800,13 +833,13 @@ void M_DrawReadThis2(void)
 //
 void M_DrawSound(void)
 {
-    V_DrawPatchDirect (60,38,0,W_CacheLumpName("M_SVOL",PU_CACHE));
+    V_DrawPatchDirect (60, 38, W_CacheLumpName(DEH_String("M_SVOL"), PU_CACHE));
 
     M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1),
-                16,snd_SfxVolume);
+                16,sfxVolume);
 
     M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1),
-                16,snd_MusicVolume);
+                16,musicVolume);
 }
 
 void M_Sound(int choice)
@@ -819,16 +852,16 @@ void M_SfxVol(int choice)
     switch(choice)
     {
       case 0:
-       if (snd_SfxVolume)
-           snd_SfxVolume--;
+       if (sfxVolume)
+           sfxVolume--;
        break;
       case 1:
-       if (snd_SfxVolume < 15)
-           snd_SfxVolume++;
+       if (sfxVolume < 15)
+           sfxVolume++;
        break;
     }
        
-    S_SetSfxVolume(snd_SfxVolume /* *8 */);
+    S_SetSfxVolume(sfxVolume * 8);
 }
 
 void M_MusicVol(int choice)
@@ -836,16 +869,16 @@ void M_MusicVol(int choice)
     switch(choice)
     {
       case 0:
-       if (snd_MusicVolume)
-           snd_MusicVolume--;
+       if (musicVolume)
+           musicVolume--;
        break;
       case 1:
-       if (snd_MusicVolume < 15)
-           snd_MusicVolume++;
+       if (musicVolume < 15)
+           musicVolume++;
        break;
     }
        
-    S_SetMusicVolume(snd_MusicVolume /* *8 */);
+    S_SetMusicVolume(musicVolume * 8);
 }
 
 
@@ -856,7 +889,8 @@ void M_MusicVol(int choice)
 //
 void M_DrawMainMenu(void)
 {
-    V_DrawPatchDirect (94,2,0,W_CacheLumpName("M_DOOM",PU_CACHE));
+    V_DrawPatchDirect(94, 2,
+                      W_CacheLumpName(DEH_String("M_DOOM"), PU_CACHE));
 }
 
 
@@ -867,19 +901,21 @@ void M_DrawMainMenu(void)
 //
 void M_DrawNewGame(void)
 {
-    V_DrawPatchDirect (96,14,0,W_CacheLumpName("M_NEWG",PU_CACHE));
-    V_DrawPatchDirect (54,38,0,W_CacheLumpName("M_SKILL",PU_CACHE));
+    V_DrawPatchDirect(96, 14, W_CacheLumpName(DEH_String("M_NEWG"), PU_CACHE));
+    V_DrawPatchDirect(54, 38, W_CacheLumpName(DEH_String("M_SKILL"), PU_CACHE));
 }
 
 void M_NewGame(int choice)
 {
     if (netgame && !demoplayback)
     {
-       M_StartMessage(NEWGAME,NULL,false);
+       M_StartMessage(DEH_String(NEWGAME),NULL,false);
        return;
     }
        
-    if ( gamemode == commercial )
+    // Chex Quest disabled the episode select screen, as did Doom II.
+
+    if (gamemode == commercial || gameversion == exe_chex)
        M_SetupNextMenu(&NewDef);
     else
        M_SetupNextMenu(&EpiDef);
@@ -893,12 +929,12 @@ int     epi;
 
 void M_DrawEpisode(void)
 {
-    V_DrawPatchDirect (54,38,0,W_CacheLumpName("M_EPISOD",PU_CACHE));
+    V_DrawPatchDirect(54, 38, W_CacheLumpName(DEH_String("M_EPISOD"), PU_CACHE));
 }
 
-void M_VerifyNightmare(int ch)
+void M_VerifyNightmare(int key)
 {
-    if (ch != 'y')
+    if (key != key_menu_confirm)
        return;
                
     G_DeferedInitNew(nightmare,epi+1,1);
@@ -909,7 +945,7 @@ void M_ChooseSkill(int choice)
 {
     if (choice == nightmare)
     {
-       M_StartMessage(NIGHTMARE,M_VerifyNightmare,true);
+       M_StartMessage(DEH_String(NIGHTMARE),M_VerifyNightmare,true);
        return;
     }
        
@@ -922,7 +958,7 @@ void M_Episode(int choice)
     if ( (gamemode == shareware)
         && choice)
     {
-       M_StartMessage(SWSTRING,NULL,false);
+       M_StartMessage(DEH_String(SWSTRING),NULL,false);
        M_SetupNextMenu(&ReadDef1);
        return;
     }
@@ -945,23 +981,25 @@ void M_Episode(int choice)
 //
 // M_Options
 //
-char    detailNames[2][9]      = {"M_GDHIGH","M_GDLOW"};
-char   msgNames[2][9]          = {"M_MSGOFF","M_MSGON"};
-
+static char *detailNames[2] = {"M_GDHIGH","M_GDLOW"};
+static char *msgNames[2] = {"M_MSGOFF","M_MSGON"};
 
 void M_DrawOptions(void)
 {
-    V_DrawPatchDirect (108,15,0,W_CacheLumpName("M_OPTTTL",PU_CACHE));
+    V_DrawPatchDirect(108, 15, W_CacheLumpName(DEH_String("M_OPTTTL"),
+                                               PU_CACHE));
        
-    V_DrawPatchDirect (OptionsDef.x + 175,OptionsDef.y+LINEHEIGHT*detail,0,
-                      W_CacheLumpName(detailNames[detailLevel],PU_CACHE));
+    V_DrawPatchDirect(OptionsDef.x + 175, OptionsDef.y + LINEHEIGHT * detail,
+                     W_CacheLumpName(DEH_String(detailNames[detailLevel]),
+                                     PU_CACHE));
 
-    V_DrawPatchDirect (OptionsDef.x + 120,OptionsDef.y+LINEHEIGHT*messages,0,
-                      W_CacheLumpName(msgNames[showMessages],PU_CACHE));
+    V_DrawPatchDirect(OptionsDef.x + 120, OptionsDef.y + LINEHEIGHT * messages,
+                      W_CacheLumpName(DEH_String(msgNames[showMessages]),
+                                      PU_CACHE));
+
+    M_DrawThermo(OptionsDef.x, OptionsDef.y + LINEHEIGHT * (mousesens + 1),
+                10, mouseSensitivity);
 
-    M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(mousesens+1),
-                10,mouseSensitivity);
-       
     M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1),
                 9,screenSize);
 }
@@ -983,9 +1021,9 @@ void M_ChangeMessages(int choice)
     showMessages = 1 - showMessages;
        
     if (!showMessages)
-       players[consoleplayer].message = MSGOFF;
+       players[consoleplayer].message = DEH_String(MSGOFF);
     else
-       players[consoleplayer].message = MSGON ;
+       players[consoleplayer].message = DEH_String(MSGON);
 
     message_dontfuckwithme = true;
 }
@@ -994,9 +1032,9 @@ void M_ChangeMessages(int choice)
 //
 // M_EndGame
 //
-void M_EndGameResponse(int ch)
+void M_EndGameResponse(int key)
 {
-    if (ch != 'y')
+    if (key != key_menu_confirm)
        return;
                
     currentMenu->lastOn = itemOn;
@@ -1015,11 +1053,11 @@ void M_EndGame(int choice)
        
     if (netgame)
     {
-       M_StartMessage(NETEND,NULL,false);
+       M_StartMessage(DEH_String(NETEND),NULL,false);
        return;
     }
        
-    M_StartMessage(ENDGAME,M_EndGameResponse,true);
+    M_StartMessage(DEH_String(ENDGAME),M_EndGameResponse,true);
 }
 
 
@@ -1036,8 +1074,20 @@ void M_ReadThis(int choice)
 
 void M_ReadThis2(int choice)
 {
-    choice = 0;
-    M_SetupNextMenu(&ReadDef2);
+    // Doom 1.9 had two menus when playing Doom 1
+    // All others had only one
+
+    if (gameversion <= exe_doom_1_9 && gamemode != commercial)
+    {
+        choice = 0;
+        M_SetupNextMenu(&ReadDef2);
+    }
+    else
+    {
+        // Close the menu
+
+        M_FinishReadThis(0);
+    }
 }
 
 void M_FinishReadThis(int choice)
@@ -1078,9 +1128,9 @@ int     quitsounds2[8] =
 
 
 
-void M_QuitResponse(int ch)
+void M_QuitResponse(int key)
 {
-    if (ch != 'y')
+    if (key != key_menu_confirm)
        return;
     if (!netgame)
     {
@@ -1094,18 +1144,33 @@ void M_QuitResponse(int ch)
 }
 
 
+static char *M_SelectEndMessage(void)
+{
+    char **endmsg;
+
+    if (logical_gamemission == doom)
+    {
+        // Doom 1
+
+        endmsg = doom1_endmsg;
+    }
+    else
+    {
+        // Doom 2
+        
+        endmsg = doom2_endmsg;
+    }
+
+    return endmsg[gametic % NUM_QUITMESSAGES];
+}
 
 
 void M_QuitDOOM(int choice)
 {
-  // We pick index 0 which is language sensitive,
-  //  or one at random, between 1 and maximum number.
-  if (language != english )
-    sprintf(endstring,"%s\n\n"DOSY, endmsg[0] );
-  else
-    sprintf(endstring,"%s\n\n"DOSY, endmsg[ (gametic%(NUM_QUITMESSAGES-2))+1 ]);
-  
-  M_StartMessage(endstring,M_QuitResponse,true);
+    DEH_snprintf(endstring, sizeof(endstring), "%s\n\n" DOSY,
+                 DEH_String(M_SelectEndMessage()));
+
+    M_StartMessage(endstring,M_QuitResponse,true);
 }
 
 
@@ -1134,17 +1199,12 @@ void M_ChangeDetail(int choice)
     choice = 0;
     detailLevel = 1 - detailLevel;
 
-    // FIXME - does not work. Remove anyway?
-    fprintf( stderr, "M_ChangeDetail: low detail mode n.a.\n");
-
-    return;
-    
-    /*R_SetViewSize (screenblocks, detailLevel);
+    R_SetViewSize (screenblocks, detailLevel);
 
     if (!detailLevel)
-       players[consoleplayer].message = DETAILHI;
+       players[consoleplayer].message = DEH_String(DETAILHI);
     else
-       players[consoleplayer].message = DETAILLO;*/
+       players[consoleplayer].message = DEH_String(DETAILLO);
 }
 
 
@@ -1191,17 +1251,17 @@ M_DrawThermo
     int                i;
 
     xx = x;
-    V_DrawPatchDirect (xx,y,0,W_CacheLumpName("M_THERML",PU_CACHE));
+    V_DrawPatchDirect(xx, y, W_CacheLumpName(DEH_String("M_THERML"), PU_CACHE));
     xx += 8;
     for (i=0;i<thermWidth;i++)
     {
-       V_DrawPatchDirect (xx,y,0,W_CacheLumpName("M_THERMM",PU_CACHE));
+       V_DrawPatchDirect(xx, y, W_CacheLumpName(DEH_String("M_THERMM"), PU_CACHE));
        xx += 8;
     }
-    V_DrawPatchDirect (xx,y,0,W_CacheLumpName("M_THERMR",PU_CACHE));
+    V_DrawPatchDirect(xx, y, W_CacheLumpName(DEH_String("M_THERMR"), PU_CACHE));
 
-    V_DrawPatchDirect ((x+8) + thermDot*8,y,
-                      0,W_CacheLumpName("M_THERMO",PU_CACHE));
+    V_DrawPatchDirect((x + 8) + thermDot * 8, y,
+                     W_CacheLumpName(DEH_String("M_THERMO"), PU_CACHE));
 }
 
 
@@ -1211,8 +1271,8 @@ M_DrawEmptyCell
 ( menu_t*      menu,
   int          item )
 {
-    V_DrawPatchDirect (menu->x - 10,        menu->y+item*LINEHEIGHT - 1, 0,
-                      W_CacheLumpName("M_CELL1",PU_CACHE));
+    V_DrawPatchDirect(menu->x - 10, menu->y + item * LINEHEIGHT - 1, 
+                      W_CacheLumpName(DEH_String("M_CELL1"), PU_CACHE));
 }
 
 void
@@ -1220,8 +1280,8 @@ M_DrawSelCell
 ( menu_t*      menu,
   int          item )
 {
-    V_DrawPatchDirect (menu->x - 10,        menu->y+item*LINEHEIGHT - 1, 0,
-                      W_CacheLumpName("M_CELL2",PU_CACHE));
+    V_DrawPatchDirect(menu->x - 10, menu->y + item * LINEHEIGHT - 1,
+                      W_CacheLumpName(DEH_String("M_CELL2"), PU_CACHE));
 }
 
 
@@ -1241,7 +1301,6 @@ M_StartMessage
 }
 
 
-
 void M_StopMessage(void)
 {
     menuactive = messageLastMenuActive;
@@ -1255,7 +1314,7 @@ void M_StopMessage(void)
 //
 int M_StringWidth(char* string)
 {
-    int             i;
+    size_t             i;
     int             w = 0;
     int             c;
        
@@ -1278,7 +1337,7 @@ int M_StringWidth(char* string)
 //
 int M_StringHeight(char* string)
 {
-    int             i;
+    size_t             i;
     int             h;
     int             height = SHORT(hu_font[0]->height);
        
@@ -1333,12 +1392,19 @@ M_WriteText
        w = SHORT (hu_font[c]->width);
        if (cx+w > SCREENWIDTH)
            break;
-       V_DrawPatchDirect(cx, cy, 0, hu_font[c]);
+       V_DrawPatchDirect(cx, cy, hu_font[c]);
        cx+=w;
     }
 }
 
+// These keys evaluate to a "null" key in Vanilla Doom that allows weird
+// jumping in the menus. Preserve this behavior for accuracy.
 
+static boolean IsNullKey(int key)
+{
+    return key == KEY_PAUSE || key == KEY_CAPSLOCK
+        || key == KEY_SCRLCK || key == KEY_NUMLOCK;
+}
 
 //
 // CONTROL PANEL
@@ -1350,6 +1416,7 @@ M_WriteText
 boolean M_Responder (event_t* ev)
 {
     int             ch;
+    int             key;
     int             i;
     static  int     joywait = 0;
     static  int     mousewait = 0;
@@ -1357,43 +1424,86 @@ boolean M_Responder (event_t* ev)
     static  int     lasty = 0;
     static  int     mousex = 0;
     static  int     lastx = 0;
-       
-    ch = -1;
+
+    // In testcontrols mode, none of the function keys should do anything
+    // - the only key is escape to quit.
+
+    if (testcontrols)
+    {
+        if (ev->type == ev_quit
+         || (ev->type == ev_keydown
+          && (ev->data1 == key_menu_activate || ev->data1 == key_menu_quit)))
+        {
+            I_Quit();
+            return true;
+        }
+
+        return false;
+    }
+
+    // "close" button pressed on window?
+    if (ev->type == ev_quit)
+    {
+        // First click on close button = bring up quit confirm message.
+        // Second click on close button = confirm quit
+
+        if (menuactive && messageToPrint && messageRoutine == M_QuitResponse)
+        {
+            M_QuitResponse(key_menu_confirm);
+        }
+        else
+        {
+            S_StartSound(NULL,sfx_swtchn);
+            M_QuitDOOM(0);
+        }
+
+        return true;
+    }
+
+    // key is the key pressed, ch is the actual character typed
+  
+    ch = 0;
+    key = -1;
        
     if (ev->type == ev_joystick && joywait < I_GetTime())
     {
-       if (ev->data3 == -1)
+       if (ev->data3 < 0)
        {
-           ch = KEY_UPARROW;
+           key = key_menu_up;
            joywait = I_GetTime() + 5;
        }
-       else if (ev->data3 == 1)
+       else if (ev->data3 > 0)
        {
-           ch = KEY_DOWNARROW;
+           key = key_menu_down;
            joywait = I_GetTime() + 5;
        }
                
-       if (ev->data2 == -1)
+       if (ev->data2 < 0)
        {
-           ch = KEY_LEFTARROW;
+           key = key_menu_left;
            joywait = I_GetTime() + 2;
        }
-       else if (ev->data2 == 1)
+       else if (ev->data2 > 0)
        {
-           ch = KEY_RIGHTARROW;
+           key = key_menu_right;
            joywait = I_GetTime() + 2;
        }
                
        if (ev->data1&1)
        {
-           ch = KEY_ENTER;
+           key = key_menu_forward;
            joywait = I_GetTime() + 5;
        }
        if (ev->data1&2)
        {
-           ch = KEY_BACKSPACE;
+           key = key_menu_back;
            joywait = I_GetTime() + 5;
        }
+        if (joybmenu >= 0 && (ev->data1 & (1 << joybmenu)) != 0)
+        {
+            key = key_menu_activate;
+           joywait = I_GetTime() + 5;
+        }
     }
     else
     {
@@ -1402,13 +1512,13 @@ boolean M_Responder (event_t* ev)
            mousey += ev->data3;
            if (mousey < lasty-30)
            {
-               ch = KEY_DOWNARROW;
+               key = key_menu_down;
                mousewait = I_GetTime() + 5;
                mousey = lasty -= 30;
            }
            else if (mousey > lasty+30)
            {
-               ch = KEY_UPARROW;
+               key = key_menu_up;
                mousewait = I_GetTime() + 5;
                mousey = lasty += 30;
            }
@@ -1416,44 +1526,46 @@ boolean M_Responder (event_t* ev)
            mousex += ev->data2;
            if (mousex < lastx-30)
            {
-               ch = KEY_LEFTARROW;
+               key = key_menu_left;
                mousewait = I_GetTime() + 5;
                mousex = lastx -= 30;
            }
            else if (mousex > lastx+30)
            {
-               ch = KEY_RIGHTARROW;
+               key = key_menu_right;
                mousewait = I_GetTime() + 5;
                mousex = lastx += 30;
            }
                
            if (ev->data1&1)
            {
-               ch = KEY_ENTER;
+               key = key_menu_forward;
                mousewait = I_GetTime() + 15;
            }
                        
            if (ev->data1&2)
            {
-               ch = KEY_BACKSPACE;
+               key = key_menu_back;
                mousewait = I_GetTime() + 15;
            }
        }
        else
+       {
            if (ev->type == ev_keydown)
            {
-               ch = ev->data1;
+               key = ev->data1;
+               ch = ev->data2;
            }
+       }
     }
     
-    if (ch == -1)
+    if (key == -1)
        return false;
 
-    
     // Save Game string input
     if (saveStringEnter)
     {
-       switch(ch)
+       switch(key)
        {
          case KEY_BACKSPACE:
            if (saveCharIndex > 0)
@@ -1462,23 +1574,40 @@ boolean M_Responder (event_t* ev)
                savegamestrings[saveSlot][saveCharIndex] = 0;
            }
            break;
-                               
-         case KEY_ESCAPE:
-           saveStringEnter = 0;
-           strcpy(&savegamestrings[saveSlot][0],saveOldString);
-           break;
-                               
+
+          case KEY_ESCAPE:
+            saveStringEnter = 0;
+            M_StringCopy(savegamestrings[saveSlot], saveOldString,
+                         SAVESTRINGSIZE);
+            break;
+
          case KEY_ENTER:
            saveStringEnter = 0;
            if (savegamestrings[saveSlot][0])
                M_DoSave(saveSlot);
            break;
-                               
+
          default:
-           ch = toupper(ch);
-           if (ch != 32)
-               if (ch-HU_FONTSTART < 0 || ch-HU_FONTSTART >= HU_FONTSIZE)
-                   break;
+            // This is complicated.
+            // Vanilla has a bug where the shift key is ignored when entering
+            // a savegame name. If vanilla_keyboard_mapping is on, we want
+            // to emulate this bug by using 'data1'. But if it's turned off,
+            // it implies the user doesn't care about Vanilla emulation: just
+            // use the correct 'data2'.
+
+            if (vanilla_keyboard_mapping)
+            {
+                ch = key;
+            }
+
+            ch = toupper(ch);
+
+            if (ch != ' '
+             && (ch - HU_FONTSTART < 0 || ch - HU_FONTSTART >= HU_FONTSIZE))
+            {
+                break;
+            }
+
            if (ch >= 32 && ch <= 127 &&
                saveCharIndex < SAVESTRINGSIZE-1 &&
                M_StringWidth(savegamestrings[saveSlot]) <
@@ -1495,121 +1624,137 @@ boolean M_Responder (event_t* ev)
     // Take care of any messages that need input
     if (messageToPrint)
     {
-       if (messageNeedsInput == true &&
-           !(ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE))
-           return false;
-               
+       if (messageNeedsInput)
+        {
+            if (key != ' ' && key != KEY_ESCAPE
+             && key != key_menu_confirm && key != key_menu_abort)
+            {
+                return false;
+            }
+       }
+
        menuactive = messageLastMenuActive;
        messageToPrint = 0;
        if (messageRoutine)
-           messageRoutine(ch);
-                       
+           messageRoutine(key);
+
        menuactive = false;
        S_StartSound(NULL,sfx_swtchx);
        return true;
     }
-       
-    if (devparm && ch == KEY_F1)
+
+    if ((devparm && key == key_menu_help) ||
+        (key != 0 && key == key_menu_screenshot))
     {
        G_ScreenShot ();
        return true;
     }
-               
-    
+
     // F-Keys
     if (!menuactive)
-       switch(ch)
-       {
-         case KEY_MINUS:         // Screen size down
+    {
+       if (key == key_menu_decscreen)      // Screen size down
+        {
            if (automapactive || chat_on)
                return false;
            M_SizeDisplay(0);
            S_StartSound(NULL,sfx_stnmov);
            return true;
-                               
-         case KEY_EQUALS:        // Screen size up
+       }
+        else if (key == key_menu_incscreen) // Screen size up
+        {
            if (automapactive || chat_on)
                return false;
            M_SizeDisplay(1);
            S_StartSound(NULL,sfx_stnmov);
            return true;
-                               
-         case KEY_F1:            // Help key
+       }
+        else if (key == key_menu_help)     // Help key
+        {
            M_StartControlPanel ();
 
            if ( gamemode == retail )
              currentMenu = &ReadDef2;
            else
              currentMenu = &ReadDef1;
-           
+
            itemOn = 0;
            S_StartSound(NULL,sfx_swtchn);
            return true;
-                               
-         case KEY_F2:            // Save
+       }
+        else if (key == key_menu_save)     // Save
+        {
            M_StartControlPanel();
            S_StartSound(NULL,sfx_swtchn);
            M_SaveGame(0);
            return true;
-                               
-         case KEY_F3:            // Load
+        }
+        else if (key == key_menu_load)     // Load
+        {
            M_StartControlPanel();
            S_StartSound(NULL,sfx_swtchn);
            M_LoadGame(0);
            return true;
-                               
-         case KEY_F4:            // Sound Volume
+        }
+        else if (key == key_menu_volume)   // Sound Volume
+        {
            M_StartControlPanel ();
            currentMenu = &SoundDef;
            itemOn = sfx_vol;
            S_StartSound(NULL,sfx_swtchn);
            return true;
-                               
-         case KEY_F5:            // Detail toggle
+       }
+        else if (key == key_menu_detail)   // Detail toggle
+        {
            M_ChangeDetail(0);
            S_StartSound(NULL,sfx_swtchn);
            return true;
-                               
-         case KEY_F6:            // Quicksave
+        }
+        else if (key == key_menu_qsave)    // Quicksave
+        {
            S_StartSound(NULL,sfx_swtchn);
            M_QuickSave();
            return true;
-                               
-         case KEY_F7:            // End game
+        }
+        else if (key == key_menu_endgame)  // End game
+        {
            S_StartSound(NULL,sfx_swtchn);
            M_EndGame(0);
            return true;
-                               
-         case KEY_F8:            // Toggle messages
+        }
+        else if (key == key_menu_messages) // Toggle messages
+        {
            M_ChangeMessages(0);
            S_StartSound(NULL,sfx_swtchn);
            return true;
-                               
-         case KEY_F9:            // Quickload
+        }
+        else if (key == key_menu_qload)    // Quickload
+        {
            S_StartSound(NULL,sfx_swtchn);
            M_QuickLoad();
            return true;
-                               
-         case KEY_F10:           // Quit DOOM
+        }
+        else if (key == key_menu_quit)     // Quit DOOM
+        {
            S_StartSound(NULL,sfx_swtchn);
            M_QuitDOOM(0);
            return true;
-                               
-         case KEY_F11:           // gamma toggle
+        }
+        else if (key == key_menu_gamma)    // gamma toggle
+        {
            usegamma++;
            if (usegamma > 4)
                usegamma = 0;
-           players[consoleplayer].message = gammamsg[usegamma];
-           I_SetPalette (W_CacheLumpName ("PLAYPAL",PU_CACHE));
+           players[consoleplayer].message = DEH_String(gammamsg[usegamma]);
+            I_SetPalette (W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE));
            return true;
-                               
        }
+    }
 
-    
     // Pop-up menu?
     if (!menuactive)
     {
-       if (ch == KEY_ESCAPE)
+       if (key == key_menu_activate)
        {
            M_StartControlPanel ();
            S_StartSound(NULL,sfx_swtchn);
@@ -1618,21 +1763,26 @@ boolean M_Responder (event_t* ev)
        return false;
     }
 
-    
     // Keys usable within menu
-    switch (ch)
+
+    if (key == key_menu_down)
     {
-      case KEY_DOWNARROW:
-       do
+        // Move down to next item
+
+        do
        {
            if (itemOn+1 > currentMenu->numitems-1)
                itemOn = 0;
            else itemOn++;
            S_StartSound(NULL,sfx_pstop);
        } while(currentMenu->menuitems[itemOn].status==-1);
+
        return true;
-               
-      case KEY_UPARROW:
+    }
+    else if (key == key_menu_up)
+    {
+        // Move back up to previous item
+
        do
        {
            if (!itemOn)
@@ -1640,9 +1790,13 @@ boolean M_Responder (event_t* ev)
            else itemOn--;
            S_StartSound(NULL,sfx_pstop);
        } while(currentMenu->menuitems[itemOn].status==-1);
+
        return true;
+    }
+    else if (key == key_menu_left)
+    {
+        // Slide slider left
 
-      case KEY_LEFTARROW:
        if (currentMenu->menuitems[itemOn].routine &&
            currentMenu->menuitems[itemOn].status == 2)
        {
@@ -1650,8 +1804,11 @@ boolean M_Responder (event_t* ev)
            currentMenu->menuitems[itemOn].routine(0);
        }
        return true;
-               
-      case KEY_RIGHTARROW:
+    }
+    else if (key == key_menu_right)
+    {
+        // Slide slider right
+
        if (currentMenu->menuitems[itemOn].routine &&
            currentMenu->menuitems[itemOn].status == 2)
        {
@@ -1659,8 +1816,11 @@ boolean M_Responder (event_t* ev)
            currentMenu->menuitems[itemOn].routine(1);
        }
        return true;
+    }
+    else if (key == key_menu_forward)
+    {
+        // Activate menu item
 
-      case KEY_ENTER:
        if (currentMenu->menuitems[itemOn].routine &&
            currentMenu->menuitems[itemOn].status)
        {
@@ -1677,14 +1837,20 @@ boolean M_Responder (event_t* ev)
            }
        }
        return true;
-               
-      case KEY_ESCAPE:
+    }
+    else if (key == key_menu_activate)
+    {
+        // Deactivate menu
+
        currentMenu->lastOn = itemOn;
        M_ClearMenus ();
        S_StartSound(NULL,sfx_swtchx);
        return true;
-               
-      case KEY_BACKSPACE:
+    }
+    else if (key == key_menu_back)
+    {
+        // Go back to previous menu
+
        currentMenu->lastOn = itemOn;
        if (currentMenu->prevMenu)
        {
@@ -1693,24 +1859,33 @@ boolean M_Responder (event_t* ev)
            S_StartSound(NULL,sfx_swtchn);
        }
        return true;
-       
-      default:
+    }
+
+    // Keyboard shortcut?
+    // Vanilla Doom has a weird behavior where it jumps to the scroll bars
+    // when the certain keys are pressed, so emulate this.
+
+    else if (ch != 0 || IsNullKey(key))
+    {
        for (i = itemOn+1;i < currentMenu->numitems;i++)
+        {
            if (currentMenu->menuitems[i].alphaKey == ch)
            {
                itemOn = i;
                S_StartSound(NULL,sfx_pstop);
                return true;
            }
+        }
+
        for (i = 0;i <= itemOn;i++)
+        {
            if (currentMenu->menuitems[i].alphaKey == ch)
            {
                itemOn = i;
                S_StartSound(NULL,sfx_pstop);
                return true;
            }
-       break;
-       
+        }
     }
 
     return false;
@@ -1732,6 +1907,41 @@ void M_StartControlPanel (void)
     itemOn = currentMenu->lastOn;   // JDC
 }
 
+// Display OPL debug messages - hack for GENMIDI development.
+
+#if 0
+static void M_DrawOPLDev(void)
+{
+    extern void I_OPL_DevMessages(char *, size_t);
+    char debug[1024];
+    char *curr, *p;
+    int line;
+
+    //XXX I_OPL_DevMessages(debug, sizeof(debug));
+    curr = debug;
+    line = 0;
+
+    for (;;)
+    {
+        p = strchr(curr, '\n');
+
+        if (p != NULL)
+        {
+            *p = '\0';
+        }
+
+        M_WriteText(0, line * 8, curr);
+        ++line;
+
+        if (p == NULL)
+        {
+            break;
+        }
+
+        curr = p + 1;
+    }
+}
+#endif
 
 //
 // M_Drawer
@@ -1742,43 +1952,59 @@ void M_Drawer (void)
 {
     static short       x;
     static short       y;
-    short              i;
-    short              max;
-    char               string[40];
+    unsigned int       i;
+    unsigned int       max;
+    char               string[80];
+    char               *name;
     int                        start;
 
     inhelpscreens = false;
-
     
     // Horiz. & Vertically center string and print it.
     if (messageToPrint)
     {
        start = 0;
-       y = 100 - M_StringHeight(messageString)/2;
-       while(*(messageString+start))
+       y = SCREENHEIGHT/2 - M_StringHeight(messageString) / 2;
+       while (messageString[start] != '\0')
        {
-           for (i = 0;i < strlen(messageString+start);i++)
-               if (*(messageString+start+i) == '\n')
-               {
-                   memset(string,0,40);
-                   strncpy(string,messageString+start,i);
-                   start += i+1;
-                   break;
-               }
-                               
-           if (i == strlen(messageString+start))
-           {
-               strcpy(string,messageString+start);
-               start += i;
-           }
-                               
-           x = 160 - M_StringWidth(string)/2;
-           M_WriteText(x,y,string);
+           int foundnewline = 0;
+
+            for (i = 0; i < strlen(messageString + start); i++)
+            {
+                if (messageString[start + i] == '\n')
+                {
+                    M_StringCopy(string, messageString + start,
+                                 sizeof(string));
+                    if (i < sizeof(string))
+                    {
+                        string[i] = '\0';
+                    }
+
+                    foundnewline = 1;
+                    start += i + 1;
+                    break;
+                }
+            }
+
+            if (!foundnewline)
+            {
+                M_StringCopy(string, messageString + start, sizeof(string));
+                start += strlen(string);
+            }
+
+           x = SCREENWIDTH/2 - M_StringWidth(string) / 2;
+           M_WriteText(x, y, string);
            y += SHORT(hu_font[0]->height);
        }
+
        return;
     }
 
+    //if (opldev)
+    //{
+    //    M_DrawOPLDev();
+    //}
+
     if (!menuactive)
        return;
 
@@ -1792,17 +2018,20 @@ void M_Drawer (void)
 
     for (i=0;i<max;i++)
     {
-       if (currentMenu->menuitems[i].name[0])
-           V_DrawPatchDirect (x,y,0,
-                              W_CacheLumpName(currentMenu->menuitems[i].name ,PU_CACHE));
+        name = DEH_String(currentMenu->menuitems[i].name);
+
+       if (name[0])
+       {
+           V_DrawPatchDirect (x, y, W_CacheLumpName(name, PU_CACHE));
+       }
        y += LINEHEIGHT;
     }
 
     
     // DRAW SKULL
-    V_DrawPatchDirect(x + SKULLXOFF,currentMenu->y - 5 + itemOn*LINEHEIGHT, 0,
-                     W_CacheLumpName(skullName[whichSkull],PU_CACHE));
-
+    V_DrawPatchDirect(x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT,
+                     W_CacheLumpName(DEH_String(skullName[whichSkull]),
+                                     PU_CACHE));
 }
 
 
@@ -1865,30 +2094,32 @@ void M_Init (void)
     switch ( gamemode )
     {
       case commercial:
-       // This is used because DOOM 2 had only one HELP
-        //  page. I use CREDIT as second page now, but
-       //  kept this hack for educational purposes.
+        // Commercial has no "read this" entry.
        MainMenu[readthis] = MainMenu[quitdoom];
        MainDef.numitems--;
        MainDef.y += 8;
        NewDef.prevMenu = &MainDef;
-       ReadDef1.routine = M_DrawReadThis1;
-       ReadDef1.x = 330;
-       ReadDef1.y = 165;
-       ReadMenu1[0].routine = M_FinishReadThis;
        break;
       case shareware:
        // Episode 2 and 3 are handled,
        //  branching to an ad screen.
       case registered:
-       // We need to remove the fourth episode.
-       EpiDef.numitems--;
        break;
       case retail:
        // We are fine.
       default:
        break;
     }
-    
+
+    // Versions of doom.exe before the Ultimate Doom release only had
+    // three episodes; if we're emulating one of those then don't try
+    // to show episode four. If we are, then do show episode four
+    // (should crash if missing).
+    if (gameversion < exe_ultimate)
+    {
+       EpiDef.numitems--;
+    }
+
+    //opldev = M_CheckParm("-opldev") > 0;
 }
 
index b02aa07f952cbb8807d4064dd129ede00426ef64..ce41db39adbaa89a4f11c8dd879890fbdc635a0d 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //   Menu widget stuff, episode selection and such.
 //    
-//-----------------------------------------------------------------------------
 
 
 #ifndef __M_MENU__
@@ -56,12 +53,9 @@ void M_StartControlPanel (void);
 
 
 
+extern int detailLevel;
+extern int screenblocks;
 
 
 
 #endif    
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 0df4fe57d6ebdf2d60fc608393cb7290574508a6..53b86dbab75ea7d261f05f56bce73e61d3b21c72 100644 (file)
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
-//     Main loop menu stuff.
-//     Default Config File.
-//     PCX Screenshots.
+//      Miscellaneous.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: m_misc.c,v 1.6 1997/02/03 22:45:10 b1 Exp $";
 
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
+#include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-
+#include <string.h>
 #include <ctype.h>
+#include <errno.h>
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <io.h>
+#ifdef _MSC_VER
+#include <direct.h>
+#endif
+#else
+#include <sys/stat.h>
+#include <sys/types.h>
+#endif
 
+#include "doomtype.h"
 
-#include "doomdef.h"
-
-#include "z_zone.h"
-
-#include "m_swap.h"
-#include "m_argv.h"
-
-#include "w_wad.h"
+#include "deh_str.h"
 
+#include "i_swap.h"
 #include "i_system.h"
 #include "i_video.h"
+#include "m_misc.h"
 #include "v_video.h"
+#include "w_wad.h"
+#include "z_zone.h"
 
-#include "hu_stuff.h"
-
-// State.
-#include "doomstat.h"
+//
+// Create a directory
+//
 
-// Data.
-#include "dstrings.h"
+void M_MakeDirectory(char *path)
+{
+#ifdef _WIN32
+    mkdir(path);
+#else
+    mkdir(path, 0755);
+#endif
+}
 
-#include "m_misc.h"
+// Check if a file exists
 
-//
-// M_DrawText
-// Returns the final X coordinate
-// HU_Init must have been called to init the font
-//
-extern patch_t*                hu_font[HU_FONTSIZE];
-
-int
-M_DrawText
-( int          x,
-  int          y,
-  boolean      direct,
-  char*                string )
+boolean M_FileExists(char *filename)
 {
-    int        c;
-    int                w;
+    FILE *fstream;
+
+    fstream = fopen(filename, "r");
 
-    while (*string)
+    if (fstream != NULL)
     {
-       c = toupper(*string) - HU_FONTSTART;
-       string++;
-       if (c < 0 || c> HU_FONTSIZE)
-       {
-           x += 4;
-           continue;
-       }
-               
-       w = SHORT (hu_font[c]->width);
-       if (x+w > SCREENWIDTH)
-           break;
-       if (direct)
-           V_DrawPatchDirect(x, y, 0, hu_font[c]);
-       else
-           V_DrawPatch(x, y, 0, hu_font[c]);
-       x+=w;
+        fclose(fstream);
+        return true;
     }
+    else
+    {
+        // If we can't open because the file is a directory, the 
+        // "file" exists at least!
 
-    return x;
+        return errno == EISDIR;
+    }
 }
 
+//
+// Determine the length of an open file.
+//
+
+long M_FileLength(FILE *handle)
+{ 
+    long savedpos;
+    long length;
+
+    // save the current position in the file
+    savedpos = ftell(handle);
+    
+    // jump to the end and find the length
+    fseek(handle, 0, SEEK_END);
+    length = ftell(handle);
 
+    // go back to the old location
+    fseek(handle, savedpos, SEEK_SET);
 
+    return length;
+}
 
 //
 // M_WriteFile
 //
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
 
-boolean
-M_WriteFile
-( char const*  name,
-  void*                source,
-  int          length )
+boolean M_WriteFile(char *name, void *source, int length)
 {
-    int                handle;
-    int                count;
+    FILE *handle;
+    int        count;
        
-    handle = open ( name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+    handle = fopen(name, "wb");
 
-    if (handle == -1)
+    if (handle == NULL)
        return false;
 
-    count = write (handle, source, length);
-    close (handle);
+    count = fwrite(source, 1, length, handle);
+    fclose(handle);
        
     if (count < length)
        return false;
@@ -136,24 +132,25 @@ M_WriteFile
 //
 // M_ReadFile
 //
-int
-M_ReadFile
-( char const*  name,
-  byte**       buffer )
+
+int M_ReadFile(char *name, byte **buffer)
 {
-    int        handle, count, length;
-    struct stat        fileinfo;
-    byte               *buf;
+    FILE *handle;
+    int        count, length;
+    byte *buf;
        
-    handle = open (name, O_RDONLY | O_BINARY, 0666);
-    if (handle == -1)
-       I_Error ("Couldn't read file %s", name);
-    if (fstat (handle,&fileinfo) == -1)
+    handle = fopen(name, "rb");
+    if (handle == NULL)
        I_Error ("Couldn't read file %s", name);
-    length = fileinfo.st_size;
+
+    // find the size of the file by seeking to the end and
+    // reading the current position
+
+    length = M_FileLength(handle);
+    
     buf = Z_Malloc (length, PU_STATIC, NULL);
-    count = read (handle, buf, length);
-    close (handle);
+    count = fread(buf, 1, length, handle);
+    fclose (handle);
        
     if (count < length)
        I_Error ("Couldn't read file %s", name);
@@ -162,373 +159,378 @@ M_ReadFile
     return length;
 }
 
-
-//
-// DEFAULTS
+// Returns the path to a temporary file of the given name, stored
+// inside the system temporary directory.
 //
-int            usemouse;
-int            usejoystick;
+// The returned value must be freed with Z_Free after use.
 
-extern int     key_right;
-extern int     key_left;
-extern int     key_up;
-extern int     key_down;
-
-extern int     key_strafeleft;
-extern int     key_straferight;
+char *M_TempFile(char *s)
+{
+    char *tempdir;
 
-extern int     key_fire;
-extern int     key_use;
-extern int     key_strafe;
-extern int     key_speed;
+#ifdef _WIN32
 
-extern int     mousebfire;
-extern int     mousebstrafe;
-extern int     mousebforward;
+    // Check the TEMP environment variable to find the location.
 
-extern int     joybfire;
-extern int     joybstrafe;
-extern int     joybuse;
-extern int     joybspeed;
+    tempdir = getenv("TEMP");
 
-extern int     viewwidth;
-extern int     viewheight;
+    if (tempdir == NULL)
+    {
+        tempdir = ".";
+    }
+#else
+    // In Unix, just use /tmp.
 
-extern int     mouseSensitivity;
-extern int     showMessages;
+    tempdir = "/tmp";
+#endif
 
-extern int     detailLevel;
+    return M_StringJoin(tempdir, DIR_SEPARATOR_S, s, NULL);
+}
 
-extern int     screenblocks;
+boolean M_StrToInt(const char *str, int *result)
+{
+    return sscanf(str, " 0x%x", result) == 1
+        || sscanf(str, " 0X%x", result) == 1
+        || sscanf(str, " 0%o", result) == 1
+        || sscanf(str, " %d", result) == 1;
+}
 
-extern int     showMessages;
+void M_ExtractFileBase(char *path, char *dest)
+{
+    char *src;
+    char *filename;
+    int length;
 
-// machine-independent sound params
-extern int     numChannels;
+    src = path + strlen(path) - 1;
 
+    // back up until a \ or the start
+    while (src != path && *(src - 1) != DIR_SEPARATOR)
+    {
+       src--;
+    }
 
-// UNIX hack, to be removed.
-#ifdef SNDSERV
-extern char*   sndserver_filename;
-extern int     mb_used;
-#endif
+    filename = src;
 
-#ifdef LINUX
-char*          mousetype;
-char*          mousedev;
-#endif
+    // Copy up to eight characters
+    // Note: Vanilla Doom exits with an error if a filename is specified
+    // with a base of more than eight characters.  To remove the 8.3
+    // filename limit, instead we simply truncate the name.
 
-extern char*   chat_macros[];
+    length = 0;
+    memset(dest, 0, 8);
 
+    while (*src != '\0' && *src != '.')
+    {
+        if (length >= 8)
+        {
+            printf("Warning: Truncated '%s' lump name to '%.8s'.\n",
+                   filename, dest);
+            break;
+        }
+
+       dest[length++] = toupper((int)*src++);
+    }
+}
 
+//---------------------------------------------------------------------------
+//
+// PROC M_ForceUppercase
+//
+// Change string to uppercase.
+//
+//---------------------------------------------------------------------------
 
-typedef struct
+void M_ForceUppercase(char *text)
 {
-    char*      name;
-    int*       location;
-    int                defaultvalue;
-    int                scantranslate;          // PC scan code hack
-    int                untranslated;           // lousy hack
-} default_t;
-
-default_t      defaults[] =
-{
-    {"mouse_sensitivity",&mouseSensitivity, 5},
-    {"sfx_volume",&snd_SfxVolume, 8},
-    {"music_volume",&snd_MusicVolume, 8},
-    {"show_messages",&showMessages, 1},
-    
+    char *p;
 
-#ifdef NORMALUNIX
-    {"key_right",&key_right, KEY_RIGHTARROW},
-    {"key_left",&key_left, KEY_LEFTARROW},
-    {"key_up",&key_up, KEY_UPARROW},
-    {"key_down",&key_down, KEY_DOWNARROW},
-    {"key_strafeleft",&key_strafeleft, ','},
-    {"key_straferight",&key_straferight, '.'},
-
-    {"key_fire",&key_fire, KEY_RCTRL},
-    {"key_use",&key_use, ' '},
-    {"key_strafe",&key_strafe, KEY_RALT},
-    {"key_speed",&key_speed, KEY_RSHIFT},
-
-// UNIX hack, to be removed. 
-#ifdef SNDSERV
-    {"sndserver", (int *) &sndserver_filename, (int) "sndserver"},
-    {"mb_used", &mb_used, 2},
-#endif
-    
-#endif
+    for (p = text; *p != '\0'; ++p)
+    {
+        *p = toupper(*p);
+    }
+}
 
-#ifdef LINUX
-    {"mousedev", (int*)&mousedev, (int)"/dev/ttyS0"},
-    {"mousetype", (int*)&mousetype, (int)"microsoft"},
-#endif
+//
+// M_StrCaseStr
+//
+// Case-insensitive version of strstr()
+//
 
-    {"use_mouse",&usemouse, 1},
-    {"mouseb_fire",&mousebfire,0},
-    {"mouseb_strafe",&mousebstrafe,1},
-    {"mouseb_forward",&mousebforward,2},
+char *M_StrCaseStr(char *haystack, char *needle)
+{
+    unsigned int haystack_len;
+    unsigned int needle_len;
+    unsigned int len;
+    unsigned int i;
 
-    {"use_joystick",&usejoystick, 0},
-    {"joyb_fire",&joybfire,0},
-    {"joyb_strafe",&joybstrafe,1},
-    {"joyb_use",&joybuse,3},
-    {"joyb_speed",&joybspeed,2},
+    haystack_len = strlen(haystack);
+    needle_len = strlen(needle);
 
-    {"screenblocks",&screenblocks, 9},
-    {"detaillevel",&detailLevel, 0},
+    if (haystack_len < needle_len)
+    {
+        return NULL;
+    }
 
-    {"snd_channels",&numChannels, 3},
+    len = haystack_len - needle_len;
 
+    for (i = 0; i <= len; ++i)
+    {
+        if (!strncasecmp(haystack + i, needle, needle_len))
+        {
+            return haystack + i;
+        }
+    }
 
+    return NULL;
+}
 
-    {"usegamma",&usegamma, 0},
+//
+// Safe version of strdup() that checks the string was successfully
+// allocated.
+//
 
-    {"chatmacro0", (int *) &chat_macros[0], (int) HUSTR_CHATMACRO0 },
-    {"chatmacro1", (int *) &chat_macros[1], (int) HUSTR_CHATMACRO1 },
-    {"chatmacro2", (int *) &chat_macros[2], (int) HUSTR_CHATMACRO2 },
-    {"chatmacro3", (int *) &chat_macros[3], (int) HUSTR_CHATMACRO3 },
-    {"chatmacro4", (int *) &chat_macros[4], (int) HUSTR_CHATMACRO4 },
-    {"chatmacro5", (int *) &chat_macros[5], (int) HUSTR_CHATMACRO5 },
-    {"chatmacro6", (int *) &chat_macros[6], (int) HUSTR_CHATMACRO6 },
-    {"chatmacro7", (int *) &chat_macros[7], (int) HUSTR_CHATMACRO7 },
-    {"chatmacro8", (int *) &chat_macros[8], (int) HUSTR_CHATMACRO8 },
-    {"chatmacro9", (int *) &chat_macros[9], (int) HUSTR_CHATMACRO9 }
+char *M_StringDuplicate(const char *orig)
+{
+    char *result;
 
-};
+    result = strdup(orig);
 
-int    numdefaults;
-char*  defaultfile;
+    if (result == NULL)
+    {
+        I_Error("Failed to duplicate string (length %i)\n",
+                strlen(orig));
+    }
 
+    return result;
+}
 
 //
-// M_SaveDefaults
+// String replace function.
 //
-void M_SaveDefaults (void)
+
+char *M_StringReplace(const char *haystack, const char *needle,
+                      const char *replacement)
 {
-    int                i;
-    int                v;
-    FILE*      f;
-       
-    f = fopen (defaultfile, "w");
-    if (!f)
-       return; // can't write the file, but don't complain
-               
-    for (i=0 ; i<numdefaults ; i++)
+    char *result, *dst;
+    const char *p;
+    size_t needle_len = strlen(needle);
+    size_t result_len, dst_len;
+
+    // Iterate through occurrences of 'needle' and calculate the size of
+    // the new string.
+    result_len = strlen(haystack) + 1;
+    p = haystack;
+
+    for (;;)
     {
-       if (defaults[i].defaultvalue > -0xfff
-           && defaults[i].defaultvalue < 0xfff)
-       {
-           v = *defaults[i].location;
-           fprintf (f,"%s\t\t%i\n",defaults[i].name,v);
-       } else {
-           fprintf (f,"%s\t\t\"%s\"\n",defaults[i].name,
-                    * (char **) (defaults[i].location));
-       }
+        p = strstr(p, needle);
+        if (p == NULL)
+        {
+            break;
+        }
+
+        p += needle_len;
+        result_len += strlen(replacement) - needle_len;
     }
-       
-    fclose (f);
-}
 
+    // Construct new string.
 
-//
-// M_LoadDefaults
-//
-extern byte    scantokey[128];
+    result = malloc(result_len);
+    if (result == NULL)
+    {
+        I_Error("M_StringReplace: Failed to allocate new string");
+        return NULL;
+    }
+
+    dst = result; dst_len = result_len;
+    p = haystack;
+
+    while (*p != '\0')
+    {
+        if (!strncmp(p, needle, needle_len))
+        {
+            M_StringCopy(dst, replacement, dst_len);
+            p += needle_len;
+            dst += strlen(replacement);
+            dst_len -= strlen(replacement);
+        }
+        else
+        {
+            *dst = *p;
+            ++dst; --dst_len;
+            ++p;
+        }
+    }
+
+    *dst = '\0';
+
+    return result;
+}
+
+// Safe string copy function that works like OpenBSD's strlcpy().
+// Returns true if the string was not truncated.
 
-void M_LoadDefaults (void)
+boolean M_StringCopy(char *dest, const char *src, size_t dest_size)
 {
-    int                i;
-    int                len;
-    FILE*      f;
-    char       def[80];
-    char       strparm[100];
-    char*      newstring;
-    int                parm;
-    boolean    isstring;
-    
-    // set everything to base values
-    numdefaults = sizeof(defaults)/sizeof(defaults[0]);
-    for (i=0 ; i<numdefaults ; i++)
-       *defaults[i].location = defaults[i].defaultvalue;
-    
-    // check for a custom default file
-    i = M_CheckParm ("-config");
-    if (i && i<myargc-1)
+    size_t len;
+
+    if (dest_size >= 1)
     {
-       defaultfile = myargv[i+1];
-       printf ("       default file: %s\n",defaultfile);
+        dest[dest_size - 1] = '\0';
+        strncpy(dest, src, dest_size - 1);
     }
     else
-       defaultfile = basedefault;
-    
-    // read the file in, overriding any set defaults
-    f = fopen (defaultfile, "r");
-    if (f)
     {
-       while (!feof(f))
-       {
-           isstring = false;
-           if (fscanf (f, "%79s %[^\n]\n", def, strparm) == 2)
-           {
-               if (strparm[0] == '"')
-               {
-                   // get a string default
-                   isstring = true;
-                   len = strlen(strparm);
-                   newstring = (char *) malloc(len);
-                   strparm[len-1] = 0;
-                   strcpy(newstring, strparm+1);
-               }
-               else if (strparm[0] == '0' && strparm[1] == 'x')
-                   sscanf(strparm+2, "%x", &parm);
-               else
-                   sscanf(strparm, "%i", &parm);
-               for (i=0 ; i<numdefaults ; i++)
-                   if (!strcmp(def, defaults[i].name))
-                   {
-                       if (!isstring)
-                           *defaults[i].location = parm;
-                       else
-                           *defaults[i].location =
-                               (int) newstring;
-                       break;
-                   }
-           }
-       }
-               
-       fclose (f);
+        return false;
     }
+
+    len = strlen(dest);
+    return src[len] == '\0';
 }
 
+// Safe string concat function that works like OpenBSD's strlcat().
+// Returns true if string not truncated.
 
-//
-// SCREEN SHOTS
-//
+boolean M_StringConcat(char *dest, const char *src, size_t dest_size)
+{
+    size_t offset;
 
+    offset = strlen(dest);
+    if (offset > dest_size)
+    {
+        offset = dest_size;
+    }
 
-typedef struct
+    return M_StringCopy(dest + offset, src, dest_size - offset);
+}
+
+// Returns true if 's' begins with the specified prefix.
+
+boolean M_StringStartsWith(const char *s, const char *prefix)
 {
-    char               manufacturer;
-    char               version;
-    char               encoding;
-    char               bits_per_pixel;
-
-    unsigned short     xmin;
-    unsigned short     ymin;
-    unsigned short     xmax;
-    unsigned short     ymax;
-    
-    unsigned short     hres;
-    unsigned short     vres;
+    return strlen(s) > strlen(prefix)
+        && strncmp(s, prefix, strlen(prefix)) == 0;
+}
 
-    unsigned char      palette[48];
-    
-    char               reserved;
-    char               color_planes;
-    unsigned short     bytes_per_line;
-    unsigned short     palette_type;
-    
-    char               filler[58];
-    unsigned char      data;           // unbounded
-} pcx_t;
+// Returns true if 's' ends with the specified suffix.
 
+boolean M_StringEndsWith(const char *s, const char *suffix)
+{
+    return strlen(s) >= strlen(suffix)
+        && strcmp(s + strlen(s) - strlen(suffix), suffix) == 0;
+}
 
-//
-// WritePCXfile
-//
-void
-WritePCXfile
-( char*                filename,
-  byte*                data,
-  int          width,
-  int          height,
-  byte*                palette )
+// Return a newly-malloced string with all the strings given as arguments
+// concatenated together.
+
+char *M_StringJoin(const char *s, ...)
 {
-    int                i;
-    int                length;
-    pcx_t*     pcx;
-    byte*      pack;
-       
-    pcx = Z_Malloc (width*height*2+1000, PU_STATIC, NULL);
-
-    pcx->manufacturer = 0x0a;          // PCX id
-    pcx->version = 5;                  // 256 color
-    pcx->encoding = 1;                 // uncompressed
-    pcx->bits_per_pixel = 8;           // 256 color
-    pcx->xmin = 0;
-    pcx->ymin = 0;
-    pcx->xmax = SHORT(width-1);
-    pcx->ymax = SHORT(height-1);
-    pcx->hres = SHORT(width);
-    pcx->vres = SHORT(height);
-    memset (pcx->palette,0,sizeof(pcx->palette));
-    pcx->color_planes = 1;             // chunky image
-    pcx->bytes_per_line = SHORT(width);
-    pcx->palette_type = SHORT(2);      // not a grey scale
-    memset (pcx->filler,0,sizeof(pcx->filler));
-
-
-    // pack the image
-    pack = &pcx->data;
-       
-    for (i=0 ; i<width*height ; i++)
+    char *result;
+    const char *v;
+    va_list args;
+    size_t result_len;
+
+    result_len = strlen(s) + 1;
+
+    va_start(args, s);
+    for (;;)
     {
-       if ( (*data & 0xc0) != 0xc0)
-           *pack++ = *data++;
-       else
-       {
-           *pack++ = 0xc1;
-           *pack++ = *data++;
-       }
+        v = va_arg(args, const char *);
+        if (v == NULL)
+        {
+            break;
+        }
+
+        result_len += strlen(v);
     }
-    
-    // write the palette
-    *pack++ = 0x0c;    // palette ID byte
-    for (i=0 ; i<768 ; i++)
-       *pack++ = *palette++;
-    
-    // write output file
-    length = pack - (byte *)pcx;
-    M_WriteFile (filename, pcx, length);
+    va_end(args);
+
+    result = malloc(result_len);
+
+    if (result == NULL)
+    {
+        I_Error("M_StringJoin: Failed to allocate new string.");
+        return NULL;
+    }
+
+    M_StringCopy(result, s, result_len);
 
-    Z_Free (pcx);
+    va_start(args, s);
+    for (;;)
+    {
+        v = va_arg(args, const char *);
+        if (v == NULL)
+        {
+            break;
+        }
+
+        M_StringConcat(result, v, result_len);
+    }
+    va_end(args);
+
+    return result;
 }
 
+// On Windows, vsnprintf() is _vsnprintf().
+#ifdef _WIN32
+#if _MSC_VER < 1400 /* not needed for Visual Studio 2008 */
+#define vsnprintf _vsnprintf
+#endif
+#endif
 
-//
-// M_ScreenShot
-//
-void M_ScreenShot (void)
+// Safe, portable vsnprintf().
+int M_vsnprintf(char *buf, size_t buf_len, const char *s, va_list args)
 {
-    int                i;
-    byte*      linear;
-    char       lbmname[12];
-    
-    // munge planar buffer to linear
-    linear = screens[2];
-    I_ReadScreen (linear);
-    
-    // find a file name to save it to
-    strcpy(lbmname,"DOOM00.pcx");
-               
-    for (i=0 ; i<=99 ; i++)
+    int result;
+
+    if (buf_len < 1)
     {
-       lbmname[4] = i/10 + '0';
-       lbmname[5] = i%10 + '0';
-       if (access(lbmname,0) == -1)
-           break;      // file doesn't exist
+        return 0;
     }
-    if (i==100)
-       I_Error ("M_ScreenShot: Couldn't create a PCX");
-    
-    // save the pcx file
-    WritePCXfile (lbmname, linear,
-                 SCREENWIDTH, SCREENHEIGHT,
-                 W_CacheLumpName ("PLAYPAL",PU_CACHE));
-       
-    players[consoleplayer].message = "screen shot";
+
+    // Windows (and other OSes?) has a vsnprintf() that doesn't always
+    // append a trailing \0. So we must do it, and write into a buffer
+    // that is one byte shorter; otherwise this function is unsafe.
+    result = vsnprintf(buf, buf_len, s, args);
+
+    // If truncated, change the final char in the buffer to a \0.
+    // A negative result indicates a truncated buffer on Windows.
+    if (result < 0 || result >= buf_len)
+    {
+        buf[buf_len - 1] = '\0';
+        result = buf_len - 1;
+    }
+
+    return result;
 }
 
+// Safe, portable snprintf().
+int M_snprintf(char *buf, size_t buf_len, const char *s, ...)
+{
+    va_list args;
+    int result;
+    va_start(args, s);
+    result = M_vsnprintf(buf, buf_len, s, args);
+    va_end(args);
+    return result;
+}
+
+#ifdef _WIN32
+
+char *M_OEMToUTF8(const char *oem)
+{
+    unsigned int len = strlen(oem) + 1;
+    wchar_t *tmp;
+    char *result;
+
+    tmp = malloc(len * sizeof(wchar_t));
+    MultiByteToWideChar(CP_OEMCP, 0, oem, len, tmp, len);
+    result = malloc(len * 4);
+    WideCharToMultiByte(CP_UTF8, 0, tmp, len, result, len * 4, NULL, NULL);
+    free(tmp);
+
+    return result;
+}
+
+#endif
 
index 82afb0f2517e7cc481d8e3915fda8a8ae52cf9cd..844b485951528a5e495045f0c19584a85fc75d19 100644 (file)
@@ -1,65 +1,51 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
-//
+//      Miscellaneous.
 //    
-//-----------------------------------------------------------------------------
 
 
 #ifndef __M_MISC__
 #define __M_MISC__
 
+#include <stdio.h>
+#include <stdarg.h>
 
 #include "doomtype.h"
-//
-// MISC
-//
-
-
-
-boolean
-M_WriteFile
-( char const*  name,
-  void*                source,
-  int          length );
-
-int
-M_ReadFile
-( char const*  name,
-  byte**       buffer );
-
-void M_ScreenShot (void);
-
-void M_LoadDefaults (void);
-
-void M_SaveDefaults (void);
-
-
-int
-M_DrawText
-( int          x,
-  int          y,
-  boolean      direct,
-  char*                string );
 
+boolean M_WriteFile(char *name, void *source, int length);
+int M_ReadFile(char *name, byte **buffer);
+void M_MakeDirectory(char *dir);
+char *M_TempFile(char *s);
+boolean M_FileExists(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);
+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);
+boolean M_StringConcat(char *dest, const char *src, size_t dest_size);
+char *M_StringReplace(const char *haystack, const char *needle,
+                      const char *replacement);
+char *M_StringJoin(const char *s, ...);
+boolean M_StringStartsWith(const char *s, const char *prefix);
+boolean M_StringEndsWith(const char *s, const char *suffix);
+int M_vsnprintf(char *buf, size_t buf_len, const char *s, va_list args);
+int M_snprintf(char *buf, size_t buf_len, const char *s, ...);
+char *M_OEMToUTF8(const char *ansi);
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
+
index 09f857d0b16def4d79048ad137528fd41b66d237..8e3b4e189e7eee53af9c1b9b3de4193dffe3ee9c 100644 (file)
@@ -1,34 +1,27 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Random number LUT.
 //
-//-----------------------------------------------------------------------------
-
-static const char rcsid[] = "$Id: m_random.c,v 1.1 1997/02/03 22:45:11 b1 Exp $";
-
 
 //
 // M_Random
 // Returns a 0-255 number
 //
-unsigned char rndtable[256] = {
+
+static const unsigned char rndtable[256] = {
     0,   8, 109, 220, 222, 241, 149, 107,  75, 248, 254, 140,  16,  66 ,
     74,  21, 211,  47,  80, 242, 154,  27, 205, 128, 161,  89,  77,  36 ,
     95, 110,  85,  48, 212, 140, 211, 249,  22,  79, 200,  50,  28, 188 ,
@@ -70,7 +63,3 @@ void M_ClearRandom (void)
 {
     rndindex = prndindex = 0;
 }
-
-
-
-
index 40b86d58410cc8ea934b088a31f6121784deaeda..aa6291ae9e4872a5f6a365cb7f68eeab2c8fb523 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //
 //    
-//-----------------------------------------------------------------------------
 
 
 #ifndef __M_RANDOM__
@@ -40,8 +37,3 @@ void M_ClearRandom (void);
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
diff --git a/frosted-doom/m_swap.c b/frosted-doom/m_swap.c
deleted file mode 100644 (file)
index 1db93c8..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
-//
-// $Id:$
-//
-// Copyright (C) 1993-1996 by id Software, Inc.
-//
-// This source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
-//
-// DESCRIPTION:
-//     Endianess handling, swapping 16bit and 32bit.
-//
-//-----------------------------------------------------------------------------
-
-static const char
-rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $";
-
-
-#ifdef __GNUG__
-#pragma implementation "m_swap.h"
-#endif
-#include "m_swap.h"
-
-
-// Not needed with big endian.
-#ifndef __BIG_ENDIAN__
-
-// Swap 16bit, that is, MSB and LSB byte.
-unsigned short SwapSHORT(unsigned short x)
-{
-    // No masking with 0xFF should be necessary. 
-    return (x>>8) | (x<<8);
-}
-
-// Swapping 32bit.
-unsigned long SwapLONG( unsigned long x)
-{
-    return
-       (x>>24)
-       | ((x>>8) & 0xff00)
-       | ((x<<8) & 0xff0000)
-       | (x<<24);
-}
-
-
-#endif
-
-
diff --git a/frosted-doom/m_swap.h b/frosted-doom/m_swap.h
deleted file mode 100644 (file)
index 86f6e0a..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
-//
-// $Id:$
-//
-// Copyright (C) 1993-1996 by id Software, Inc.
-//
-// This source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// DESCRIPTION:
-//     Endianess handling, swapping 16bit and 32bit.
-//
-//-----------------------------------------------------------------------------
-
-
-#ifndef __M_SWAP__
-#define __M_SWAP__
-
-
-#ifdef __GNUG__
-#pragma interface
-#endif
-
-
-// Endianess handling.
-// WAD files are stored little endian.
-#ifdef __BIG_ENDIAN__
-short  SwapSHORT(short);
-long   SwapLONG(long);
-#define SHORT(x)       ((short)SwapSHORT((unsigned short) (x)))
-#define LONG(x)         ((long)SwapLONG((unsigned long) (x)))
-#else
-#define SHORT(x)       (x)
-#define LONG(x)         (x)
-#endif
-
-
-
-
-#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
diff --git a/frosted-doom/memio.c b/frosted-doom/memio.c
new file mode 100644 (file)
index 0000000..3cc769a
--- /dev/null
@@ -0,0 +1,197 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// Emulates the IO functions in C stdio.h reading and writing to 
+// memory.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "memio.h"
+
+#include "z_zone.h"
+
+typedef enum {
+       MODE_READ,
+       MODE_WRITE,
+} memfile_mode_t;
+
+struct _MEMFILE {
+       unsigned char *buf;
+       size_t buflen;
+       size_t alloced;
+       unsigned int position;
+       memfile_mode_t mode;
+};
+
+// Open a memory area for reading
+
+MEMFILE *mem_fopen_read(void *buf, size_t buflen)
+{
+       MEMFILE *file;
+
+       file = Z_Malloc(sizeof(MEMFILE), PU_STATIC, 0);
+
+       file->buf = (unsigned char *) buf;
+       file->buflen = buflen;
+       file->position = 0;
+       file->mode = MODE_READ;
+
+       return file;
+}
+
+// Read bytes
+
+size_t mem_fread(void *buf, size_t size, size_t nmemb, MEMFILE *stream)
+{
+       size_t items;
+
+       if (stream->mode != MODE_READ)
+       {
+               printf("not a read stream\n");
+               return -1;
+       }
+
+       // Trying to read more bytes than we have left?
+       
+       items = nmemb;
+
+       if (items * size > stream->buflen - stream->position) 
+       {
+               items = (stream->buflen - stream->position) / size;
+       }
+       
+       // Copy bytes to buffer
+       
+       memcpy(buf, stream->buf + stream->position, items * size);
+
+       // Update position
+
+       stream->position += items * size;
+       
+       return items;
+}
+
+// Open a memory area for writing
+
+MEMFILE *mem_fopen_write(void)
+{
+       MEMFILE *file;
+
+       file = Z_Malloc(sizeof(MEMFILE), PU_STATIC, 0);
+
+       file->alloced = 1024;
+       file->buf = Z_Malloc(file->alloced, PU_STATIC, 0);
+       file->buflen = 0;
+       file->position = 0;
+       file->mode = MODE_WRITE;
+
+       return file;
+}
+
+// Write bytes to stream
+
+size_t mem_fwrite(const void *ptr, size_t size, size_t nmemb, MEMFILE *stream)
+{
+       size_t bytes;
+
+       if (stream->mode != MODE_WRITE)
+       {
+               return -1;
+       }
+       
+       // More bytes than can fit in the buffer?
+       // If so, reallocate bigger.
+
+       bytes = size * nmemb;
+       
+       while (bytes > stream->alloced - stream->position)
+       {
+               unsigned char *newbuf;
+
+               newbuf = Z_Malloc(stream->alloced * 2, PU_STATIC, 0);
+               memcpy(newbuf, stream->buf, stream->alloced);
+               Z_Free(stream->buf);
+               stream->buf = newbuf;
+               stream->alloced *= 2;
+       }
+
+       // Copy into buffer
+       
+       memcpy(stream->buf + stream->position, ptr, bytes);
+       stream->position += bytes;
+
+       if (stream->position > stream->buflen)
+               stream->buflen = stream->position;
+
+       return nmemb;
+}
+
+void mem_get_buf(MEMFILE *stream, void **buf, size_t *buflen)
+{
+       *buf = stream->buf;
+       *buflen = stream->buflen;
+}
+
+void mem_fclose(MEMFILE *stream)
+{
+       if (stream->mode == MODE_WRITE)
+       {
+               Z_Free(stream->buf);
+       }
+
+       Z_Free(stream);
+}
+
+long mem_ftell(MEMFILE *stream)
+{
+       return stream->position;
+}
+
+int mem_fseek(MEMFILE *stream, signed long position, mem_rel_t whence)
+{
+       unsigned int newpos;
+
+       switch (whence)
+       {
+               case MEM_SEEK_SET:
+                       newpos = (int) position;
+                       break;
+
+               case MEM_SEEK_CUR:
+                       newpos = (int) (stream->position + position);
+                       break;
+                       
+               case MEM_SEEK_END:
+                       newpos = (int) (stream->buflen + position);
+                       break;
+               default:
+                       return -1;
+       }
+
+       if (newpos < stream->buflen)
+       {
+               stream->position = newpos;
+               return 0;
+       }
+       else
+       {
+               printf("Error seeking to %i\n", newpos);
+               return -1;
+       }
+}
+
+
diff --git a/frosted-doom/memio.h b/frosted-doom/memio.h
new file mode 100644 (file)
index 0000000..03706a3
--- /dev/null
@@ -0,0 +1,38 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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 MEMIO_H
+#define MEMIO_H
+
+typedef struct _MEMFILE MEMFILE;
+
+typedef enum 
+{
+       MEM_SEEK_SET,
+       MEM_SEEK_CUR,
+       MEM_SEEK_END,
+} mem_rel_t;
+
+MEMFILE *mem_fopen_read(void *buf, size_t buflen);
+size_t mem_fread(void *buf, size_t size, size_t nmemb, MEMFILE *stream);
+MEMFILE *mem_fopen_write(void);
+size_t mem_fwrite(const void *ptr, size_t size, size_t nmemb, MEMFILE *stream);
+void mem_get_buf(MEMFILE *stream, void **buf, size_t *buflen);
+void mem_fclose(MEMFILE *stream);
+long mem_ftell(MEMFILE *stream);
+int mem_fseek(MEMFILE *stream, signed long offset, mem_rel_t whence);
+
+#endif /* #ifndef MEMIO_H */
+         
diff --git a/frosted-doom/net_client.h b/frosted-doom/net_client.h
new file mode 100644 (file)
index 0000000..31dc9e4
--- /dev/null
@@ -0,0 +1,52 @@
+//
+// 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.
+//
+// Network client code
+//
+
+#ifndef NET_CLIENT_H
+#define NET_CLIENT_H
+
+#include "doomtype.h"
+#include "d_ticcmd.h"
+#include "sha1.h"
+#include "net_defs.h"
+
+boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data);
+void NET_CL_Disconnect(void);
+void NET_CL_Run(void);
+void NET_CL_Init(void);
+void NET_CL_LaunchGame(void);
+void NET_CL_StartGame(net_gamesettings_t *settings);
+void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic);
+boolean NET_CL_GetSettings(net_gamesettings_t *_settings);
+void NET_Init(void);
+
+void NET_BindVariables(void);
+
+extern boolean net_client_connected;
+extern boolean net_client_received_wait_data;
+extern net_waitdata_t net_client_wait_data;
+extern boolean net_waiting_for_launch;
+extern char *net_player_name;
+
+extern sha1_digest_t net_server_wad_sha1sum;
+extern sha1_digest_t net_server_deh_sha1sum;
+extern unsigned int net_server_is_freedoom;
+extern sha1_digest_t net_local_wad_sha1sum;
+extern sha1_digest_t net_local_deh_sha1sum;
+extern unsigned int net_local_is_freedoom;
+
+extern boolean drone;
+
+#endif /* #ifndef NET_CLIENT_H */
diff --git a/frosted-doom/net_dedicated.h b/frosted-doom/net_dedicated.h
new file mode 100644 (file)
index 0000000..3d7387b
--- /dev/null
@@ -0,0 +1,25 @@
+//
+// 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.
+//
+//
+// Dedicated server code.
+// 
+
+#ifndef NET_DEDICATED_H
+#define NET_DEDICATED_H
+
+void NET_DedicatedServer(void);
+
+#endif /* #ifndef NET_DEDICATED_H */
+
+
diff --git a/frosted-doom/net_defs.h b/frosted-doom/net_defs.h
new file mode 100644 (file)
index 0000000..bedfb95
--- /dev/null
@@ -0,0 +1,248 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//     Definitions for use in networking code.
+//
+
+#ifndef NET_DEFS_H
+#define NET_DEFS_H 
+
+#include <stdio.h>
+
+#include "doomtype.h"
+#include "d_ticcmd.h"
+#include "sha1.h"
+
+// Absolute maximum number of "nodes" in the game.  This is different to
+// NET_MAXPLAYERS, as there may be observers that are not participating
+// (eg. left/right monitors)
+
+#define MAXNETNODES 16
+
+// The maximum number of players, multiplayer/networking.
+// This is the maximum supported by the networking code; individual games
+// have their own values for MAXPLAYERS that can be smaller.
+
+#define NET_MAXPLAYERS 8
+
+// Maximum length of a player's name.
+
+#define MAXPLAYERNAME 30
+
+// Networking and tick handling related.
+
+#define BACKUPTICS 128
+
+typedef struct _net_module_s net_module_t;
+typedef struct _net_packet_s net_packet_t;
+typedef struct _net_addr_s net_addr_t;
+typedef struct _net_context_s net_context_t;
+
+struct _net_packet_s
+{
+    byte *data;
+    size_t len;
+    size_t alloced;
+    unsigned int pos;
+};
+
+struct _net_module_s
+{
+    // Initialize this module for use as a client
+
+    boolean (*InitClient)(void);
+
+    // Initialize this module for use as a server
+
+    boolean (*InitServer)(void);
+
+    // Send a packet
+
+    void (*SendPacket)(net_addr_t *addr, net_packet_t *packet);
+
+    // Check for new packets to receive
+    //
+    // Returns true if packet received
+
+    boolean (*RecvPacket)(net_addr_t **addr, net_packet_t **packet);
+
+    // Converts an address to a string
+
+    void (*AddrToString)(net_addr_t *addr, char *buffer, int buffer_len);
+
+    // Free back an address when no longer in use
+
+    void (*FreeAddress)(net_addr_t *addr);
+
+    // Try to resolve a name to an address
+
+    net_addr_t *(*ResolveAddress)(char *addr);
+};
+
+// net_addr_t
+
+struct _net_addr_s
+{
+    net_module_t *module;
+    void *handle;
+};
+
+// magic number sent when connecting to check this is a valid client
+
+#define NET_MAGIC_NUMBER 3436803284U
+
+// header field value indicating that the packet is a reliable packet
+
+#define NET_RELIABLE_PACKET (1 << 15)
+
+// packet types
+
+typedef enum
+{
+    NET_PACKET_TYPE_SYN,
+    NET_PACKET_TYPE_ACK,
+    NET_PACKET_TYPE_REJECTED,
+    NET_PACKET_TYPE_KEEPALIVE,
+    NET_PACKET_TYPE_WAITING_DATA,
+    NET_PACKET_TYPE_GAMESTART,
+    NET_PACKET_TYPE_GAMEDATA,
+    NET_PACKET_TYPE_GAMEDATA_ACK,
+    NET_PACKET_TYPE_DISCONNECT,
+    NET_PACKET_TYPE_DISCONNECT_ACK,
+    NET_PACKET_TYPE_RELIABLE_ACK,
+    NET_PACKET_TYPE_GAMEDATA_RESEND,
+    NET_PACKET_TYPE_CONSOLE_MESSAGE,
+    NET_PACKET_TYPE_QUERY,
+    NET_PACKET_TYPE_QUERY_RESPONSE,
+    NET_PACKET_TYPE_LAUNCH,
+} net_packet_type_t;
+
+typedef enum
+{
+    NET_MASTER_PACKET_TYPE_ADD,
+    NET_MASTER_PACKET_TYPE_ADD_RESPONSE,
+    NET_MASTER_PACKET_TYPE_QUERY,
+    NET_MASTER_PACKET_TYPE_QUERY_RESPONSE,
+    NET_MASTER_PACKET_TYPE_GET_METADATA,
+    NET_MASTER_PACKET_TYPE_GET_METADATA_RESPONSE,
+    NET_MASTER_PACKET_TYPE_SIGN_START,
+    NET_MASTER_PACKET_TYPE_SIGN_START_RESPONSE,
+    NET_MASTER_PACKET_TYPE_SIGN_END,
+    NET_MASTER_PACKET_TYPE_SIGN_END_RESPONSE,
+} net_master_packet_type_t;
+
+// Settings specified when the client connects to the server.
+
+typedef struct
+{
+    int gamemode;
+    int gamemission;
+    int lowres_turn;
+    int drone;
+    int max_players;
+    int is_freedoom;
+    sha1_digest_t wad_sha1sum;
+    sha1_digest_t deh_sha1sum;
+    int player_class;
+} net_connect_data_t;
+
+// Game settings sent by client to server when initiating game start,
+// and received from the server by clients when the game starts.
+
+typedef struct
+{
+    int ticdup;
+    int extratics;
+    int deathmatch;
+    int episode;
+    int nomonsters;
+    int fast_monsters;
+    int respawn_monsters;
+    int map;
+    int skill;
+    int gameversion;
+    int lowres_turn;
+    int new_sync;
+    int timelimit;
+    int loadgame;
+    int random;  // [Strife only]
+
+    // These fields are only used by the server when sending a game
+    // start message:
+
+    int num_players;
+    int consoleplayer;
+
+    // Hexen player classes:
+
+    int player_classes[NET_MAXPLAYERS];
+
+} net_gamesettings_t;
+
+#define NET_TICDIFF_FORWARD      (1 << 0)
+#define NET_TICDIFF_SIDE         (1 << 1)
+#define NET_TICDIFF_TURN         (1 << 2)
+#define NET_TICDIFF_BUTTONS      (1 << 3)
+#define NET_TICDIFF_CONSISTANCY  (1 << 4)
+#define NET_TICDIFF_CHATCHAR     (1 << 5)
+#define NET_TICDIFF_RAVEN        (1 << 6)
+#define NET_TICDIFF_STRIFE       (1 << 7)
+
+typedef struct
+{
+    unsigned int diff;
+    ticcmd_t cmd;
+} net_ticdiff_t;
+
+// Complete set of ticcmds from all players
+
+typedef struct 
+{
+    signed int latency;
+    unsigned int seq;
+    boolean playeringame[NET_MAXPLAYERS];
+    net_ticdiff_t cmds[NET_MAXPLAYERS];
+} net_full_ticcmd_t;
+
+// Data sent in response to server queries
+
+typedef struct
+{
+    char *version;
+    int server_state;
+    int num_players;
+    int max_players;
+    int gamemode;
+    int gamemission;
+    char *description;
+} net_querydata_t;
+
+// Data sent by the server while waiting for the game to start.
+
+typedef struct
+{
+    int num_players;
+    int num_drones;
+    int ready_players;
+    int max_players;
+    int is_controller;
+    int consoleplayer;
+    char player_names[NET_MAXPLAYERS][MAXPLAYERNAME];
+    char player_addrs[NET_MAXPLAYERS][MAXPLAYERNAME];
+    sha1_digest_t wad_sha1sum;
+    sha1_digest_t deh_sha1sum;
+    int is_freedoom;
+} net_waitdata_t;
+
+#endif /* #ifndef NET_DEFS_H */
diff --git a/frosted-doom/net_gui.h b/frosted-doom/net_gui.h
new file mode 100644 (file)
index 0000000..4f4198b
--- /dev/null
@@ -0,0 +1,29 @@
+//
+// 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.
+//
+// Graphical stuff related to the networking code:
+//
+//  * The client waiting screen when we are waiting for the server to
+//    start the game.
+//
+
+
+#ifndef NET_GUI_H
+#define NET_GUI_H
+
+#include "doomtype.h"
+
+extern void NET_WaitForLaunch(void);
+
+#endif /* #ifndef NET_GUI_H */
+
diff --git a/frosted-doom/net_io.h b/frosted-doom/net_io.h
new file mode 100644 (file)
index 0000000..5350222
--- /dev/null
@@ -0,0 +1,36 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//      Network packet manipulation (net_packet_t)
+//
+
+#ifndef NET_IO_H
+#define NET_IO_H
+
+#include "net_defs.h"
+
+extern net_addr_t net_broadcast_addr;
+
+net_context_t *NET_NewContext(void);
+void NET_AddModule(net_context_t *context, net_module_t *module);
+void NET_SendPacket(net_addr_t *addr, net_packet_t *packet);
+void NET_SendBroadcast(net_context_t *context, net_packet_t *packet);
+boolean NET_RecvPacket(net_context_t *context, net_addr_t **addr, 
+                       net_packet_t **packet);
+char *NET_AddrToString(net_addr_t *addr);
+void NET_FreeAddress(net_addr_t *addr);
+net_addr_t *NET_ResolveAddress(net_context_t *context, char *address);
+
+#endif  /* #ifndef NET_IO_H */
+
diff --git a/frosted-doom/net_loop.h b/frosted-doom/net_loop.h
new file mode 100644 (file)
index 0000000..5a2e58e
--- /dev/null
@@ -0,0 +1,27 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//      Loopback network module for server compiled into the client
+//
+
+#ifndef NET_LOOP_H
+#define NET_LOOP_H
+
+#include "net_defs.h"
+
+extern net_module_t net_loop_client_module;
+extern net_module_t net_loop_server_module;
+
+#endif /* #ifndef NET_LOOP_H */
+
diff --git a/frosted-doom/net_packet.h b/frosted-doom/net_packet.h
new file mode 100644 (file)
index 0000000..ced4e43
--- /dev/null
@@ -0,0 +1,44 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//     Definitions for use in networking code.
+//
+
+#ifndef NET_PACKET_H
+#define NET_PACKET_H
+
+#include "net_defs.h"
+
+net_packet_t *NET_NewPacket(int initial_size);
+net_packet_t *NET_PacketDup(net_packet_t *packet);
+void NET_FreePacket(net_packet_t *packet);
+
+boolean NET_ReadInt8(net_packet_t *packet, unsigned int *data);
+boolean NET_ReadInt16(net_packet_t *packet, unsigned int *data);
+boolean NET_ReadInt32(net_packet_t *packet, unsigned int *data);
+
+boolean NET_ReadSInt8(net_packet_t *packet, signed int *data);
+boolean NET_ReadSInt16(net_packet_t *packet, signed int *data);
+boolean NET_ReadSInt32(net_packet_t *packet, signed int *data);
+
+char *NET_ReadString(net_packet_t *packet);
+
+void NET_WriteInt8(net_packet_t *packet, unsigned int i);
+void NET_WriteInt16(net_packet_t *packet, unsigned int i);
+void NET_WriteInt32(net_packet_t *packet, unsigned int i);
+
+void NET_WriteString(net_packet_t *packet, char *string);
+
+#endif /* #ifndef NET_PACKET_H */
+
diff --git a/frosted-doom/net_query.h b/frosted-doom/net_query.h
new file mode 100644 (file)
index 0000000..563a055
--- /dev/null
@@ -0,0 +1,44 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//     Querying servers to find their current status.
+//
+
+#ifndef NET_QUERY_H
+#define NET_QUERY_H
+
+#include "net_defs.h"
+
+typedef void (*net_query_callback_t)(net_addr_t *addr,
+                                     net_querydata_t *querydata,
+                                     unsigned int ping_time,
+                                     void *user_data);
+
+extern int NET_StartLANQuery(void);
+extern int NET_StartMasterQuery(void);
+
+extern void NET_LANQuery(void);
+extern void NET_MasterQuery(void);
+extern void NET_QueryAddress(char *addr);
+extern net_addr_t *NET_FindLANServer(void);
+
+extern int NET_Query_Poll(net_query_callback_t callback, void *user_data);
+
+extern net_addr_t *NET_Query_ResolveMaster(net_context_t *context);
+extern void NET_Query_AddToMaster(net_addr_t *master_addr);
+extern boolean NET_Query_CheckAddedToMaster(boolean *result);
+extern void NET_Query_MasterResponse(net_packet_t *packet);
+
+#endif /* #ifndef NET_QUERY_H */
+
diff --git a/frosted-doom/net_sdl.h b/frosted-doom/net_sdl.h
new file mode 100644 (file)
index 0000000..c249de1
--- /dev/null
@@ -0,0 +1,26 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//     Networking module which uses SDL_net
+//
+
+#ifndef NET_SDL_H
+#define NET_SDL_H
+
+#include "net_defs.h"
+
+extern net_module_t net_sdl_module;
+
+#endif /* #ifndef NET_SDL_H */
+
diff --git a/frosted-doom/net_server.h b/frosted-doom/net_server.h
new file mode 100644 (file)
index 0000000..b9de745
--- /dev/null
@@ -0,0 +1,42 @@
+//
+// 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.
+//
+// Network server code
+//
+
+#ifndef NET_SERVER_H
+#define NET_SERVER_H
+
+// initialize server and wait for connections
+
+void NET_SV_Init(void);
+
+// run server: check for new packets received etc.
+
+void NET_SV_Run(void);
+
+// Shut down the server
+// Blocks until all clients disconnect, or until a 5 second timeout
+
+void NET_SV_Shutdown(void);
+
+// Add a network module to the context used by the server
+
+void NET_SV_AddModule(net_module_t *module);
+
+// Register server with master server.
+
+void NET_SV_RegisterWithMaster(void);
+
+#endif /* #ifndef NET_SERVER_H */
+
index 680990245eaf27fc2de64f70ecc3478c0cc0ec5a..d1e61c898b40e9a0be05dbe71d591f0297b0d1a1 100644 (file)
@@ -1,27 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:  Ceiling aninmation (lowering, crushing, raising)
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: p_ceilng.c,v 1.4 1997/02/03 16:47:53 b1 Exp $";
 
 
 #include "z_zone.h"
@@ -72,8 +65,7 @@ void T_MoveCeiling (ceiling_t* ceiling)
              case silentCrushAndRaise:
                break;
              default:
-               S_StartSound((mobj_t *)&ceiling->sector->soundorg,
-                            sfx_stnmov);
+               S_StartSound(&ceiling->sector->soundorg, sfx_stnmov);
                // ?
                break;
            }
@@ -88,8 +80,7 @@ void T_MoveCeiling (ceiling_t* ceiling)
                break;
                
              case silentCrushAndRaise:
-               S_StartSound((mobj_t *)&ceiling->sector->soundorg,
-                            sfx_pstop);
+               S_StartSound(&ceiling->sector->soundorg, sfx_pstop);
              case fastCrushAndRaise:
              case crushAndRaise:
                ceiling->direction = -1;
@@ -115,8 +106,7 @@ void T_MoveCeiling (ceiling_t* ceiling)
            {
              case silentCrushAndRaise: break;
              default:
-               S_StartSound((mobj_t *)&ceiling->sector->soundorg,
-                            sfx_stnmov);
+               S_StartSound(&ceiling->sector->soundorg, sfx_stnmov);
            }
        }
        
@@ -125,8 +115,7 @@ void T_MoveCeiling (ceiling_t* ceiling)
            switch(ceiling->type)
            {
              case silentCrushAndRaise:
-               S_StartSound((mobj_t *)&ceiling->sector->soundorg,
-                            sfx_pstop);
+               S_StartSound(&ceiling->sector->soundorg, sfx_pstop);
              case crushAndRaise:
                ceiling->speed = CEILSPEED;
              case fastCrushAndRaise:
index 2e0442eb4ef3fbd76b9c932bb65d41b9d1b14835..cafab0f4378c6fd4d5f4e412569a6b8cf4621763 100644 (file)
@@ -1,31 +1,25 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION: Door animation code (opening/closing)
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: p_doors.c,v 1.4 1997/02/03 16:47:53 b1 Exp $";
 
 
 #include "z_zone.h"
 #include "doomdef.h"
+#include "deh_main.h"
 #include "p_local.h"
 
 #include "s_sound.h"
@@ -72,22 +66,19 @@ void T_VerticalDoor (vldoor_t* door)
        {
            switch(door->type)
            {
-             case blazeRaise:
+             case vld_blazeRaise:
                door->direction = -1; // time to go back down
-               S_StartSound((mobj_t *)&door->sector->soundorg,
-                            sfx_bdcls);
+               S_StartSound(&door->sector->soundorg, sfx_bdcls);
                break;
                
-             case normal:
+             case vld_normal:
                door->direction = -1; // time to go back down
-               S_StartSound((mobj_t *)&door->sector->soundorg,
-                            sfx_dorcls);
+               S_StartSound(&door->sector->soundorg, sfx_dorcls);
                break;
                
-             case close30ThenOpen:
+             case vld_close30ThenOpen:
                door->direction = 1;
-               S_StartSound((mobj_t *)&door->sector->soundorg,
-                            sfx_doropn);
+               S_StartSound(&door->sector->soundorg, sfx_doropn);
                break;
                
              default:
@@ -102,11 +93,10 @@ void T_VerticalDoor (vldoor_t* door)
        {
            switch(door->type)
            {
-             case raiseIn5Mins:
+             case vld_raiseIn5Mins:
                door->direction = 1;
-               door->type = normal;
-               S_StartSound((mobj_t *)&door->sector->soundorg,
-                            sfx_doropn);
+               door->type = vld_normal;
+               S_StartSound(&door->sector->soundorg, sfx_doropn);
                break;
                
              default:
@@ -125,23 +115,22 @@ void T_VerticalDoor (vldoor_t* door)
        {
            switch(door->type)
            {
-             case blazeRaise:
-             case blazeClose:
+             case vld_blazeRaise:
+             case vld_blazeClose:
                door->sector->specialdata = NULL;
                P_RemoveThinker (&door->thinker);  // unlink and free
-               S_StartSound((mobj_t *)&door->sector->soundorg,
-                            sfx_bdcls);
+               S_StartSound(&door->sector->soundorg, sfx_bdcls);
                break;
                
-             case normal:
-             case close:
+             case vld_normal:
+             case vld_close:
                door->sector->specialdata = NULL;
                P_RemoveThinker (&door->thinker);  // unlink and free
                break;
                
-             case close30ThenOpen:
+             case vld_close30ThenOpen:
                door->direction = 0;
-               door->topcountdown = 35*30;
+               door->topcountdown = TICRATE*30;
                break;
                
              default:
@@ -152,14 +141,13 @@ void T_VerticalDoor (vldoor_t* door)
        {
            switch(door->type)
            {
-             case blazeClose:
-             case close:               // DO NOT GO BACK UP!
+             case vld_blazeClose:
+             case vld_close:           // DO NOT GO BACK UP!
                break;
                
              default:
                door->direction = 1;
-               S_StartSound((mobj_t *)&door->sector->soundorg,
-                            sfx_doropn);
+               S_StartSound(&door->sector->soundorg, sfx_doropn);
                break;
            }
        }
@@ -176,15 +164,15 @@ void T_VerticalDoor (vldoor_t* door)
        {
            switch(door->type)
            {
-             case blazeRaise:
-             case normal:
+             case vld_blazeRaise:
+             case vld_normal:
                door->direction = 0; // wait at top
                door->topcountdown = door->topwait;
                break;
                
-             case close30ThenOpen:
-             case blazeOpen:
-             case open:
+             case vld_close30ThenOpen:
+             case vld_blazeOpen:
+             case vld_open:
                door->sector->specialdata = NULL;
                P_RemoveThinker (&door->thinker);  // unlink and free
                break;
@@ -224,7 +212,7 @@ EV_DoLockedDoor
            return 0;
        if (!p->cards[it_bluecard] && !p->cards[it_blueskull])
        {
-           p->message = PD_BLUEO;
+           p->message = DEH_String(PD_BLUEO);
            S_StartSound(NULL,sfx_oof);
            return 0;
        }
@@ -236,7 +224,7 @@ EV_DoLockedDoor
            return 0;
        if (!p->cards[it_redcard] && !p->cards[it_redskull])
        {
-           p->message = PD_REDO;
+           p->message = DEH_String(PD_REDO);
            S_StartSound(NULL,sfx_oof);
            return 0;
        }
@@ -249,7 +237,7 @@ EV_DoLockedDoor
        if (!p->cards[it_yellowcard] &&
            !p->cards[it_yellowskull])
        {
-           p->message = PD_YELLOWO;
+           p->message = DEH_String(PD_YELLOWO);
            S_StartSound(NULL,sfx_oof);
            return 0;
        }
@@ -293,49 +281,44 @@ EV_DoDoor
                
        switch(type)
        {
-         case blazeClose:
+         case vld_blazeClose:
            door->topheight = P_FindLowestCeilingSurrounding(sec);
            door->topheight -= 4*FRACUNIT;
            door->direction = -1;
            door->speed = VDOORSPEED * 4;
-           S_StartSound((mobj_t *)&door->sector->soundorg,
-                        sfx_bdcls);
+           S_StartSound(&door->sector->soundorg, sfx_bdcls);
            break;
            
-         case close:
+         case vld_close:
            door->topheight = P_FindLowestCeilingSurrounding(sec);
            door->topheight -= 4*FRACUNIT;
            door->direction = -1;
-           S_StartSound((mobj_t *)&door->sector->soundorg,
-                        sfx_dorcls);
+           S_StartSound(&door->sector->soundorg, sfx_dorcls);
            break;
            
-         case close30ThenOpen:
+         case vld_close30ThenOpen:
            door->topheight = sec->ceilingheight;
            door->direction = -1;
-           S_StartSound((mobj_t *)&door->sector->soundorg,
-                        sfx_dorcls);
+           S_StartSound(&door->sector->soundorg, sfx_dorcls);
            break;
            
-         case blazeRaise:
-         case blazeOpen:
+         case vld_blazeRaise:
+         case vld_blazeOpen:
            door->direction = 1;
            door->topheight = P_FindLowestCeilingSurrounding(sec);
            door->topheight -= 4*FRACUNIT;
            door->speed = VDOORSPEED * 4;
            if (door->topheight != sec->ceilingheight)
-               S_StartSound((mobj_t *)&door->sector->soundorg,
-                            sfx_bdopn);
+               S_StartSound(&door->sector->soundorg, sfx_bdopn);
            break;
            
-         case normal:
-         case open:
+         case vld_normal:
+         case vld_open:
            door->direction = 1;
            door->topheight = P_FindLowestCeilingSurrounding(sec);
            door->topheight -= 4*FRACUNIT;
            if (door->topheight != sec->ceilingheight)
-               S_StartSound((mobj_t *)&door->sector->soundorg,
-                            sfx_doropn);
+               S_StartSound(&door->sector->soundorg, sfx_doropn);
            break;
            
          default:
@@ -356,7 +339,6 @@ EV_VerticalDoor
   mobj_t*      thing )
 {
     player_t*  player;
-    //int              secnum;
     sector_t*  sec;
     vldoor_t*  door;
     int                side;
@@ -375,7 +357,7 @@ EV_VerticalDoor
        
        if (!player->cards[it_bluecard] && !player->cards[it_blueskull])
        {
-           player->message = PD_BLUEK;
+           player->message = DEH_String(PD_BLUEK);
            S_StartSound(NULL,sfx_oof);
            return;
        }
@@ -389,7 +371,7 @@ EV_VerticalDoor
        if (!player->cards[it_yellowcard] &&
            !player->cards[it_yellowskull])
        {
-           player->message = PD_YELLOWK;
+           player->message = DEH_String(PD_YELLOWK);
            S_StartSound(NULL,sfx_oof);
            return;
        }
@@ -402,7 +384,7 @@ EV_VerticalDoor
        
        if (!player->cards[it_redcard] && !player->cards[it_redskull])
        {
-           player->message = PD_REDK;
+           player->message = DEH_String(PD_REDK);
            S_StartSound(NULL,sfx_oof);
            return;
        }
@@ -411,7 +393,6 @@ EV_VerticalDoor
        
     // if the sector has an active thinker, use it
     sec = sides[ line->sidenum[side^1]] .sector;
-    //secnum = sec-sectors;
 
     if (sec->specialdata)
     {
@@ -429,8 +410,41 @@ EV_VerticalDoor
            {
                if (!thing->player)
                    return;             // JDC: bad guys never close doors
-               
-               door->direction = -1;   // start going down immediately
+
+                // When is a door not a door?
+                // In Vanilla, door->direction is set, even though
+                // "specialdata" might not actually point at a door.
+
+                if (door->thinker.function.acp1 == (actionf_p1) T_VerticalDoor)
+                {
+                    door->direction = -1;      // start going down immediately
+                }
+                else if (door->thinker.function.acp1 == (actionf_p1) T_PlatRaise)
+                {
+                    // Erm, this is a plat, not a door.
+                    // This notably causes a problem in ep1-0500.lmp where
+                    // a plat and a door are cross-referenced; the door
+                    // doesn't open on 64-bit.
+                    // The direction field in vldoor_t corresponds to the wait
+                    // field in plat_t.  Let's set that to -1 instead.
+
+                    plat_t *plat;
+
+                    plat = (plat_t *) door;
+                    plat->wait = -1;
+                }
+                else
+                {
+                    // This isn't a door OR a plat.  Now we're in trouble.
+
+                    fprintf(stderr, "EV_VerticalDoor: Tried to close "
+                                    "something that wasn't a door.\n");
+
+                    // Try closing it anyway. At least it will work on 32-bit
+                    // machines.
+
+                    door->direction = -1;
+                }
            }
            return;
        }
@@ -441,16 +455,16 @@ EV_VerticalDoor
     {
       case 117:        // BLAZING DOOR RAISE
       case 118:        // BLAZING DOOR OPEN
-       S_StartSound((mobj_t *)&sec->soundorg,sfx_bdopn);
+       S_StartSound(&sec->soundorg,sfx_bdopn);
        break;
        
       case 1:  // NORMAL DOOR SOUND
       case 31:
-       S_StartSound((mobj_t *)&sec->soundorg,sfx_doropn);
+       S_StartSound(&sec->soundorg,sfx_doropn);
        break;
        
       default: // LOCKED DOOR SOUND
-       S_StartSound((mobj_t *)&sec->soundorg,sfx_doropn);
+       S_StartSound(&sec->soundorg,sfx_doropn);
        break;
     }
        
@@ -471,23 +485,23 @@ EV_VerticalDoor
       case 26:
       case 27:
       case 28:
-       door->type = normal;
+       door->type = vld_normal;
        break;
        
       case 31:
       case 32:
       case 33:
       case 34:
-       door->type = open;
+       door->type = vld_open;
        line->special = 0;
        break;
        
       case 117:        // blazing door raise
-       door->type = blazeRaise;
+       door->type = vld_blazeRaise;
        door->speed = VDOORSPEED*4;
        break;
       case 118:        // blazing door open
-       door->type = blazeOpen;
+       door->type = vld_blazeOpen;
        line->special = 0;
        door->speed = VDOORSPEED*4;
        break;
@@ -516,9 +530,9 @@ void P_SpawnDoorCloseIn30 (sector_t* sec)
     door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
     door->sector = sec;
     door->direction = 0;
-    door->type = normal;
+    door->type = vld_normal;
     door->speed = VDOORSPEED;
-    door->topcountdown = 30 * 35;
+    door->topcountdown = 30 * TICRATE;
 }
 
 //
@@ -541,12 +555,12 @@ P_SpawnDoorRaiseIn5Mins
     door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
     door->sector = sec;
     door->direction = 2;
-    door->type = raiseIn5Mins;
+    door->type = vld_raiseIn5Mins;
     door->speed = VDOORSPEED;
     door->topheight = P_FindLowestCeilingSurrounding(sec);
     door->topheight -= 4*FRACUNIT;
     door->topwait = VDOORWAIT;
-    door->topcountdown = 5 * 60 * 35;
+    door->topcountdown = 5 * 60 * TICRATE;
 }
 
 
index 6d0175ae93b8f3848c83bd826a83d045c470dd04..f2b44d139ff8b0275a8874e6b996dfa28c38ae8a 100644 (file)
@@ -1,31 +1,24 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Enemy thinking, AI.
 //     Action Pointer Functions
 //     that are associated with states/frames. 
 //
-//-----------------------------------------------------------------------------
-
-static const char
-rcsid[] = "$Id: p_enemy.c,v 1.5 1997/02/03 22:45:11 b1 Exp $";
 
+#include <stdio.h>
 #include <stdlib.h>
 
 #include "m_random.h"
@@ -264,11 +257,6 @@ boolean P_CheckMissileRange (mobj_t* actor)
 fixed_t        xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
 fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
 
-#define MAXSPECIALCROSS        8
-
-extern line_t* spechit[MAXSPECIALCROSS];
-extern int     numspechit;
-
 boolean P_Move (mobj_t*        actor)
 {
     fixed_t    tryx;
@@ -400,7 +388,7 @@ void P_NewChaseDir (mobj_t* actor)
        && d[2] != DI_NODIR)
     {
        actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
-       if (actor->movedir != turnaround && P_TryWalk(actor))
+       if (actor->movedir != (int) turnaround && P_TryWalk(actor))
            return;
     }
 
@@ -453,7 +441,7 @@ void P_NewChaseDir (mobj_t* actor)
              tdir<=DI_SOUTHEAST;
              tdir++ )
        {
-           if (tdir!=turnaround)
+           if (tdir != (int) turnaround)
            {
                actor->movedir =tdir;
                
@@ -468,9 +456,9 @@ void P_NewChaseDir (mobj_t* actor)
              tdir != (DI_EAST-1);
              tdir-- )
        {
-           if (tdir!=turnaround)
+           if (tdir != (int) turnaround)
            {
-               actor->movedir =tdir;
+               actor->movedir = tdir;
                
                if ( P_TryWalk(actor) )
                    return;
@@ -503,12 +491,9 @@ P_LookForPlayers
     int                c;
     int                stop;
     player_t*  player;
-    //sector_t*        sector;
     angle_t    an;
     fixed_t    dist;
-               
-    //sector = actor->subsector->sector;
-       
+
     c = 0;
     stop = (actor->lastlook-1)&3;
        
@@ -589,7 +574,7 @@ void A_KeenDie (mobj_t* mo)
     }
 
     junk.tag = 666;
-    EV_DoDoor(&junk,open);
+    EV_DoDoor(&junk, vld_open);
 }
 
 
@@ -1257,14 +1242,17 @@ void A_FireCrackle (mobj_t* actor)
 void A_Fire (mobj_t* actor)
 {
     mobj_t*    dest;
+    mobj_t*     target;
     unsigned   an;
                
     dest = actor->tracer;
     if (!dest)
        return;
+
+    target = P_SubstNullMobj(actor->target);
                
     // don't move it if the vile lost sight
-    if (!P_CheckSight (actor->target, dest) )
+    if (!P_CheckSight (target, dest) )
        return;
 
     an = dest->angle >> ANGLETOFINESHIFT;
@@ -1358,14 +1346,17 @@ void A_FatRaise (mobj_t *actor)
 void A_FatAttack1 (mobj_t* actor)
 {
     mobj_t*    mo;
+    mobj_t*     target;
     int                an;
-       
+
     A_FaceTarget (actor);
+
     // Change direction  to ...
     actor->angle += FATSPREAD;
-    P_SpawnMissile (actor, actor->target, MT_FATSHOT);
+    target = P_SubstNullMobj(actor->target);
+    P_SpawnMissile (actor, target, MT_FATSHOT);
 
-    mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
+    mo = P_SpawnMissile (actor, target, MT_FATSHOT);
     mo->angle += FATSPREAD;
     an = mo->angle >> ANGLETOFINESHIFT;
     mo->momx = FixedMul (mo->info->speed, finecosine[an]);
@@ -1375,14 +1366,16 @@ void A_FatAttack1 (mobj_t* actor)
 void A_FatAttack2 (mobj_t* actor)
 {
     mobj_t*    mo;
+    mobj_t*     target;
     int                an;
 
     A_FaceTarget (actor);
     // Now here choose opposite deviation.
     actor->angle -= FATSPREAD;
-    P_SpawnMissile (actor, actor->target, MT_FATSHOT);
+    target = P_SubstNullMobj(actor->target);
+    P_SpawnMissile (actor, target, MT_FATSHOT);
 
-    mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
+    mo = P_SpawnMissile (actor, target, MT_FATSHOT);
     mo->angle -= FATSPREAD*2;
     an = mo->angle >> ANGLETOFINESHIFT;
     mo->momx = FixedMul (mo->info->speed, finecosine[an]);
@@ -1392,17 +1385,20 @@ void A_FatAttack2 (mobj_t* actor)
 void A_FatAttack3 (mobj_t*     actor)
 {
     mobj_t*    mo;
+    mobj_t*     target;
     int                an;
 
     A_FaceTarget (actor);
+
+    target = P_SubstNullMobj(actor->target);
     
-    mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
+    mo = P_SpawnMissile (actor, target, MT_FATSHOT);
     mo->angle -= FATSPREAD/2;
     an = mo->angle >> ANGLETOFINESHIFT;
     mo->momx = FixedMul (mo->info->speed, finecosine[an]);
     mo->momy = FixedMul (mo->info->speed, finesine[an]);
 
-    mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
+    mo = P_SpawnMissile (actor, target, MT_FATSHOT);
     mo->angle += FATSPREAD/2;
     an = mo->angle >> ANGLETOFINESHIFT;
     mo->momx = FixedMul (mo->info->speed, finecosine[an]);
@@ -1597,9 +1593,60 @@ void A_Fall (mobj_t *actor)
 //
 void A_Explode (mobj_t* thingy)
 {
-    P_RadiusAttack ( thingy, thingy->target, 128 );
+    P_RadiusAttack(thingy, thingy->target, 128);
 }
 
+// Check whether the death of the specified monster type is allowed
+// to trigger the end of episode special action.
+//
+// This behavior changed in v1.9, the most notable effect of which
+// was to break uac_dead.wad
+
+static boolean CheckBossEnd(mobjtype_t motype)
+{
+    if (gameversion < exe_ultimate)
+    {
+        if (gamemap != 8)
+        {
+            return false;
+        }
+
+        // Baron death on later episodes is nothing special.
+
+        if (motype == MT_BRUISER && gameepisode != 1)
+        {
+            return false;
+        }
+
+        return true;
+    }
+    else
+    {
+        // New logic that appeared in Ultimate Doom.
+        // Looks like the logic was overhauled while adding in the
+        // episode 4 support.  Now bosses only trigger on their
+        // specific episode.
+
+       switch(gameepisode)
+       {
+            case 1:
+                return gamemap == 8 && motype == MT_BRUISER;
+
+            case 2:
+                return gamemap == 8 && motype == MT_CYBORG;
+
+            case 3:
+                return gamemap == 8 && motype == MT_SPIDER;
+
+           case 4:
+                return (gamemap == 6 && motype == MT_CYBORG)
+                    || (gamemap == 8 && motype == MT_SPIDER);
+
+            default:
+                return gamemap == 8;
+       }
+    }
+}
 
 //
 // A_BossDeath
@@ -1624,61 +1671,12 @@ void A_BossDeath (mobj_t* mo)
     }
     else
     {
-       switch(gameepisode)
-       {
-         case 1:
-           if (gamemap != 8)
-               return;
-
-           if (mo->type != MT_BRUISER)
-               return;
-           break;
-           
-         case 2:
-           if (gamemap != 8)
-               return;
-
-           if (mo->type != MT_CYBORG)
-               return;
-           break;
-           
-         case 3:
-           if (gamemap != 8)
-               return;
-           
-           if (mo->type != MT_SPIDER)
-               return;
-           
-           break;
-           
-         case 4:
-           switch(gamemap)
-           {
-             case 6:
-               if (mo->type != MT_CYBORG)
-                   return;
-               break;
-               
-             case 8: 
-               if (mo->type != MT_SPIDER)
-                   return;
-               break;
-               
-             default:
-               return;
-               break;
-           }
-           break;
-           
-         default:
-           if (gamemap != 8)
-               return;
-           break;
-       }
-               
+        if (!CheckBossEnd(mo->type))
+        {
+            return;
+        }
     }
 
-    
     // make sure there is a player alive for victory
     for (i=0 ; i<MAXPLAYERS ; i++)
        if (playeringame[i] && players[i].health > 0)
@@ -1739,7 +1737,7 @@ void A_BossDeath (mobj_t* mo)
            {
              case 6:
                junk.tag = 666;
-               EV_DoDoor (&junk, blazeOpen);
+               EV_DoDoor (&junk, vld_blazeOpen);
                return;
                break;
                
@@ -1808,7 +1806,7 @@ A_CloseShotgun2
 
 mobj_t*                braintargets[32];
 int            numbraintargets;
-int            braintargeton;
+int            braintargeton = 0;
 
 void A_BrainAwake (mobj_t* mo)
 {
@@ -1944,7 +1942,7 @@ void A_SpawnFly (mobj_t* mo)
     if (--mo->reactiontime)
        return; // still flying
        
-    targ = mo->target;
+    targ = P_SubstNullMobj(mo->target);
 
     // First spawn teleport fog.
     fog = P_SpawnMobj (targ->x, targ->y, targ->z, MT_SPAWNFIRE);
index 37a6cd8aa9aff13b95f01da41a855fbefd20ddb8..1384ee6b46c485d95570bc2939752bc9a08f499a 100644 (file)
@@ -1,28 +1,21 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Floor animation: raising stairs.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: p_floor.c,v 1.4 1997/02/03 16:47:54 b1 Exp $";
 
 
 #include "z_zone.h"
@@ -216,8 +209,7 @@ void T_MoveFloor(floormove_t* floor)
                      floor->crush,0,floor->direction);
     
     if (!(leveltime&7))
-       S_StartSound((mobj_t *)&floor->sector->soundorg,
-                    sfx_stnmov);
+       S_StartSound(&floor->sector->soundorg, sfx_stnmov);
     
     if (res == pastdest)
     {
@@ -247,8 +239,7 @@ void T_MoveFloor(floormove_t* floor)
        }
        P_RemoveThinker(&floor->thinker);
 
-       S_StartSound((mobj_t *)&floor->sector->soundorg,
-                    sfx_pstop);
+       S_StartSound(&floor->sector->soundorg, sfx_pstop);
     }
 
 }
@@ -371,7 +362,7 @@ EV_DoFloor
 
          case raiseToTexture:
          {
-             int       minsize = MAXINT;
+             int       minsize = INT_MAX;
              side_t*   side;
                                
              floor->direction = 1;
@@ -467,8 +458,8 @@ EV_BuildStairs
 
     floormove_t*       floor;
     
-    fixed_t            stairsize;
-    fixed_t            speed;
+    fixed_t            stairsize = 0;
+    fixed_t            speed = 0;
 
     secnum = -1;
     rtn = 0;
index eea30f1d13747932d20add774338b9713dee7e22..1eb58cfcab5d7268742f032ae6fe10c304db4162 100644 (file)
@@ -1,29 +1,22 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Handling interactions (i.e., collisions).
 //
-//-----------------------------------------------------------------------------
 
 
-static const char
-rcsid[] = "$Id: p_inter.c,v 1.4 1997/02/03 22:45:11 b1 Exp $";
 
 
 // Data.
@@ -31,6 +24,8 @@ rcsid[] = "$Id: p_inter.c,v 1.4 1997/02/03 22:45:11 b1 Exp $";
 #include "dstrings.h"
 #include "sounds.h"
 
+#include "deh_main.h"
+#include "deh_misc.h"
 #include "doomstat.h"
 
 #include "m_random.h"
@@ -42,9 +37,6 @@ rcsid[] = "$Id: p_inter.c,v 1.4 1997/02/03 22:45:11 b1 Exp $";
 
 #include "s_sound.h"
 
-#ifdef __GNUG__
-#pragma implementation "p_inter.h"
-#endif
 #include "p_inter.h"
 
 
@@ -81,7 +73,7 @@ P_GiveAmmo
     if (ammo == am_noammo)
        return false;
                
-    if (ammo < 0 || ammo > NUMAMMO)
+    if (ammo > NUMAMMO)
        I_Error ("P_GiveAmmo: bad type %i", ammo);
                
     if ( player->ammo[ammo] == player->maxammo[ammo]  )
@@ -172,48 +164,50 @@ P_GiveWeapon
 {
     boolean    gaveammo;
     boolean    gaveweapon;
-       
-    if (netgame
-       && (deathmatch!=2)
-        && !dropped )
-    {
-       // leave placed weapons forever on net games
-       if (player->weaponowned[weapon])
-           return false;
-
-       player->bonuscount += BONUSADD;
-       player->weaponowned[weapon] = true;
 
-       if (deathmatch)
-           P_GiveAmmo (player, weaponinfo[weapon].ammo, 5);
-       else
-           P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
-       player->pendingweapon = weapon;
-
-       if (player == &players[consoleplayer])
-           S_StartSound (NULL, sfx_wpnup);
-       return false;
+    if (netgame && (deathmatch!=2) && !dropped )
+       {
+               // leave placed weapons forever on net games
+               if (player->weaponowned[weapon])
+                       return false;
+
+               player->bonuscount += BONUSADD;
+               player->weaponowned[weapon] = true;
+       
+               if (deathmatch)
+                       P_GiveAmmo (player, weaponinfo[weapon].ammo, 5);
+               else
+                       P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
+               player->pendingweapon = weapon;
+
+               if (player == &players[consoleplayer])
+                       S_StartSound (NULL, sfx_wpnup);
+               return false;
     }
        
     if (weaponinfo[weapon].ammo != am_noammo)
     {
-       // give one clip with a dropped weapon,
-       // two clips with a found weapon
-       if (dropped)
-           gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1);
-       else
-           gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
+               // give one clip with a dropped weapon,
+               // two clips with a found weapon
+               if (dropped)
+                       gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1);
+               else
+                       gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
     }
     else
-       gaveammo = false;
+    {
+       gaveammo = false;
+    }
        
     if (player->weaponowned[weapon])
-       gaveweapon = false;
+    {
+       gaveweapon = false;
+    }
     else
     {
-       gaveweapon = true;
-       player->weaponowned[weapon] = true;
-       player->pendingweapon = weapon;
+               gaveweapon = true;
+               player->weaponowned[weapon] = true;
+               player->pendingweapon = weapon;
     }
        
     return (gaveweapon || gaveammo);
@@ -368,51 +362,55 @@ P_TouchSpecialThing
     {
        // armor
       case SPR_ARM1:
-       if (!P_GiveArmor (player, 1))
+       if (!P_GiveArmor (player, deh_green_armor_class))
            return;
-       player->message = GOTARMOR;
+       player->message = DEH_String(GOTARMOR);
        break;
                
       case SPR_ARM2:
-       if (!P_GiveArmor (player, 2))
+       if (!P_GiveArmor (player, deh_blue_armor_class))
            return;
-       player->message = GOTMEGA;
+       player->message = DEH_String(GOTMEGA);
        break;
        
        // bonus items
       case SPR_BON1:
        player->health++;               // can go over 100%
-       if (player->health > 200)
-           player->health = 200;
+       if (player->health > deh_max_health)
+           player->health = deh_max_health;
        player->mo->health = player->health;
-       player->message = GOTHTHBONUS;
+       player->message = DEH_String(GOTHTHBONUS);
        break;
        
       case SPR_BON2:
        player->armorpoints++;          // can go over 100%
-       if (player->armorpoints > 200)
-           player->armorpoints = 200;
+       if (player->armorpoints > deh_max_armor)
+           player->armorpoints = deh_max_armor;
+        // deh_green_armor_class only applies to the green armor shirt;
+        // for the armor helmets, armortype 1 is always used.
        if (!player->armortype)
            player->armortype = 1;
-       player->message = GOTARMBONUS;
+       player->message = DEH_String(GOTARMBONUS);
        break;
        
       case SPR_SOUL:
-       player->health += 100;
-       if (player->health > 200)
-           player->health = 200;
+       player->health += deh_soulsphere_health;
+       if (player->health > deh_max_soulsphere)
+           player->health = deh_max_soulsphere;
        player->mo->health = player->health;
-       player->message = GOTSUPER;
+       player->message = DEH_String(GOTSUPER);
        sound = sfx_getpow;
        break;
        
       case SPR_MEGA:
        if (gamemode != commercial)
            return;
-       player->health = 200;
+       player->health = deh_megasphere_health;
        player->mo->health = player->health;
-       P_GiveArmor (player,2);
-       player->message = GOTMSPHERE;
+        // We always give armor type 2 for the megasphere; dehacked only 
+        // affects the MegaArmor.
+       P_GiveArmor (player, 2);
+       player->message = DEH_String(GOTMSPHERE);
        sound = sfx_getpow;
        break;
        
@@ -420,7 +418,7 @@ P_TouchSpecialThing
        // leave cards for everyone
       case SPR_BKEY:
        if (!player->cards[it_bluecard])
-           player->message = GOTBLUECARD;
+           player->message = DEH_String(GOTBLUECARD);
        P_GiveCard (player, it_bluecard);
        if (!netgame)
            break;
@@ -428,7 +426,7 @@ P_TouchSpecialThing
        
       case SPR_YKEY:
        if (!player->cards[it_yellowcard])
-           player->message = GOTYELWCARD;
+           player->message = DEH_String(GOTYELWCARD);
        P_GiveCard (player, it_yellowcard);
        if (!netgame)
            break;
@@ -436,7 +434,7 @@ P_TouchSpecialThing
        
       case SPR_RKEY:
        if (!player->cards[it_redcard])
-           player->message = GOTREDCARD;
+           player->message = DEH_String(GOTREDCARD);
        P_GiveCard (player, it_redcard);
        if (!netgame)
            break;
@@ -444,7 +442,7 @@ P_TouchSpecialThing
        
       case SPR_BSKU:
        if (!player->cards[it_blueskull])
-           player->message = GOTBLUESKUL;
+           player->message = DEH_String(GOTBLUESKUL);
        P_GiveCard (player, it_blueskull);
        if (!netgame)
            break;
@@ -452,7 +450,7 @@ P_TouchSpecialThing
        
       case SPR_YSKU:
        if (!player->cards[it_yellowskull])
-           player->message = GOTYELWSKUL;
+           player->message = DEH_String(GOTYELWSKUL);
        P_GiveCard (player, it_yellowskull);
        if (!netgame)
            break;
@@ -460,7 +458,7 @@ P_TouchSpecialThing
        
       case SPR_RSKU:
        if (!player->cards[it_redskull])
-           player->message = GOTREDSKULL;
+           player->message = DEH_String(GOTREDSKULL);
        P_GiveCard (player, it_redskull);
        if (!netgame)
            break;
@@ -470,7 +468,7 @@ P_TouchSpecialThing
       case SPR_STIM:
        if (!P_GiveBody (player, 10))
            return;
-       player->message = GOTSTIM;
+       player->message = DEH_String(GOTSTIM);
        break;
        
       case SPR_MEDI:
@@ -478,9 +476,9 @@ P_TouchSpecialThing
            return;
 
        if (player->health < 25)
-           player->message = GOTMEDINEED;
+           player->message = DEH_String(GOTMEDINEED);
        else
-           player->message = GOTMEDIKIT;
+           player->message = DEH_String(GOTMEDIKIT);
        break;
 
        
@@ -488,14 +486,14 @@ P_TouchSpecialThing
       case SPR_PINV:
        if (!P_GivePower (player, pw_invulnerability))
            return;
-       player->message = GOTINVUL;
+       player->message = DEH_String(GOTINVUL);
        sound = sfx_getpow;
        break;
        
       case SPR_PSTR:
        if (!P_GivePower (player, pw_strength))
            return;
-       player->message = GOTBERSERK;
+       player->message = DEH_String(GOTBERSERK);
        if (player->readyweapon != wp_fist)
            player->pendingweapon = wp_fist;
        sound = sfx_getpow;
@@ -504,28 +502,28 @@ P_TouchSpecialThing
       case SPR_PINS:
        if (!P_GivePower (player, pw_invisibility))
            return;
-       player->message = GOTINVIS;
+       player->message = DEH_String(GOTINVIS);
        sound = sfx_getpow;
        break;
        
       case SPR_SUIT:
        if (!P_GivePower (player, pw_ironfeet))
            return;
-       player->message = GOTSUIT;
+       player->message = DEH_String(GOTSUIT);
        sound = sfx_getpow;
        break;
        
       case SPR_PMAP:
        if (!P_GivePower (player, pw_allmap))
            return;
-       player->message = GOTMAP;
+       player->message = DEH_String(GOTMAP);
        sound = sfx_getpow;
        break;
        
       case SPR_PVIS:
        if (!P_GivePower (player, pw_infrared))
            return;
-       player->message = GOTVISOR;
+       player->message = DEH_String(GOTVISOR);
        sound = sfx_getpow;
        break;
        
@@ -541,49 +539,49 @@ P_TouchSpecialThing
            if (!P_GiveAmmo (player,am_clip,1))
                return;
        }
-       player->message = GOTCLIP;
+       player->message = DEH_String(GOTCLIP);
        break;
        
       case SPR_AMMO:
        if (!P_GiveAmmo (player, am_clip,5))
            return;
-       player->message = GOTCLIPBOX;
+       player->message = DEH_String(GOTCLIPBOX);
        break;
        
       case SPR_ROCK:
        if (!P_GiveAmmo (player, am_misl,1))
            return;
-       player->message = GOTROCKET;
+       player->message = DEH_String(GOTROCKET);
        break;
        
       case SPR_BROK:
        if (!P_GiveAmmo (player, am_misl,5))
            return;
-       player->message = GOTROCKBOX;
+       player->message = DEH_String(GOTROCKBOX);
        break;
        
       case SPR_CELL:
        if (!P_GiveAmmo (player, am_cell,1))
            return;
-       player->message = GOTCELL;
+       player->message = DEH_String(GOTCELL);
        break;
        
       case SPR_CELP:
        if (!P_GiveAmmo (player, am_cell,5))
            return;
-       player->message = GOTCELLBOX;
+       player->message = DEH_String(GOTCELLBOX);
        break;
        
       case SPR_SHEL:
        if (!P_GiveAmmo (player, am_shell,1))
            return;
-       player->message = GOTSHELLS;
+       player->message = DEH_String(GOTSHELLS);
        break;
        
       case SPR_SBOX:
        if (!P_GiveAmmo (player, am_shell,5))
            return;
-       player->message = GOTSHELLBOX;
+       player->message = DEH_String(GOTSHELLBOX);
        break;
        
       case SPR_BPAK:
@@ -595,56 +593,56 @@ P_TouchSpecialThing
        }
        for (i=0 ; i<NUMAMMO ; i++)
            P_GiveAmmo (player, i, 1);
-       player->message = GOTBACKPACK;
+       player->message = DEH_String(GOTBACKPACK);
        break;
        
        // weapons
       case SPR_BFUG:
        if (!P_GiveWeapon (player, wp_bfg, false) )
            return;
-       player->message = GOTBFG9000;
+       player->message = DEH_String(GOTBFG9000);
        sound = sfx_wpnup;      
        break;
        
       case SPR_MGUN:
-       if (!P_GiveWeapon (player, wp_chaingun, special->flags&MF_DROPPED) )
+       if (!P_GiveWeapon (player, wp_chaingun, (special->flags&MF_DROPPED) != 0) )
            return;
-       player->message = GOTCHAINGUN;
+       player->message = DEH_String(GOTCHAINGUN);
        sound = sfx_wpnup;      
        break;
        
       case SPR_CSAW:
        if (!P_GiveWeapon (player, wp_chainsaw, false) )
            return;
-       player->message = GOTCHAINSAW;
+       player->message = DEH_String(GOTCHAINSAW);
        sound = sfx_wpnup;      
        break;
        
       case SPR_LAUN:
        if (!P_GiveWeapon (player, wp_missile, false) )
            return;
-       player->message = GOTLAUNCHER;
+       player->message = DEH_String(GOTLAUNCHER);
        sound = sfx_wpnup;      
        break;
        
       case SPR_PLAS:
        if (!P_GiveWeapon (player, wp_plasma, false) )
            return;
-       player->message = GOTPLASMA;
+       player->message = DEH_String(GOTPLASMA);
        sound = sfx_wpnup;      
        break;
        
       case SPR_SHOT:
-       if (!P_GiveWeapon (player, wp_shotgun, special->flags&MF_DROPPED ) )
+       if (!P_GiveWeapon (player, wp_shotgun, (special->flags&MF_DROPPED) != 0 ) )
            return;
-       player->message = GOTSHOTGUN;
+       player->message = DEH_String(GOTSHOTGUN);
        sound = sfx_wpnup;      
        break;
                
       case SPR_SGN2:
-       if (!P_GiveWeapon (player, wp_supershotgun, special->flags&MF_DROPPED ) )
+       if (!P_GiveWeapon (player, wp_supershotgun, (special->flags&MF_DROPPED) != 0 ) )
            return;
-       player->message = GOTSHOTGUN2;
+       player->message = DEH_String(GOTSHOTGUN2);
        sound = sfx_wpnup;      
        break;
                
@@ -730,6 +728,12 @@ P_KillMobj
                
     // I_StartSound (&actor->r, actor->info->deathsound);
 
+    // In Chex Quest, monsters don't drop items.
+
+    if (gameversion == exe_chex)
+    {
+        return;
+    }
 
     // Drop stuff.
     // This determines the kind of object spawned
index 1b1c5160973f6227b14094310939986c08f83dea..5764d5dab51991ce40c9315bbd1ba36a4ba56fa7 100644 (file)
@@ -1,32 +1,26 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __P_INTER__
 #define __P_INTER__
 
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 
 boolean        P_GivePower(player_t*, int);
@@ -34,8 +28,3 @@ boolean       P_GivePower(player_t*, int);
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 2a0555ef917f129da21a7764c683f3b820e4c573..863338dcf3c72431b7890c5d58ab0b5179d5be76 100644 (file)
@@ -1,29 +1,22 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Handle Sector base lighting effects.
 //     Muzzle flash?
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: p_lights.c,v 1.5 1997/02/03 22:45:11 b1 Exp $";
 
 
 #include "z_zone.h"
index c3e181b3673799e9f93035214df19b0cabe143c3..95fa405340c58ec1b2bebe7e1276cc020638f933 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Play functions, animation, global header.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __P_LOCAL__
@@ -92,8 +89,8 @@ void  P_PlayerThink (player_t* player);
 //
 // P_MOBJ
 //
-#define ONFLOORZ               MININT
-#define ONCEILINGZ             MAXINT
+#define ONFLOORZ               INT_MIN
+#define ONCEILINGZ             INT_MAX
 
 // Time interval for item respawning.
 #define ITEMQUESIZE            128
@@ -114,6 +111,7 @@ P_SpawnMobj
   mobjtype_t   type );
 
 void   P_RemoveMobj (mobj_t* th);
+mobj_t* P_SubstNullMobj (mobj_t* th);
 boolean        P_SetMobjState (mobj_t* mobj, statenum_t state);
 void   P_MobjThinker (mobj_t* mobj);
 
@@ -151,7 +149,10 @@ typedef struct
     }                  d;
 } intercept_t;
 
-#define MAXINTERCEPTS  128
+// Extended MAXINTERCEPTS, to allow for intercepts overrun emulation.
+
+#define MAXINTERCEPTS_ORIGINAL 128
+#define MAXINTERCEPTS          (MAXINTERCEPTS_ORIGINAL + 61)
 
 extern intercept_t     intercepts[MAXINTERCEPTS];
 extern intercept_t*    intercept_p;
@@ -207,6 +208,20 @@ extern fixed_t             tmceilingz;
 
 extern line_t*         ceilingline;
 
+// fraggle: I have increased the size of this buffer.  In the original Doom,
+// overrunning past this limit caused other bits of memory to be overwritten,
+// affecting demo playback.  However, in doing so, the limit was still
+// exceeded.  So we have to support more than 8 specials.
+//
+// We keep the original limit, to detect what variables in memory were
+// overwritten (see SpechitOverrun())
+
+#define MAXSPECIALCROSS                20
+#define MAXSPECIALCROSS_ORIGINAL       8
+
+extern line_t* spechit[MAXSPECIALCROSS];
+extern int     numspechit;
+
 boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y);
 boolean P_TryMove (mobj_t* thing, fixed_t x, fixed_t y);
 boolean P_TeleportMove (mobj_t* thing, fixed_t x, fixed_t y);
@@ -280,10 +295,3 @@ P_DamageMobj
 
 
 #endif // __P_LOCAL__
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-
-
index aba15d80847774d4ad0c88f43255717e104499b8..e371869a74ef162c7e5f9799ac9f0895e60b5aa3 100644 (file)
@@ -1,37 +1,34 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard, Andrey Budko
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Movement, collision handling.
 //     Shooting and aiming.
 //
-//-----------------------------------------------------------------------------
-
-static const char
-rcsid[] = "$Id: p_map.c,v 1.5 1997/02/03 22:45:11 b1 Exp $";
 
+#include <stdio.h>
 #include <stdlib.h>
 
+#include "deh_misc.h"
+
 #include "m_bbox.h"
 #include "m_random.h"
 #include "i_system.h"
 
 #include "doomdef.h"
+#include "m_argv.h"
+#include "m_misc.h"
 #include "p_local.h"
 
 #include "s_sound.h"
@@ -42,6 +39,26 @@ rcsid[] = "$Id: p_map.c,v 1.5 1997/02/03 22:45:11 b1 Exp $";
 // Data.
 #include "sounds.h"
 
+// Spechit overrun magic value.
+//
+// This is the value used by PrBoom-plus.  I think the value below is 
+// actually better and works with more demos.  However, I think
+// it's better for the spechits emulation to be compatible with
+// PrBoom-plus, at least so that the big spechits emulation list
+// on Doomworld can also be used with Chocolate Doom.
+
+#define DEFAULT_SPECHIT_MAGIC 0x01C09C98
+
+// This is from a post by myk on the Doomworld forums, 
+// outputted from entryway's spechit_magic generator for
+// s205n546.lmp.  The _exact_ value of this isn't too
+// important; as long as it is in the right general
+// range, it will usually work.  Otherwise, we can use
+// the generator (hacked doom2.exe) and provide it 
+// with -spechit.
+
+//#define DEFAULT_SPECHIT_MAGIC 0x84f968e8
+
 
 fixed_t                tmbbox[4];
 mobj_t*                tmthing;
@@ -64,7 +81,6 @@ line_t*               ceilingline;
 
 // keep track of special lines as they are hit,
 // but don't process them until the move is proven valid
-#define MAXSPECIALCROSS                8
 
 line_t*                spechit[MAXSPECIALCROSS];
 int            numspechit;
@@ -181,6 +197,7 @@ P_TeleportMove
 // MOVEMENT ITERATOR FUNCTIONS
 //
 
+static void SpechitOverrun(line_t *ld);
 
 //
 // PIT_CheckLine
@@ -239,8 +256,14 @@ boolean PIT_CheckLine (line_t* ld)
     // if contacted a special line, add it to the list
     if (ld->special)
     {
-       spechit[numspechit] = ld;
+        spechit[numspechit] = ld;
        numspechit++;
+
+        // fraggle: spechits overrun emulation code from prboom-plus
+        if (numspechit > MAXSPECIALCROSS_ORIGINAL)
+        {
+            SpechitOverrun(ld);
+        }
     }
 
     return true;
@@ -296,8 +319,8 @@ boolean PIT_CheckThing (mobj_t* thing)
        if (tmthing->z+tmthing->height < thing->z)
            return true;                // underneath
                
-       if (tmthing->target && (
-           tmthing->target->type == thing->type || 
+       if (tmthing->target 
+         && (tmthing->target->type == thing->type || 
            (tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER)||
            (tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT) ) )
        {
@@ -305,7 +328,11 @@ boolean PIT_CheckThing (mobj_t* thing)
            if (thing == tmthing->target)
                return true;
 
-           if (thing->type != MT_PLAYER)
+            // sdh: Add deh_species_infighting here.  We can override the
+            // "monsters of the same species cant hurt each other" behavior
+            // through dehacked patches
+
+           if (thing->type != MT_PLAYER && !deh_species_infighting)
            {
                // Explode, but do no damage.
                // Let players missile other players.
@@ -839,14 +866,16 @@ PTR_AimTraverse (intercept_t* in)
        
        dist = FixedMul (attackrange, in->frac);
 
-       if (li->frontsector->floorheight != li->backsector->floorheight)
+        if (li->backsector == NULL
+         || li->frontsector->floorheight != li->backsector->floorheight)
        {
            slope = FixedDiv (openbottom - shootz , dist);
            if (slope > bottomslope)
                bottomslope = slope;
        }
                
-       if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+       if (li->backsector == NULL
+         || li->frontsector->ceilingheight != li->backsector->ceilingheight)
        {
            slope = FixedDiv (opentop - shootz , dist);
            if (slope < topslope)
@@ -927,19 +956,35 @@ boolean PTR_ShootTraverse (intercept_t* in)
                
        dist = FixedMul (attackrange, in->frac);
 
-       if (li->frontsector->floorheight != li->backsector->floorheight)
-       {
-           slope = FixedDiv (openbottom - shootz , dist);
-           if (slope > aimslope)
-               goto hitline;
-       }
-               
-       if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
-       {
-           slope = FixedDiv (opentop - shootz , dist);
-           if (slope < aimslope)
-               goto hitline;
-       }
+        // e6y: emulation of missed back side on two-sided lines.
+        // backsector can be NULL when emulating missing back side.
+
+        if (li->backsector == NULL)
+        {
+            slope = FixedDiv (openbottom - shootz , dist);
+            if (slope > aimslope)
+                goto hitline;
+
+            slope = FixedDiv (opentop - shootz , dist);
+            if (slope < aimslope)
+                goto hitline;
+        }
+        else
+        {
+            if (li->frontsector->floorheight != li->backsector->floorheight)
+            {
+                slope = FixedDiv (openbottom - shootz , dist);
+                if (slope > aimslope)
+                    goto hitline;
+            }
+
+            if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+            {
+                slope = FixedDiv (opentop - shootz , dist);
+                if (slope < aimslope)
+                    goto hitline;
+            }
+        }
 
        // shot continues
        return true;
@@ -1027,6 +1072,8 @@ P_AimLineAttack
 {
     fixed_t    x2;
     fixed_t    y2;
+
+    t1 = P_SubstNullMobj(t1);
        
     angle >>= ANGLETOFINESHIFT;
     shootthing = t1;
@@ -1337,3 +1384,65 @@ P_ChangeSector
     return nofit;
 }
 
+// Code to emulate the behavior of Vanilla Doom when encountering an overrun
+// of the spechit array.  This is by Andrey Budko (e6y) and comes from his
+// PrBoom plus port.  A big thanks to Andrey for this.
+
+static void SpechitOverrun(line_t *ld)
+{
+    static unsigned int baseaddr = 0;
+    unsigned int addr;
+   
+    if (baseaddr == 0)
+    {
+        int p;
+
+        // This is the first time we have had an overrun.  Work out
+        // what base address we are going to use.
+        // Allow a spechit value to be specified on the command line.
+
+        //!
+        // @category compat
+        // @arg <n>
+        //
+        // Use the specified magic value when emulating spechit overruns.
+        //
+
+        p = M_CheckParmWithArgs("-spechit", 1);
+        
+        if (p > 0)
+        {
+            M_StrToInt(myargv[p+1], (int *) &baseaddr);
+        }
+        else
+        {
+            baseaddr = DEFAULT_SPECHIT_MAGIC;
+        }
+    }
+    
+    // Calculate address used in doom2.exe
+
+    addr = baseaddr + (ld - lines) * 0x3E;
+
+    switch(numspechit)
+    {
+        case 9: 
+        case 10:
+        case 11:
+        case 12:
+            tmbbox[numspechit-9] = addr;
+            break;
+        case 13: 
+            crushchange = addr; 
+            break;
+        case 14: 
+            nofit = addr; 
+            break;
+        default:
+            fprintf(stderr, "SpechitOverrun: Warning: unable to emulate"
+                            "an overrun where numspechit=%i\n",
+                            numspechit);
+            break;
+    }
+}
+
index 597b19c075dce45f9930be8000d1d5d8b5ff3596..916f2b643771a8360a43029d405c874aa92bdce9 100644 (file)
@@ -1,20 +1,17 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
+// Copyright(C) 2005, 2006 Andrey Budko
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Movement/collision utility functions,
 //     BLOCKMAP Iterator functions,
 //     and some PIT_* functions to use for iteration.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: p_maputl.c,v 1.5 1997/02/03 22:45:11 b1 Exp $";
 
 
 #include <stdlib.h>
@@ -34,6 +28,7 @@ rcsid[] = "$Id: p_maputl.c,v 1.5 1997/02/03 22:45:11 b1 Exp $";
 #include "m_bbox.h"
 
 #include "doomdef.h"
+#include "doomstat.h"
 #include "p_local.h"
 
 
@@ -111,8 +106,8 @@ P_BoxOnLineSide
 ( fixed_t*     tmbox,
   line_t*      ld )
 {
-    int                p1;
-    int                p2;
+    int                p1 = 0;
+    int                p2 = 0;
        
     switch (ld->slopetype)
     {
@@ -548,6 +543,8 @@ divline_t   trace;
 boolean        earlyout;
 int            ptflags;
 
+static void InterceptsOverrun(int num_intercepts, intercept_t *intercept);
+
 //
 // PIT_AddLineIntercepts.
 // Looks for lines in the given block
@@ -603,6 +600,7 @@ PIT_AddLineIntercepts (line_t* ld)
     intercept_p->frac = frac;
     intercept_p->isaline = true;
     intercept_p->d.line = ld;
+    InterceptsOverrun(intercept_p - intercepts, intercept_p);
     intercept_p++;
 
     return true;       // continue
@@ -668,6 +666,7 @@ boolean PIT_AddThingIntercepts (mobj_t* thing)
     intercept_p->frac = frac;
     intercept_p->isaline = false;
     intercept_p->d.thing = thing;
+    InterceptsOverrun(intercept_p - intercepts, intercept_p);
     intercept_p++;
 
     return true;               // keep going
@@ -695,7 +694,7 @@ P_TraverseIntercepts
        
     while (count--)
     {
-       dist = MAXINT;
+       dist = INT_MAX;
        for (scan = intercepts ; scan<intercept_p ; scan++)
        {
            if (scan->frac < dist)
@@ -723,13 +722,132 @@ P_TraverseIntercepts
         if ( !func (in) )
            return false;       // don't bother going farther
 
-       in->frac = MAXINT;
+       in->frac = INT_MAX;
     }
        
     return true;               // everything was traversed
 }
 
+extern fixed_t bulletslope;
+
+// Intercepts Overrun emulation, from PrBoom-plus.
+// Thanks to Andrey Budko (entryway) for researching this and his 
+// implementation of Intercepts Overrun emulation in PrBoom-plus
+// which this is based on.
+
+typedef struct
+{
+    int len;
+    void *addr;
+    boolean int16_array;
+} intercepts_overrun_t;
+
+// Intercepts memory table.  This is where various variables are located
+// in memory in Vanilla Doom.  When the intercepts table overflows, we
+// need to write to them.
+//
+// Almost all of the values to overwrite are 32-bit integers, except for
+// playerstarts, which is effectively an array of 16-bit integers and
+// must be treated differently.
+
+static intercepts_overrun_t intercepts_overrun[] =
+{
+    {4,   NULL,                          false},
+    {4,   NULL, /* &earlyout, */         false},
+    {4,   NULL, /* &intercept_p, */      false},
+    {4,   &lowfloor,                     false},
+    {4,   &openbottom,                   false},
+    {4,   &opentop,                      false},
+    {4,   &openrange,                    false},
+    {4,   NULL,                          false},
+    {120, NULL, /* &activeplats, */      false},
+    {8,   NULL,                          false},
+    {4,   &bulletslope,                  false},
+    {4,   NULL, /* &swingx, */           false},
+    {4,   NULL, /* &swingy, */           false},
+    {4,   NULL,                          false},
+    {40,  &playerstarts,                 true},
+    {4,   NULL, /* &blocklinks, */       false},
+    {4,   &bmapwidth,                    false},
+    {4,   NULL, /* &blockmap, */         false},
+    {4,   &bmaporgx,                     false},
+    {4,   &bmaporgy,                     false},
+    {4,   NULL, /* &blockmaplump, */     false},
+    {4,   &bmapheight,                   false},
+    {0,   NULL,                          false},
+};
+
+// Overwrite a specific memory location with a value.
+
+static void InterceptsMemoryOverrun(int location, int value)
+{
+    int i, offset;
+    int index;
+    void *addr;
 
+    i = 0;
+    offset = 0;
+
+    // Search down the array until we find the right entry
+
+    while (intercepts_overrun[i].len != 0)
+    {
+        if (offset + intercepts_overrun[i].len > location)
+        {
+            addr = intercepts_overrun[i].addr;
+
+            // Write the value to the memory location.
+            // 16-bit and 32-bit values are written differently.
+
+            if (addr != NULL)
+            {
+                if (intercepts_overrun[i].int16_array)
+                {
+                    index = (location - offset) / 2;
+                    ((short *) addr)[index] = value & 0xffff;
+                    ((short *) addr)[index + 1] = (value >> 16) & 0xffff;
+                }
+                else
+                {
+                    index = (location - offset) / 4;
+                    ((int *) addr)[index] = value;
+                }
+            }
+
+            break;
+        }
+
+        offset += intercepts_overrun[i].len;
+        ++i;
+    }
+}
+
+// Emulate overruns of the intercepts[] array.
+
+static void InterceptsOverrun(int num_intercepts, intercept_t *intercept)
+{
+    int location;
+
+    if (num_intercepts <= MAXINTERCEPTS_ORIGINAL)
+    {
+        // No overrun
+
+        return;
+    }
+
+    location = (num_intercepts - MAXINTERCEPTS_ORIGINAL - 1) * 12;
+
+    // Overwrite memory that is overwritten in Vanilla Doom, using
+    // the values from the intercept structure.
+    //
+    // Note: the ->d.{thing,line} member should really have its
+    // address translated into the correct address value for 
+    // Vanilla Doom.
+
+    InterceptsMemoryOverrun(location, intercept->frac);
+    InterceptsMemoryOverrun(location + 4, intercept->isaline);
+    InterceptsMemoryOverrun(location + 8, (int) intercept->d.thing);
+}
 
 
 //
index 209d16144ffe6a0f2cde0981999e06b5299240d2..a3b9c432219f13aae45ab73d9643b62ef31d99c8 100644 (file)
@@ -1,28 +1,22 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Moving object handling. Spawn functions.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: p_mobj.c,v 1.5 1997/02/03 22:45:12 b1 Exp $";
+#include <stdio.h>
 
 #include "i_system.h"
 #include "z_zone.h"
@@ -288,7 +282,29 @@ void P_ZMovement (mobj_t* mo)
        // Note (id):
        //  somebody left this after the setting momz to 0,
        //  kinda useless there.
-       if (mo->flags & MF_SKULLFLY)
+       //
+       // cph - This was the a bug in the linuxdoom-1.10 source which
+       //  caused it not to sync Doom 2 v1.9 demos. Someone
+       //  added the above comment and moved up the following code. So
+       //  demos would desync in close lost soul fights.
+       // Note that this only applies to original Doom 1 or Doom2 demos - not
+       //  Final Doom and Ultimate Doom.  So we test demo_compatibility *and*
+       //  gamemission. (Note we assume that Doom1 is always Ult Doom, which
+       //  seems to hold for most published demos.)
+        //  
+        //  fraggle - cph got the logic here slightly wrong.  There are three
+        //  versions of Doom 1.9:
+        //
+        //  * The version used in registered doom 1.9 + doom2 - no bounce
+        //  * The version used in ultimate doom - has bounce
+        //  * The version used in final doom - has bounce
+        //
+        // So we need to check that this is either retail or commercial
+        // (but not doom2)
+       
+       int correct_lost_soul_bounce = gameversion >= exe_ultimate;
+
+       if (correct_lost_soul_bounce && mo->flags & MF_SKULLFLY)
        {
            // the skull slammed into something
            mo->momz = -mo->momz;
@@ -310,6 +326,16 @@ void P_ZMovement (mobj_t* mo)
        }
        mo->z = mo->floorz;
 
+
+       // cph 2001/05/26 -
+       // See lost soul bouncing comment above. We need this here for bug
+       // compatibility with original Doom2 v1.9 - if a soul is charging and
+       // hit by a raising floor this incorrectly reverses its Y momentum.
+       //
+
+        if (!correct_lost_soul_bounce && mo->flags & MF_SKULLFLY)
+            mo->momz = -mo->momz;
+
        if ( (mo->flags & MF_MISSILE)
             && !(mo->flags & MF_NOCLIP) )
        {
@@ -458,7 +484,7 @@ void P_MobjThinker (mobj_t* mobj)
 
        mobj->movecount++;
 
-       if (mobj->movecount < 12*35)
+       if (mobj->movecount < 12*TICRATE)
            return;
 
        if ( leveltime&31 )
@@ -596,7 +622,7 @@ void P_RespawnSpecials (void)
        return;         
 
     // wait at least 30 seconds
-    if (leveltime - itemrespawntime[iquetail] < 30*35)
+    if (leveltime - itemrespawntime[iquetail] < 30*TICRATE)
        return;                 
 
     mthing = &itemrespawnque[iquetail];
@@ -650,6 +676,11 @@ void P_SpawnPlayer (mapthing_t* mthing)
 
     int                        i;
 
+    if (mthing->type == 0)
+    {
+        return;
+    }
+
     // not playing?
     if (!playeringame[mthing->type-1])
        return;                                 
@@ -724,6 +755,14 @@ void P_SpawnMapThing (mapthing_t* mthing)
        }
        return;
     }
+
+    if (mthing->type <= 0)
+    {
+        // Thing type 0 is actually "player -1 start".  
+        // For some reason, Vanilla Doom accepts/ignores this.
+
+        return;
+    }
        
     // check for players specially
     if (mthing->type <= 4)
@@ -881,6 +920,28 @@ void P_CheckMissileSpawn (mobj_t* th)
        P_ExplodeMissile (th);
 }
 
+// Certain functions assume that a mobj_t pointer is non-NULL,
+// causing a crash in some situations where it is NULL.  Vanilla
+// Doom did not crash because of the lack of proper memory 
+// protection. This function substitutes NULL pointers for
+// pointers to a dummy mobj, to avoid a crash.
+
+mobj_t *P_SubstNullMobj(mobj_t *mobj)
+{
+    if (mobj == NULL)
+    {
+        static mobj_t dummy_mobj;
+
+        dummy_mobj.x = 0;
+        dummy_mobj.y = 0;
+        dummy_mobj.z = 0;
+        dummy_mobj.flags = 0;
+
+        mobj = &dummy_mobj;
+    }
+
+    return mobj;
+}
 
 //
 // P_SpawnMissile
@@ -903,7 +964,7 @@ P_SpawnMissile
        S_StartSound (th, th->info->seesound);
 
     th->target = source;       // where it came from
-    an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y);     
+    an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y);
 
     // fuzzy player
     if (dest->flags & MF_SHADOW)
index 75d368a71dc948ff9cea904f5f5fb7b0e0772064..90ed764b91c7de405d2bb5a98c348ad9083645b1 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Map Objects, MObj, definition and handling.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __P_MOBJ__
@@ -41,9 +38,6 @@
 
 
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 
 
@@ -288,8 +282,3 @@ typedef struct mobj_s
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 47150f1ff807932a096198f923362809609f7f64..9e773d55cbd16bea2c0bfe7ab7c23a56bf6db751 100644 (file)
@@ -1,29 +1,22 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Plats (i.e. elevator platforms) code, raising/lowering.
 //
-//-----------------------------------------------------------------------------
-
-static const char
-rcsid[] = "$Id: p_plats.c,v 1.5 1997/02/03 22:45:12 b1 Exp $";
 
+#include <stdio.h>
 
 #include "i_system.h"
 #include "z_zone.h"
@@ -65,8 +58,7 @@ void T_PlatRaise(plat_t* plat)
            || plat->type == raiseToNearestAndChange)
        {
            if (!(leveltime&7))
-               S_StartSound((mobj_t *)&plat->sector->soundorg,
-                            sfx_stnmov);
+               S_StartSound(&plat->sector->soundorg, sfx_stnmov);
        }
        
                                
@@ -74,8 +66,7 @@ void T_PlatRaise(plat_t* plat)
        {
            plat->count = plat->wait;
            plat->status = down;
-           S_StartSound((mobj_t *)&plat->sector->soundorg,
-                        sfx_pstart);
+           S_StartSound(&plat->sector->soundorg, sfx_pstart);
        }
        else
        {
@@ -83,8 +74,7 @@ void T_PlatRaise(plat_t* plat)
            {
                plat->count = plat->wait;
                plat->status = waiting;
-               S_StartSound((mobj_t *)&plat->sector->soundorg,
-                            sfx_pstop);
+               S_StartSound(&plat->sector->soundorg, sfx_pstop);
 
                switch(plat->type)
                {
@@ -112,7 +102,7 @@ void T_PlatRaise(plat_t* plat)
        {
            plat->count = plat->wait;
            plat->status = waiting;
-           S_StartSound((mobj_t *)&plat->sector->soundorg,sfx_pstop);
+           S_StartSound(&plat->sector->soundorg,sfx_pstop);
        }
        break;
        
@@ -123,7 +113,7 @@ void T_PlatRaise(plat_t* plat)
                plat->status = up;
            else
                plat->status = down;
-           S_StartSound((mobj_t *)&plat->sector->soundorg,sfx_pstart);
+           S_StartSound(&plat->sector->soundorg,sfx_pstart);
        }
       case     in_stasis:
        break;
@@ -191,7 +181,7 @@ EV_DoPlat
            // NO MORE DAMAGE, IF APPLICABLE
            sec->special = 0;           
 
-           S_StartSound((mobj_t *)&sec->soundorg,sfx_stnmov);
+           S_StartSound(&sec->soundorg,sfx_stnmov);
            break;
            
          case raiseAndChange:
@@ -201,7 +191,7 @@ EV_DoPlat
            plat->wait = 0;
            plat->status = up;
 
-           S_StartSound((mobj_t *)&sec->soundorg,sfx_stnmov);
+           S_StartSound(&sec->soundorg,sfx_stnmov);
            break;
            
          case downWaitUpStay:
@@ -212,9 +202,9 @@ EV_DoPlat
                plat->low = sec->floorheight;
 
            plat->high = sec->floorheight;
-           plat->wait = 35*PLATWAIT;
+           plat->wait = TICRATE*PLATWAIT;
            plat->status = down;
-           S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart);
+           S_StartSound(&sec->soundorg,sfx_pstart);
            break;
            
          case blazeDWUS:
@@ -225,9 +215,9 @@ EV_DoPlat
                plat->low = sec->floorheight;
 
            plat->high = sec->floorheight;
-           plat->wait = 35*PLATWAIT;
+           plat->wait = TICRATE*PLATWAIT;
            plat->status = down;
-           S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart);
+           S_StartSound(&sec->soundorg,sfx_pstart);
            break;
            
          case perpetualRaise:
@@ -242,10 +232,10 @@ EV_DoPlat
            if (plat->high < sec->floorheight)
                plat->high = sec->floorheight;
 
-           plat->wait = 35*PLATWAIT;
+           plat->wait = TICRATE*PLATWAIT;
            plat->status = P_Random()&1;
 
-           S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart);
+           S_StartSound(&sec->soundorg,sfx_pstart);
            break;
        }
        P_AddActivePlat(plat);
index 2ac53b88a1baa443255f2e46d1ff761d5363ca9f..e4774c702f1888358ad0fe1ba3b41a188550330a 100644 (file)
@@ -1,33 +1,27 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Weapon sprite animation, weapon objects.
 //     Action functions for weapons.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: p_pspr.c,v 1.5 1997/02/03 22:45:12 b1 Exp $";
 
 #include "doomdef.h"
 #include "d_event.h"
 
+#include "deh_misc.h"
 
 #include "m_random.h"
 #include "p_local.h"
@@ -48,9 +42,6 @@ rcsid[] = "$Id: p_pspr.c,v 1.5 1997/02/03 22:45:12 b1 Exp $";
 #define WEAPONTOP              32*FRACUNIT
 
 
-// plasma cells for a bfg attack
-#define BFGCELLS               40              
-
 
 //
 // P_SetPsprite
@@ -167,7 +158,7 @@ boolean P_CheckAmmo (player_t* player)
 
     // Minimal amount for one shot varies.
     if (player->readyweapon == wp_bfg)
-       count = BFGCELLS;
+       count = deh_bfg_cells_per_shot;
     else if (player->readyweapon == wp_supershotgun)
        count = 2;      // Double barrel.
     else
@@ -527,7 +518,7 @@ A_Saw
                             linetarget->x, linetarget->y);
     if (angle - player->mo->angle > ANG180)
     {
-       if (angle - player->mo->angle < -ANG90/20)
+       if ((signed int) (angle - player->mo->angle) < -ANG90/20)
            player->mo->angle = angle + ANG90/21;
        else
            player->mo->angle -= ANG90/20;
@@ -542,6 +533,23 @@ A_Saw
     player->mo->flags |= MF_JUSTATTACKED;
 }
 
+// Doom does not check the bounds of the ammo array.  As a result,
+// it is possible to use an ammo type > 4 that overflows into the
+// maxammo array and affects that instead.  Through dehacked, for
+// example, it is possible to make a weapon that decreases the max
+// number of ammo for another weapon.  Emulate this.
+
+static void DecreaseAmmo(player_t *player, int ammonum, int amount)
+{
+    if (ammonum < NUMAMMO)
+    {
+        player->ammo[ammonum] -= amount;
+    }
+    else
+    {
+        player->maxammo[ammonum - NUMAMMO] -= amount;
+    }
+}
 
 
 //
@@ -552,7 +560,7 @@ A_FireMissile
 ( player_t*    player,
   pspdef_t*    psp ) 
 {
-    player->ammo[weaponinfo[player->readyweapon].ammo]--;
+    DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1);
     P_SpawnPlayerMissile (player->mo, MT_ROCKET);
 }
 
@@ -565,7 +573,8 @@ A_FireBFG
 ( player_t*    player,
   pspdef_t*    psp ) 
 {
-    player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS;
+    DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 
+                 deh_bfg_cells_per_shot);
     P_SpawnPlayerMissile (player->mo, MT_BFG);
 }
 
@@ -579,7 +588,7 @@ A_FirePlasma
 ( player_t*    player,
   pspdef_t*    psp ) 
 {
-    player->ammo[weaponinfo[player->readyweapon].ammo]--;
+    DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1);
 
     P_SetPsprite (player,
                  ps_flash,
@@ -651,7 +660,7 @@ A_FirePistol
     S_StartSound (player->mo, sfx_pistol);
 
     P_SetMobjState (player->mo, S_PLAY_ATK2);
-    player->ammo[weaponinfo[player->readyweapon].ammo]--;
+    DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1);
 
     P_SetPsprite (player,
                  ps_flash,
@@ -675,7 +684,7 @@ A_FireShotgun
     S_StartSound (player->mo, sfx_shotgn);
     P_SetMobjState (player->mo, S_PLAY_ATK2);
 
-    player->ammo[weaponinfo[player->readyweapon].ammo]--;
+    DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1);
 
     P_SetPsprite (player,
                  ps_flash,
@@ -705,7 +714,7 @@ A_FireShotgun2
     S_StartSound (player->mo, sfx_dshtgn);
     P_SetMobjState (player->mo, S_PLAY_ATK2);
 
-    player->ammo[weaponinfo[player->readyweapon].ammo]-=2;
+    DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 2);
 
     P_SetPsprite (player,
                  ps_flash,
@@ -740,7 +749,7 @@ A_FireCGun
        return;
                
     P_SetMobjState (player->mo, S_PLAY_ATK2);
-    player->ammo[weaponinfo[player->readyweapon].ammo]--;
+    DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1);
 
     P_SetPsprite (player,
                  ps_flash,
index b76b6cca80d6a7465a4ebca76a52c0a26894732d..f98fe3533569581ab7bea652c595215e865c3471 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //  Sprite animation.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __P_PSPR__
@@ -38,9 +35,6 @@
 // and the Frame Sequence table.
 #include "info.h"
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 
 //
@@ -75,8 +69,3 @@ typedef struct
 } pspdef_t;
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 4500a540bbc2a39a751bfd05c07297b03df2880e..5cb81967a87c5eb9973ecea61b02f35477941cf9 100644 (file)
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
+// 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:
+//     Archiving: SaveGame I/O.
+//
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "dstrings.h"
+#include "deh_main.h"
+#include "i_system.h"
+#include "z_zone.h"
+#include "p_local.h"
+#include "p_saveg.h"
+
+// State.
+#include "doomstat.h"
+#include "g_game.h"
+#include "m_misc.h"
+#include "r_state.h"
+
+#define SAVEGAME_EOF 0x1d
+#define VERSIONSIZE 16 
+
+FILE *save_stream;
+int savegamelength;
+boolean savegame_error;
+
+// Get the filename of a temporary file to write the savegame to.  After
+// the file has been successfully saved, it will be renamed to the 
+// real file.
+
+char *P_TempSaveGameFile(void)
+{
+    static char *filename = NULL;
+
+    if (filename == NULL)
+    {
+        filename = M_StringJoin(savegamedir, "temp.dsg", NULL);
+    }
+
+    return filename;
+}
+
+// Get the filename of the save game file to use for the specified slot.
+
+char *P_SaveGameFile(int slot)
+{
+    static char *filename = NULL;
+    static size_t filename_size = 0;
+    char basename[32];
+
+    if (filename == NULL)
+    {
+        filename_size = strlen(savegamedir) + 32;
+        filename = malloc(filename_size);
+    }
+
+    DEH_snprintf(basename, 32, SAVEGAMENAME "%d.dsg", slot);
+    M_snprintf(filename, filename_size, "%s%s", savegamedir, basename);
+
+    return filename;
+}
+
+// Endian-safe integer read/write functions
+
+static byte saveg_read8(void)
+{
+    byte result;
+
+    if (fread(&result, 1, 1, save_stream) < 1)
+    {
+        if (!savegame_error)
+        {
+            fprintf(stderr, "saveg_read8: Unexpected end of file while "
+                            "reading save game\n");
+
+            savegame_error = true;
+        }
+    }
+
+    return result;
+}
+
+static void saveg_write8(byte value)
+{
+    if (fwrite(&value, 1, 1, save_stream) < 1)
+    {
+        if (!savegame_error)
+        {
+            fprintf(stderr, "saveg_write8: Error while writing save game\n");
+
+            savegame_error = true;
+        }
+    }
+}
+
+static short saveg_read16(void)
+{
+    int result;
+
+    result = saveg_read8();
+    result |= saveg_read8() << 8;
+
+    return result;
+}
+
+static void saveg_write16(short value)
+{
+    saveg_write8(value & 0xff);
+    saveg_write8((value >> 8) & 0xff);
+}
+
+static int saveg_read32(void)
+{
+    int result;
+
+    result = saveg_read8();
+    result |= saveg_read8() << 8;
+    result |= saveg_read8() << 16;
+    result |= saveg_read8() << 24;
+
+    return result;
+}
+
+static void saveg_write32(int value)
+{
+    saveg_write8(value & 0xff);
+    saveg_write8((value >> 8) & 0xff);
+    saveg_write8((value >> 16) & 0xff);
+    saveg_write8((value >> 24) & 0xff);
+}
+
+// Pad to 4-byte boundaries
+
+static void saveg_read_pad(void)
+{
+    unsigned long pos;
+    int padding;
+    int i;
+
+    pos = ftell(save_stream);
+
+    padding = (4 - (pos & 3)) & 3;
+
+    for (i=0; i<padding; ++i)
+    {
+        saveg_read8();
+    }
+}
+
+static void saveg_write_pad(void)
+{
+    unsigned long pos;
+    int padding;
+    int i;
+
+    pos = ftell(save_stream);
+
+    padding = (4 - (pos & 3)) & 3;
+
+    for (i=0; i<padding; ++i)
+    {
+        saveg_write8(0);
+    }
+}
+
+
+// Pointers
+
+static void *saveg_readp(void)
+{
+    return (void *) (intptr_t) saveg_read32();
+}
+
+static void saveg_writep(void *p)
+{
+    saveg_write32((intptr_t) p);
+}
+
+// Enum values are 32-bit integers.
+
+#define saveg_read_enum saveg_read32
+#define saveg_write_enum saveg_write32
+
+//
+// Structure read/write functions
+//
+
+//
+// mapthing_t
+//
+
+static void saveg_read_mapthing_t(mapthing_t *str)
+{
+    // short x;
+    str->x = saveg_read16();
+
+    // short y;
+    str->y = saveg_read16();
+
+    // short angle;
+    str->angle = saveg_read16();
+
+    // short type;
+    str->type = saveg_read16();
+
+    // short options;
+    str->options = saveg_read16();
+}
+
+static void saveg_write_mapthing_t(mapthing_t *str)
+{
+    // short x;
+    saveg_write16(str->x);
+
+    // short y;
+    saveg_write16(str->y);
+
+    // short angle;
+    saveg_write16(str->angle);
+
+    // short type;
+    saveg_write16(str->type);
+
+    // short options;
+    saveg_write16(str->options);
+}
+
+//
+// actionf_t
+// 
+
+static void saveg_read_actionf_t(actionf_t *str)
+{
+    // actionf_p1 acp1;
+    str->acp1 = saveg_readp();
+}
+
+static void saveg_write_actionf_t(actionf_t *str)
+{
+    // actionf_p1 acp1;
+    saveg_writep(str->acp1);
+}
+
+//
+// think_t
+//
+// This is just an actionf_t.
+//
+
+#define saveg_read_think_t saveg_read_actionf_t
+#define saveg_write_think_t saveg_write_actionf_t
+
+//
+// thinker_t
+//
+
+static void saveg_read_thinker_t(thinker_t *str)
+{
+    // struct thinker_s* prev;
+    str->prev = saveg_readp();
+
+    // struct thinker_s* next;
+    str->next = saveg_readp();
+
+    // think_t function;
+    saveg_read_think_t(&str->function);
+}
+
+static void saveg_write_thinker_t(thinker_t *str)
+{
+    // struct thinker_s* prev;
+    saveg_writep(str->prev);
+
+    // struct thinker_s* next;
+    saveg_writep(str->next);
+
+    // think_t function;
+    saveg_write_think_t(&str->function);
+}
+
+//
+// mobj_t
+//
+
+static void saveg_read_mobj_t(mobj_t *str)
+{
+    int pl;
+
+    // thinker_t thinker;
+    saveg_read_thinker_t(&str->thinker);
+
+    // fixed_t x;
+    str->x = saveg_read32();
+
+    // fixed_t y;
+    str->y = saveg_read32();
+
+    // fixed_t z;
+    str->z = saveg_read32();
+
+    // struct mobj_s* snext;
+    str->snext = saveg_readp();
+
+    // struct mobj_s* sprev;
+    str->sprev = saveg_readp();
+
+    // angle_t angle;
+    str->angle = saveg_read32();
+
+    // spritenum_t sprite;
+    str->sprite = saveg_read_enum();
+
+    // int frame;
+    str->frame = saveg_read32();
+
+    // struct mobj_s* bnext;
+    str->bnext = saveg_readp();
+
+    // struct mobj_s* bprev;
+    str->bprev = saveg_readp();
+
+    // struct subsector_s* subsector;
+    str->subsector = saveg_readp();
+
+    // fixed_t floorz;
+    str->floorz = saveg_read32();
+
+    // fixed_t ceilingz;
+    str->ceilingz = saveg_read32();
+
+    // fixed_t radius;
+    str->radius = saveg_read32();
+
+    // fixed_t height;
+    str->height = saveg_read32();
+
+    // fixed_t momx;
+    str->momx = saveg_read32();
+
+    // fixed_t momy;
+    str->momy = saveg_read32();
+
+    // fixed_t momz;
+    str->momz = saveg_read32();
+
+    // int validcount;
+    str->validcount = saveg_read32();
+
+    // mobjtype_t type;
+    str->type = saveg_read_enum();
+
+    // mobjinfo_t* info;
+    str->info = saveg_readp();
+
+    // int tics;
+    str->tics = saveg_read32();
+
+    // state_t* state;
+    str->state = &states[saveg_read32()];
+
+    // int flags;
+    str->flags = saveg_read32();
+
+    // int health;
+    str->health = saveg_read32();
+
+    // int movedir;
+    str->movedir = saveg_read32();
+
+    // int movecount;
+    str->movecount = saveg_read32();
+
+    // struct mobj_s* target;
+    str->target = saveg_readp();
+
+    // int reactiontime;
+    str->reactiontime = saveg_read32();
+
+    // int threshold;
+    str->threshold = saveg_read32();
+
+    // struct player_s* player;
+    pl = saveg_read32();
+
+    if (pl > 0)
+    {
+        str->player = &players[pl - 1];
+        str->player->mo = str;
+    }
+    else
+    {
+        str->player = NULL;
+    }
+
+    // int lastlook;
+    str->lastlook = saveg_read32();
+
+    // mapthing_t spawnpoint;
+    saveg_read_mapthing_t(&str->spawnpoint);
+
+    // struct mobj_s* tracer;
+    str->tracer = saveg_readp();
+}
+
+static void saveg_write_mobj_t(mobj_t *str)
+{
+    // thinker_t thinker;
+    saveg_write_thinker_t(&str->thinker);
+
+    // fixed_t x;
+    saveg_write32(str->x);
+
+    // fixed_t y;
+    saveg_write32(str->y);
+
+    // fixed_t z;
+    saveg_write32(str->z);
+
+    // struct mobj_s* snext;
+    saveg_writep(str->snext);
+
+    // struct mobj_s* sprev;
+    saveg_writep(str->sprev);
+
+    // angle_t angle;
+    saveg_write32(str->angle);
+
+    // spritenum_t sprite;
+    saveg_write_enum(str->sprite);
+
+    // int frame;
+    saveg_write32(str->frame);
+
+    // struct mobj_s* bnext;
+    saveg_writep(str->bnext);
+
+    // struct mobj_s* bprev;
+    saveg_writep(str->bprev);
+
+    // struct subsector_s* subsector;
+    saveg_writep(str->subsector);
+
+    // fixed_t floorz;
+    saveg_write32(str->floorz);
+
+    // fixed_t ceilingz;
+    saveg_write32(str->ceilingz);
+
+    // fixed_t radius;
+    saveg_write32(str->radius);
+
+    // fixed_t height;
+    saveg_write32(str->height);
+
+    // fixed_t momx;
+    saveg_write32(str->momx);
+
+    // fixed_t momy;
+    saveg_write32(str->momy);
+
+    // fixed_t momz;
+    saveg_write32(str->momz);
+
+    // int validcount;
+    saveg_write32(str->validcount);
+
+    // mobjtype_t type;
+    saveg_write_enum(str->type);
+
+    // mobjinfo_t* info;
+    saveg_writep(str->info);
+
+    // int tics;
+    saveg_write32(str->tics);
+
+    // state_t* state;
+    saveg_write32(str->state - states);
+
+    // int flags;
+    saveg_write32(str->flags);
+
+    // int health;
+    saveg_write32(str->health);
+
+    // int movedir;
+    saveg_write32(str->movedir);
+
+    // int movecount;
+    saveg_write32(str->movecount);
+
+    // struct mobj_s* target;
+    saveg_writep(str->target);
+
+    // int reactiontime;
+    saveg_write32(str->reactiontime);
+
+    // int threshold;
+    saveg_write32(str->threshold);
+
+    // struct player_s* player;
+    if (str->player)
+    {
+        saveg_write32(str->player - players + 1);
+    }
+    else
+    {
+        saveg_write32(0);
+    }
+
+    // int lastlook;
+    saveg_write32(str->lastlook);
+
+    // mapthing_t spawnpoint;
+    saveg_write_mapthing_t(&str->spawnpoint);
+
+    // struct mobj_s* tracer;
+    saveg_writep(str->tracer);
+}
+
+
+//
+// ticcmd_t
+//
+
+static void saveg_read_ticcmd_t(ticcmd_t *str)
+{
+
+    // signed char forwardmove;
+    str->forwardmove = saveg_read8();
+
+    // signed char sidemove;
+    str->sidemove = saveg_read8();
+
+    // short angleturn;
+    str->angleturn = saveg_read16();
+
+    // short consistancy;
+    str->consistancy = saveg_read16();
+
+    // byte chatchar;
+    str->chatchar = saveg_read8();
+
+    // byte buttons;
+    str->buttons = saveg_read8();
+}
+
+static void saveg_write_ticcmd_t(ticcmd_t *str)
+{
+
+    // signed char forwardmove;
+    saveg_write8(str->forwardmove);
+
+    // signed char sidemove;
+    saveg_write8(str->sidemove);
+
+    // short angleturn;
+    saveg_write16(str->angleturn);
+
+    // short consistancy;
+    saveg_write16(str->consistancy);
+
+    // byte chatchar;
+    saveg_write8(str->chatchar);
+
+    // byte buttons;
+    saveg_write8(str->buttons);
+}
+
+//
+// pspdef_t
+//
+
+static void saveg_read_pspdef_t(pspdef_t *str)
+{
+    int state;
+
+    // state_t* state;
+    state = saveg_read32();
+
+    if (state > 0)
+    {
+        str->state = &states[state];
+    }
+    else
+    {
+        str->state = NULL;
+    }
+
+    // int tics;
+    str->tics = saveg_read32();
+
+    // fixed_t sx;
+    str->sx = saveg_read32();
+
+    // fixed_t sy;
+    str->sy = saveg_read32();
+}
+
+static void saveg_write_pspdef_t(pspdef_t *str)
+{
+    // state_t* state;
+    if (str->state)
+    {
+        saveg_write32(str->state - states);
+    }
+    else
+    {
+        saveg_write32(0);
+    }
+
+    // int tics;
+    saveg_write32(str->tics);
+
+    // fixed_t sx;
+    saveg_write32(str->sx);
+
+    // fixed_t sy;
+    saveg_write32(str->sy);
+}
+
+//
+// player_t
+//
+
+static void saveg_read_player_t(player_t *str)
+{
+    int i;
+
+    // mobj_t* mo;
+    str->mo = saveg_readp();
+
+    // playerstate_t playerstate;
+    str->playerstate = saveg_read_enum();
+
+    // ticcmd_t cmd;
+    saveg_read_ticcmd_t(&str->cmd);
+
+    // fixed_t viewz;
+    str->viewz = saveg_read32();
+
+    // fixed_t viewheight;
+    str->viewheight = saveg_read32();
+
+    // fixed_t deltaviewheight;
+    str->deltaviewheight = saveg_read32();
+
+    // fixed_t bob;
+    str->bob = saveg_read32();
+
+    // int health;
+    str->health = saveg_read32();
+
+    // int armorpoints;
+    str->armorpoints = saveg_read32();
+
+    // int armortype;
+    str->armortype = saveg_read32();
+
+    // int powers[NUMPOWERS];
+    for (i=0; i<NUMPOWERS; ++i)
+    {
+        str->powers[i] = saveg_read32();
+    }
+
+    // boolean cards[NUMCARDS];
+    for (i=0; i<NUMCARDS; ++i)
+    {
+        str->cards[i] = saveg_read32();
+    }
+
+    // boolean backpack;
+    str->backpack = saveg_read32();
+
+    // int frags[MAXPLAYERS];
+    for (i=0; i<MAXPLAYERS; ++i)
+    {
+        str->frags[i] = saveg_read32();
+    }
+
+    // weapontype_t readyweapon;
+    str->readyweapon = saveg_read_enum();
+
+    // weapontype_t pendingweapon;
+    str->pendingweapon = saveg_read_enum();
+
+    // boolean weaponowned[NUMWEAPONS];
+    for (i=0; i<NUMWEAPONS; ++i)
+    {
+        str->weaponowned[i] = saveg_read32();
+    }
+
+    // int ammo[NUMAMMO];
+    for (i=0; i<NUMAMMO; ++i)
+    {
+        str->ammo[i] = saveg_read32();
+    }
+
+    // int maxammo[NUMAMMO];
+    for (i=0; i<NUMAMMO; ++i)
+    {
+        str->maxammo[i] = saveg_read32();
+    }
+
+    // int attackdown;
+    str->attackdown = saveg_read32();
+
+    // int usedown;
+    str->usedown = saveg_read32();
+
+    // int cheats;
+    str->cheats = saveg_read32();
+
+    // int refire;
+    str->refire = saveg_read32();
+
+    // int killcount;
+    str->killcount = saveg_read32();
+
+    // int itemcount;
+    str->itemcount = saveg_read32();
+
+    // int secretcount;
+    str->secretcount = saveg_read32();
+
+    // char* message;
+    str->message = saveg_readp();
+
+    // int damagecount;
+    str->damagecount = saveg_read32();
+
+    // int bonuscount;
+    str->bonuscount = saveg_read32();
+
+    // mobj_t* attacker;
+    str->attacker = saveg_readp();
+
+    // int extralight;
+    str->extralight = saveg_read32();
+
+    // int fixedcolormap;
+    str->fixedcolormap = saveg_read32();
+
+    // int colormap;
+    str->colormap = saveg_read32();
+
+    // pspdef_t psprites[NUMPSPRITES];
+    for (i=0; i<NUMPSPRITES; ++i)
+    {
+        saveg_read_pspdef_t(&str->psprites[i]);
+    }
+
+    // boolean didsecret;
+    str->didsecret = saveg_read32();
+}
+
+static void saveg_write_player_t(player_t *str)
+{
+    int i;
+
+    // mobj_t* mo;
+    saveg_writep(str->mo);
+
+    // playerstate_t playerstate;
+    saveg_write_enum(str->playerstate);
+
+    // ticcmd_t cmd;
+    saveg_write_ticcmd_t(&str->cmd);
+
+    // fixed_t viewz;
+    saveg_write32(str->viewz);
+
+    // fixed_t viewheight;
+    saveg_write32(str->viewheight);
+
+    // fixed_t deltaviewheight;
+    saveg_write32(str->deltaviewheight);
+
+    // fixed_t bob;
+    saveg_write32(str->bob);
+
+    // int health;
+    saveg_write32(str->health);
+
+    // int armorpoints;
+    saveg_write32(str->armorpoints);
+
+    // int armortype;
+    saveg_write32(str->armortype);
+
+    // int powers[NUMPOWERS];
+    for (i=0; i<NUMPOWERS; ++i)
+    {
+        saveg_write32(str->powers[i]);
+    }
+
+    // boolean cards[NUMCARDS];
+    for (i=0; i<NUMCARDS; ++i)
+    {
+        saveg_write32(str->cards[i]);
+    }
+
+    // boolean backpack;
+    saveg_write32(str->backpack);
+
+    // int frags[MAXPLAYERS];
+    for (i=0; i<MAXPLAYERS; ++i)
+    {
+        saveg_write32(str->frags[i]);
+    }
+
+    // weapontype_t readyweapon;
+    saveg_write_enum(str->readyweapon);
+
+    // weapontype_t pendingweapon;
+    saveg_write_enum(str->pendingweapon);
+
+    // boolean weaponowned[NUMWEAPONS];
+    for (i=0; i<NUMWEAPONS; ++i)
+    {
+        saveg_write32(str->weaponowned[i]);
+    }
+
+    // int ammo[NUMAMMO];
+    for (i=0; i<NUMAMMO; ++i)
+    {
+        saveg_write32(str->ammo[i]);
+    }
+
+    // int maxammo[NUMAMMO];
+    for (i=0; i<NUMAMMO; ++i)
+    {
+        saveg_write32(str->maxammo[i]);
+    }
+
+    // int attackdown;
+    saveg_write32(str->attackdown);
+
+    // int usedown;
+    saveg_write32(str->usedown);
+
+    // int cheats;
+    saveg_write32(str->cheats);
+
+    // int refire;
+    saveg_write32(str->refire);
+
+    // int killcount;
+    saveg_write32(str->killcount);
+
+    // int itemcount;
+    saveg_write32(str->itemcount);
+
+    // int secretcount;
+    saveg_write32(str->secretcount);
+
+    // char* message;
+    saveg_writep(str->message);
+
+    // int damagecount;
+    saveg_write32(str->damagecount);
+
+    // int bonuscount;
+    saveg_write32(str->bonuscount);
+
+    // mobj_t* attacker;
+    saveg_writep(str->attacker);
+
+    // int extralight;
+    saveg_write32(str->extralight);
+
+    // int fixedcolormap;
+    saveg_write32(str->fixedcolormap);
+
+    // int colormap;
+    saveg_write32(str->colormap);
+
+    // pspdef_t psprites[NUMPSPRITES];
+    for (i=0; i<NUMPSPRITES; ++i)
+    {
+        saveg_write_pspdef_t(&str->psprites[i]);
+    }
+
+    // boolean didsecret;
+    saveg_write32(str->didsecret);
+}
+
+
 //
-// The source is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// ceiling_t
 //
-// $Log:$
+
+static void saveg_read_ceiling_t(ceiling_t *str)
+{
+    int sector;
+
+    // thinker_t thinker;
+    saveg_read_thinker_t(&str->thinker);
+
+    // ceiling_e type;
+    str->type = saveg_read_enum();
+
+    // sector_t* sector;
+    sector = saveg_read32();
+    str->sector = &sectors[sector];
+
+    // fixed_t bottomheight;
+    str->bottomheight = saveg_read32();
+
+    // fixed_t topheight;
+    str->topheight = saveg_read32();
+
+    // fixed_t speed;
+    str->speed = saveg_read32();
+
+    // boolean crush;
+    str->crush = saveg_read32();
+
+    // int direction;
+    str->direction = saveg_read32();
+
+    // int tag;
+    str->tag = saveg_read32();
+
+    // int olddirection;
+    str->olddirection = saveg_read32();
+}
+
+static void saveg_write_ceiling_t(ceiling_t *str)
+{
+    // thinker_t thinker;
+    saveg_write_thinker_t(&str->thinker);
+
+    // ceiling_e type;
+    saveg_write_enum(str->type);
+
+    // sector_t* sector;
+    saveg_write32(str->sector - sectors);
+
+    // fixed_t bottomheight;
+    saveg_write32(str->bottomheight);
+
+    // fixed_t topheight;
+    saveg_write32(str->topheight);
+
+    // fixed_t speed;
+    saveg_write32(str->speed);
+
+    // boolean crush;
+    saveg_write32(str->crush);
+
+    // int direction;
+    saveg_write32(str->direction);
+
+    // int tag;
+    saveg_write32(str->tag);
+
+    // int olddirection;
+    saveg_write32(str->olddirection);
+}
+
 //
-// DESCRIPTION:
-//     Archiving: SaveGame I/O.
+// vldoor_t
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: p_tick.c,v 1.4 1997/02/03 16:47:55 b1 Exp $";
+static void saveg_read_vldoor_t(vldoor_t *str)
+{
+    int sector;
 
-#include "i_system.h"
-#include "z_zone.h"
-#include "p_local.h"
+    // thinker_t thinker;
+    saveg_read_thinker_t(&str->thinker);
 
-// State.
-#include "doomstat.h"
-#include "r_state.h"
+    // vldoor_e type;
+    str->type = saveg_read_enum();
+
+    // sector_t* sector;
+    sector = saveg_read32();
+    str->sector = &sectors[sector];
+
+    // fixed_t topheight;
+    str->topheight = saveg_read32();
+
+    // fixed_t speed;
+    str->speed = saveg_read32();
+
+    // int direction;
+    str->direction = saveg_read32();
+
+    // int topwait;
+    str->topwait = saveg_read32();
+
+    // int topcountdown;
+    str->topcountdown = saveg_read32();
+}
+
+static void saveg_write_vldoor_t(vldoor_t *str)
+{
+    // thinker_t thinker;
+    saveg_write_thinker_t(&str->thinker);
+
+    // vldoor_e type;
+    saveg_write_enum(str->type);
+
+    // sector_t* sector;
+    saveg_write32(str->sector - sectors);
+
+    // fixed_t topheight;
+    saveg_write32(str->topheight);
+
+    // fixed_t speed;
+    saveg_write32(str->speed);
+
+    // int direction;
+    saveg_write32(str->direction);
+
+    // int topwait;
+    saveg_write32(str->topwait);
+
+    // int topcountdown;
+    saveg_write32(str->topcountdown);
+}
+
+//
+// floormove_t
+//
+
+static void saveg_read_floormove_t(floormove_t *str)
+{
+    int sector;
+
+    // thinker_t thinker;
+    saveg_read_thinker_t(&str->thinker);
+
+    // floor_e type;
+    str->type = saveg_read_enum();
+
+    // boolean crush;
+    str->crush = saveg_read32();
+
+    // sector_t* sector;
+    sector = saveg_read32();
+    str->sector = &sectors[sector];
+
+    // int direction;
+    str->direction = saveg_read32();
+
+    // int newspecial;
+    str->newspecial = saveg_read32();
+
+    // short texture;
+    str->texture = saveg_read16();
+
+    // fixed_t floordestheight;
+    str->floordestheight = saveg_read32();
+
+    // fixed_t speed;
+    str->speed = saveg_read32();
+}
+
+static void saveg_write_floormove_t(floormove_t *str)
+{
+    // thinker_t thinker;
+    saveg_write_thinker_t(&str->thinker);
+
+    // floor_e type;
+    saveg_write_enum(str->type);
+
+    // boolean crush;
+    saveg_write32(str->crush);
+
+    // sector_t* sector;
+    saveg_write32(str->sector - sectors);
+
+    // int direction;
+    saveg_write32(str->direction);
+
+    // int newspecial;
+    saveg_write32(str->newspecial);
+
+    // short texture;
+    saveg_write16(str->texture);
+
+    // fixed_t floordestheight;
+    saveg_write32(str->floordestheight);
+
+    // fixed_t speed;
+    saveg_write32(str->speed);
+}
+
+//
+// plat_t
+//
+
+static void saveg_read_plat_t(plat_t *str)
+{
+    int sector;
+
+    // thinker_t thinker;
+    saveg_read_thinker_t(&str->thinker);
+
+    // sector_t* sector;
+    sector = saveg_read32();
+    str->sector = &sectors[sector];
+
+    // fixed_t speed;
+    str->speed = saveg_read32();
+
+    // fixed_t low;
+    str->low = saveg_read32();
+
+    // fixed_t high;
+    str->high = saveg_read32();
+
+    // int wait;
+    str->wait = saveg_read32();
+
+    // int count;
+    str->count = saveg_read32();
+
+    // plat_e status;
+    str->status = saveg_read_enum();
+
+    // plat_e oldstatus;
+    str->oldstatus = saveg_read_enum();
+
+    // boolean crush;
+    str->crush = saveg_read32();
+
+    // int tag;
+    str->tag = saveg_read32();
+
+    // plattype_e type;
+    str->type = saveg_read_enum();
+}
+
+static void saveg_write_plat_t(plat_t *str)
+{
+    // thinker_t thinker;
+    saveg_write_thinker_t(&str->thinker);
+
+    // sector_t* sector;
+    saveg_write32(str->sector - sectors);
+
+    // fixed_t speed;
+    saveg_write32(str->speed);
+
+    // fixed_t low;
+    saveg_write32(str->low);
+
+    // fixed_t high;
+    saveg_write32(str->high);
+
+    // int wait;
+    saveg_write32(str->wait);
+
+    // int count;
+    saveg_write32(str->count);
+
+    // plat_e status;
+    saveg_write_enum(str->status);
+
+    // plat_e oldstatus;
+    saveg_write_enum(str->oldstatus);
+
+    // boolean crush;
+    saveg_write32(str->crush);
+
+    // int tag;
+    saveg_write32(str->tag);
 
-byte*          save_p;
+    // plattype_e type;
+    saveg_write_enum(str->type);
+}
+
+//
+// lightflash_t
+//
+
+static void saveg_read_lightflash_t(lightflash_t *str)
+{
+    int sector;
+
+    // thinker_t thinker;
+    saveg_read_thinker_t(&str->thinker);
+
+    // sector_t* sector;
+    sector = saveg_read32();
+    str->sector = &sectors[sector];
+
+    // int count;
+    str->count = saveg_read32();
+
+    // int maxlight;
+    str->maxlight = saveg_read32();
+
+    // int minlight;
+    str->minlight = saveg_read32();
+
+    // int maxtime;
+    str->maxtime = saveg_read32();
+
+    // int mintime;
+    str->mintime = saveg_read32();
+}
+
+static void saveg_write_lightflash_t(lightflash_t *str)
+{
+    // thinker_t thinker;
+    saveg_write_thinker_t(&str->thinker);
+
+    // sector_t* sector;
+    saveg_write32(str->sector - sectors);
+
+    // int count;
+    saveg_write32(str->count);
+
+    // int maxlight;
+    saveg_write32(str->maxlight);
+
+    // int minlight;
+    saveg_write32(str->minlight);
+
+    // int maxtime;
+    saveg_write32(str->maxtime);
+
+    // int mintime;
+    saveg_write32(str->mintime);
+}
+
+//
+// strobe_t
+//
+
+static void saveg_read_strobe_t(strobe_t *str)
+{
+    int sector;
+
+    // thinker_t thinker;
+    saveg_read_thinker_t(&str->thinker);
+
+    // sector_t* sector;
+    sector = saveg_read32();
+    str->sector = &sectors[sector];
+
+    // int count;
+    str->count = saveg_read32();
+
+    // int minlight;
+    str->minlight = saveg_read32();
+
+    // int maxlight;
+    str->maxlight = saveg_read32();
+
+    // int darktime;
+    str->darktime = saveg_read32();
+
+    // int brighttime;
+    str->brighttime = saveg_read32();
+}
+
+static void saveg_write_strobe_t(strobe_t *str)
+{
+    // thinker_t thinker;
+    saveg_write_thinker_t(&str->thinker);
+
+    // sector_t* sector;
+    saveg_write32(str->sector - sectors);
+
+    // int count;
+    saveg_write32(str->count);
+
+    // int minlight;
+    saveg_write32(str->minlight);
+
+    // int maxlight;
+    saveg_write32(str->maxlight);
+
+    // int darktime;
+    saveg_write32(str->darktime);
+
+    // int brighttime;
+    saveg_write32(str->brighttime);
+}
+
+//
+// glow_t
+//
+
+static void saveg_read_glow_t(glow_t *str)
+{
+    int sector;
+
+    // thinker_t thinker;
+    saveg_read_thinker_t(&str->thinker);
+
+    // sector_t* sector;
+    sector = saveg_read32();
+    str->sector = &sectors[sector];
+
+    // int minlight;
+    str->minlight = saveg_read32();
+
+    // int maxlight;
+    str->maxlight = saveg_read32();
+
+    // int direction;
+    str->direction = saveg_read32();
+}
+
+static void saveg_write_glow_t(glow_t *str)
+{
+    // thinker_t thinker;
+    saveg_write_thinker_t(&str->thinker);
+
+    // sector_t* sector;
+    saveg_write32(str->sector - sectors);
+
+    // int minlight;
+    saveg_write32(str->minlight);
+
+    // int maxlight;
+    saveg_write32(str->maxlight);
+
+    // int direction;
+    saveg_write32(str->direction);
+}
+
+//
+// Write the header for a savegame
+//
+
+void P_WriteSaveGameHeader(char *description)
+{
+    char name[VERSIONSIZE]; 
+    int i; 
+       
+    for (i=0; description[i] != '\0'; ++i)
+        saveg_write8(description[i]);
+    for (; i<SAVESTRINGSIZE; ++i)
+        saveg_write8(0);
+
+    memset(name, 0, sizeof(name));
+    M_snprintf(name, sizeof(name), "version %i", G_VanillaVersionCode());
+
+    for (i=0; i<VERSIONSIZE; ++i)
+        saveg_write8(name[i]);
+        
+    saveg_write8(gameskill);
+    saveg_write8(gameepisode);
+    saveg_write8(gamemap);
+
+    for (i=0 ; i<MAXPLAYERS ; i++) 
+        saveg_write8(playeringame[i]);
+
+    saveg_write8((leveltime >> 16) & 0xff);
+    saveg_write8((leveltime >> 8) & 0xff);
+    saveg_write8(leveltime & 0xff);
+}
+
+// 
+// Read the header for a savegame
+//
+
+boolean P_ReadSaveGameHeader(void)
+{
+    int         i; 
+    byte a, b, c; 
+    char vcheck[VERSIONSIZE]; 
+    char read_vcheck[VERSIONSIZE];
+        
+    // skip the description field 
+
+    for (i=0; i<SAVESTRINGSIZE; ++i)
+        saveg_read8();
+    
+    for (i=0; i<VERSIONSIZE; ++i)
+        read_vcheck[i] = saveg_read8();
 
+    memset(vcheck, 0, sizeof(vcheck));
+    M_snprintf(vcheck, sizeof(vcheck), "version %i", G_VanillaVersionCode());
+    if (strcmp(read_vcheck, vcheck) != 0)
+       return false;                           // bad version 
 
-// Pads save_p to a 4-byte boundary
-//  so that the load/save works on SGI&Gecko.
-#define PADSAVEP()     save_p += (4 - ((int) save_p & 3)) & 3
+    gameskill = saveg_read8();
+    gameepisode = saveg_read8();
+    gamemap = saveg_read8();
 
+    for (i=0 ; i<MAXPLAYERS ; i++) 
+       playeringame[i] = saveg_read8();
 
+    // get the times 
+    a = saveg_read8();
+    b = saveg_read8();
+    c = saveg_read8();
+    leveltime = (a<<16) + (b<<8) + c; 
+
+    return true;
+}
+
+//
+// Read the end of file marker.  Returns true if read successfully.
+// 
+
+boolean P_ReadSaveGameEOF(void)
+{
+    int value;
+
+    value = saveg_read8();
+
+    return value == SAVEGAME_EOF;
+}
+
+//
+// Write the end of file marker
+//
+
+void P_WriteSaveGameEOF(void)
+{
+    saveg_write8(SAVEGAME_EOF);
+}
 
 //
 // P_ArchivePlayers
@@ -47,27 +1440,15 @@ byte*             save_p;
 void P_ArchivePlayers (void)
 {
     int                i;
-    int                j;
-    player_t*  dest;
                
     for (i=0 ; i<MAXPLAYERS ; i++)
     {
        if (!playeringame[i])
            continue;
        
-       PADSAVEP();
+       saveg_write_pad();
 
-       dest = (player_t *)save_p;
-       memcpy (dest,&players[i],sizeof(player_t));
-       save_p += sizeof(player_t);
-       for (j=0 ; j<NUMPSPRITES ; j++)
-       {
-           if (dest->psprites[j].state)
-           {
-               dest->psprites[j].state 
-                   = (state_t *)(dest->psprites[j].state-states);
-           }
-       }
+        saveg_write_player_t(&players[i]);
     }
 }
 
@@ -79,31 +1460,20 @@ void P_ArchivePlayers (void)
 void P_UnArchivePlayers (void)
 {
     int                i;
-    int                j;
        
     for (i=0 ; i<MAXPLAYERS ; i++)
     {
        if (!playeringame[i])
            continue;
        
-       PADSAVEP();
+       saveg_read_pad();
 
-       memcpy (&players[i],save_p, sizeof(player_t));
-       save_p += sizeof(player_t);
+        saveg_read_player_t(&players[i]);
        
        // will be set when unarc thinker
        players[i].mo = NULL;   
        players[i].message = NULL;
        players[i].attacker = NULL;
-
-       for (j=0 ; j<NUMPSPRITES ; j++)
-       {
-           if (players[i]. psprites[j].state)
-           {
-               players[i]. psprites[j].state 
-                   = &states[ (int)players[i].psprites[j].state ];
-           }
-       }
     }
 }
 
@@ -118,29 +1488,26 @@ void P_ArchiveWorld (void)
     sector_t*          sec;
     line_t*            li;
     side_t*            si;
-    short*             put;
-       
-    put = (short *)save_p;
     
     // do sectors
     for (i=0, sec = sectors ; i<numsectors ; i++,sec++)
     {
-       *put++ = sec->floorheight >> FRACBITS;
-       *put++ = sec->ceilingheight >> FRACBITS;
-       *put++ = sec->floorpic;
-       *put++ = sec->ceilingpic;
-       *put++ = sec->lightlevel;
-       *put++ = sec->special;          // needed?
-       *put++ = sec->tag;              // needed?
+       saveg_write16(sec->floorheight >> FRACBITS);
+       saveg_write16(sec->ceilingheight >> FRACBITS);
+       saveg_write16(sec->floorpic);
+       saveg_write16(sec->ceilingpic);
+       saveg_write16(sec->lightlevel);
+       saveg_write16(sec->special);            // needed?
+       saveg_write16(sec->tag);                // needed?
     }
 
     
     // do lines
     for (i=0, li = lines ; i<numlines ; i++,li++)
     {
-       *put++ = li->flags;
-       *put++ = li->special;
-       *put++ = li->tag;
+       saveg_write16(li->flags);
+       saveg_write16(li->special);
+       saveg_write16(li->tag);
        for (j=0 ; j<2 ; j++)
        {
            if (li->sidenum[j] == -1)
@@ -148,15 +1515,13 @@ void P_ArchiveWorld (void)
            
            si = &sides[li->sidenum[j]];
 
-           *put++ = si->textureoffset >> FRACBITS;
-           *put++ = si->rowoffset >> FRACBITS;
-           *put++ = si->toptexture;
-           *put++ = si->bottomtexture;
-           *put++ = si->midtexture;    
+           saveg_write16(si->textureoffset >> FRACBITS);
+           saveg_write16(si->rowoffset >> FRACBITS);
+           saveg_write16(si->toptexture);
+           saveg_write16(si->bottomtexture);
+           saveg_write16(si->midtexture);      
        }
     }
-       
-    save_p = (byte *)put;
 }
 
 
@@ -171,20 +1536,17 @@ void P_UnArchiveWorld (void)
     sector_t*          sec;
     line_t*            li;
     side_t*            si;
-    short*             get;
-       
-    get = (short *)save_p;
     
     // do sectors
     for (i=0, sec = sectors ; i<numsectors ; i++,sec++)
     {
-       sec->floorheight = *get++ << FRACBITS;
-       sec->ceilingheight = *get++ << FRACBITS;
-       sec->floorpic = *get++;
-       sec->ceilingpic = *get++;
-       sec->lightlevel = *get++;
-       sec->special = *get++;          // needed?
-       sec->tag = *get++;              // needed?
+       sec->floorheight = saveg_read16() << FRACBITS;
+       sec->ceilingheight = saveg_read16() << FRACBITS;
+       sec->floorpic = saveg_read16();
+       sec->ceilingpic = saveg_read16();
+       sec->lightlevel = saveg_read16();
+       sec->special = saveg_read16();          // needed?
+       sec->tag = saveg_read16();              // needed?
        sec->specialdata = 0;
        sec->soundtarget = 0;
     }
@@ -192,22 +1554,21 @@ void P_UnArchiveWorld (void)
     // do lines
     for (i=0, li = lines ; i<numlines ; i++,li++)
     {
-       li->flags = *get++;
-       li->special = *get++;
-       li->tag = *get++;
+       li->flags = saveg_read16();
+       li->special = saveg_read16();
+       li->tag = saveg_read16();
        for (j=0 ; j<2 ; j++)
        {
            if (li->sidenum[j] == -1)
                continue;
            si = &sides[li->sidenum[j]];
-           si->textureoffset = *get++ << FRACBITS;
-           si->rowoffset = *get++ << FRACBITS;
-           si->toptexture = *get++;
-           si->bottomtexture = *get++;
-           si->midtexture = *get++;
+           si->textureoffset = saveg_read16() << FRACBITS;
+           si->rowoffset = saveg_read16() << FRACBITS;
+           si->toptexture = saveg_read16();
+           si->bottomtexture = saveg_read16();
+           si->midtexture = saveg_read16();
        }
     }
-    save_p = (byte *)get;      
 }
 
 
@@ -225,29 +1586,22 @@ typedef enum
 } thinkerclass_t;
 
 
-
 //
 // P_ArchiveThinkers
 //
 void P_ArchiveThinkers (void)
 {
     thinker_t*         th;
-    mobj_t*            mobj;
-       
+
     // save off the current thinkers
     for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
     {
        if (th->function.acp1 == (actionf_p1)P_MobjThinker)
        {
-           *save_p++ = tc_mobj;
-           PADSAVEP();
-           mobj = (mobj_t *)save_p;
-           memcpy (mobj, th, sizeof(*mobj));
-           save_p += sizeof(*mobj);
-           mobj->state = (state_t *)(mobj->state - states);
-           
-           if (mobj->player)
-               mobj->player = (player_t *)((mobj->player-players) + 1);
+            saveg_write8(tc_mobj);
+           saveg_write_pad();
+            saveg_write_mobj_t((mobj_t *) th);
+
            continue;
        }
                
@@ -255,7 +1609,7 @@ void P_ArchiveThinkers (void)
     }
 
     // add a terminating marker
-    *save_p++ = tc_end;        
+    saveg_write8(tc_end);
 }
 
 
@@ -284,28 +1638,23 @@ void P_UnArchiveThinkers (void)
        currentthinker = next;
     }
     P_InitThinkers ();
-       
+    
     // read in saved thinkers
     while (1)
     {
-       tclass = *save_p++;
+       tclass = saveg_read8();
        switch (tclass)
        {
          case tc_end:
            return;     // end of list
                        
          case tc_mobj:
-           PADSAVEP();
+           saveg_read_pad();
            mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL);
-           memcpy (mobj, save_p, sizeof(*mobj));
-           save_p += sizeof(*mobj);
-           mobj->state = &states[(int)mobj->state];
+            saveg_read_mobj_t(mobj);
+
            mobj->target = NULL;
-           if (mobj->player)
-           {
-               mobj->player = &players[(int)mobj->player-1];
-               mobj->player->mo = mobj;
-           }
+            mobj->tracer = NULL;
            P_SetThingPosition (mobj);
            mobj->info = &mobjinfo[mobj->type];
            mobj->floorz = mobj->subsector->sector->floorheight;
@@ -313,7 +1662,7 @@ void P_UnArchiveThinkers (void)
            mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
            P_AddThinker (&mobj->thinker);
            break;
-                       
+
          default:
            I_Error ("Unknown tclass %i in savegame",tclass);
        }
@@ -355,13 +1704,6 @@ enum
 void P_ArchiveSpecials (void)
 {
     thinker_t*         th;
-    ceiling_t*         ceiling;
-    vldoor_t*          door;
-    floormove_t*       floor;
-    plat_t*            plat;
-    lightflash_t*      flash;
-    strobe_t*          strobe;
-    glow_t*            glow;
     int                        i;
        
     // save off the current thinkers
@@ -375,96 +1717,72 @@ void P_ArchiveSpecials (void)
            
            if (i<MAXCEILINGS)
            {
-               *save_p++ = tc_ceiling;
-               PADSAVEP();
-               ceiling = (ceiling_t *)save_p;
-               memcpy (ceiling, th, sizeof(*ceiling));
-               save_p += sizeof(*ceiling);
-               ceiling->sector = (sector_t *)(ceiling->sector - sectors);
+                saveg_write8(tc_ceiling);
+               saveg_write_pad();
+                saveg_write_ceiling_t((ceiling_t *) th);
            }
            continue;
        }
                        
        if (th->function.acp1 == (actionf_p1)T_MoveCeiling)
        {
-           *save_p++ = tc_ceiling;
-           PADSAVEP();
-           ceiling = (ceiling_t *)save_p;
-           memcpy (ceiling, th, sizeof(*ceiling));
-           save_p += sizeof(*ceiling);
-           ceiling->sector = (sector_t *)(ceiling->sector - sectors);
+            saveg_write8(tc_ceiling);
+           saveg_write_pad();
+            saveg_write_ceiling_t((ceiling_t *) th);
            continue;
        }
                        
        if (th->function.acp1 == (actionf_p1)T_VerticalDoor)
        {
-           *save_p++ = tc_door;
-           PADSAVEP();
-           door = (vldoor_t *)save_p;
-           memcpy (door, th, sizeof(*door));
-           save_p += sizeof(*door);
-           door->sector = (sector_t *)(door->sector - sectors);
+            saveg_write8(tc_door);
+           saveg_write_pad();
+            saveg_write_vldoor_t((vldoor_t *) th);
            continue;
        }
                        
        if (th->function.acp1 == (actionf_p1)T_MoveFloor)
        {
-           *save_p++ = tc_floor;
-           PADSAVEP();
-           floor = (floormove_t *)save_p;
-           memcpy (floor, th, sizeof(*floor));
-           save_p += sizeof(*floor);
-           floor->sector = (sector_t *)(floor->sector - sectors);
+            saveg_write8(tc_floor);
+           saveg_write_pad();
+            saveg_write_floormove_t((floormove_t *) th);
            continue;
        }
                        
        if (th->function.acp1 == (actionf_p1)T_PlatRaise)
        {
-           *save_p++ = tc_plat;
-           PADSAVEP();
-           plat = (plat_t *)save_p;
-           memcpy (plat, th, sizeof(*plat));
-           save_p += sizeof(*plat);
-           plat->sector = (sector_t *)(plat->sector - sectors);
+            saveg_write8(tc_plat);
+           saveg_write_pad();
+            saveg_write_plat_t((plat_t *) th);
            continue;
        }
                        
        if (th->function.acp1 == (actionf_p1)T_LightFlash)
        {
-           *save_p++ = tc_flash;
-           PADSAVEP();
-           flash = (lightflash_t *)save_p;
-           memcpy (flash, th, sizeof(*flash));
-           save_p += sizeof(*flash);
-           flash->sector = (sector_t *)(flash->sector - sectors);
+            saveg_write8(tc_flash);
+           saveg_write_pad();
+            saveg_write_lightflash_t((lightflash_t *) th);
            continue;
        }
                        
        if (th->function.acp1 == (actionf_p1)T_StrobeFlash)
        {
-           *save_p++ = tc_strobe;
-           PADSAVEP();
-           strobe = (strobe_t *)save_p;
-           memcpy (strobe, th, sizeof(*strobe));
-           save_p += sizeof(*strobe);
-           strobe->sector = (sector_t *)(strobe->sector - sectors);
+            saveg_write8(tc_strobe);
+           saveg_write_pad();
+            saveg_write_strobe_t((strobe_t *) th);
            continue;
        }
                        
        if (th->function.acp1 == (actionf_p1)T_Glow)
        {
-           *save_p++ = tc_glow;
-           PADSAVEP();
-           glow = (glow_t *)save_p;
-           memcpy (glow, th, sizeof(*glow));
-           save_p += sizeof(*glow);
-           glow->sector = (sector_t *)(glow->sector - sectors);
+            saveg_write8(tc_glow);
+           saveg_write_pad();
+            saveg_write_glow_t((glow_t *) th);
            continue;
        }
     }
        
     // add a terminating marker
-    *save_p++ = tc_endspecials;        
+    saveg_write8(tc_endspecials);
 
 }
 
@@ -487,18 +1805,17 @@ void P_UnArchiveSpecials (void)
     // read in saved thinkers
     while (1)
     {
-       tclass = *save_p++;
+       tclass = saveg_read8();
+
        switch (tclass)
        {
          case tc_endspecials:
            return;     // end of list
                        
          case tc_ceiling:
-           PADSAVEP();
+           saveg_read_pad();
            ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVEL, NULL);
-           memcpy (ceiling, save_p, sizeof(*ceiling));
-           save_p += sizeof(*ceiling);
-           ceiling->sector = &sectors[(int)ceiling->sector];
+            saveg_read_ceiling_t(ceiling);
            ceiling->sector->specialdata = ceiling;
 
            if (ceiling->thinker.function.acp1)
@@ -509,33 +1826,27 @@ void P_UnArchiveSpecials (void)
            break;
                                
          case tc_door:
-           PADSAVEP();
+           saveg_read_pad();
            door = Z_Malloc (sizeof(*door), PU_LEVEL, NULL);
-           memcpy (door, save_p, sizeof(*door));
-           save_p += sizeof(*door);
-           door->sector = &sectors[(int)door->sector];
+            saveg_read_vldoor_t(door);
            door->sector->specialdata = door;
            door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
            P_AddThinker (&door->thinker);
            break;
                                
          case tc_floor:
-           PADSAVEP();
+           saveg_read_pad();
            floor = Z_Malloc (sizeof(*floor), PU_LEVEL, NULL);
-           memcpy (floor, save_p, sizeof(*floor));
-           save_p += sizeof(*floor);
-           floor->sector = &sectors[(int)floor->sector];
+            saveg_read_floormove_t(floor);
            floor->sector->specialdata = floor;
            floor->thinker.function.acp1 = (actionf_p1)T_MoveFloor;
            P_AddThinker (&floor->thinker);
            break;
                                
          case tc_plat:
-           PADSAVEP();
+           saveg_read_pad();
            plat = Z_Malloc (sizeof(*plat), PU_LEVEL, NULL);
-           memcpy (plat, save_p, sizeof(*plat));
-           save_p += sizeof(*plat);
-           plat->sector = &sectors[(int)plat->sector];
+            saveg_read_plat_t(plat);
            plat->sector->specialdata = plat;
 
            if (plat->thinker.function.acp1)
@@ -546,31 +1857,25 @@ void P_UnArchiveSpecials (void)
            break;
                                
          case tc_flash:
-           PADSAVEP();
+           saveg_read_pad();
            flash = Z_Malloc (sizeof(*flash), PU_LEVEL, NULL);
-           memcpy (flash, save_p, sizeof(*flash));
-           save_p += sizeof(*flash);
-           flash->sector = &sectors[(int)flash->sector];
+            saveg_read_lightflash_t(flash);
            flash->thinker.function.acp1 = (actionf_p1)T_LightFlash;
            P_AddThinker (&flash->thinker);
            break;
                                
          case tc_strobe:
-           PADSAVEP();
+           saveg_read_pad();
            strobe = Z_Malloc (sizeof(*strobe), PU_LEVEL, NULL);
-           memcpy (strobe, save_p, sizeof(*strobe));
-           save_p += sizeof(*strobe);
-           strobe->sector = &sectors[(int)strobe->sector];
+            saveg_read_strobe_t(strobe);
            strobe->thinker.function.acp1 = (actionf_p1)T_StrobeFlash;
            P_AddThinker (&strobe->thinker);
            break;
                                
          case tc_glow:
-           PADSAVEP();
+           saveg_read_pad();
            glow = Z_Malloc (sizeof(*glow), PU_LEVEL, NULL);
-           memcpy (glow, save_p, sizeof(*glow));
-           save_p += sizeof(*glow);
-           glow->sector = &sectors[(int)glow->sector];
+            saveg_read_glow_t(glow);
            glow->thinker.function.acp1 = (actionf_p1)T_Glow;
            P_AddThinker (&glow->thinker);
            break;
index 4caf6edadffc87321372cceaa84549b69ada28b1..2d7beba3c673aa775c8402d81e17005719ce1a27 100644 (file)
@@ -1,33 +1,48 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Savegame I/O, archiving, persistence.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __P_SAVEG__
 #define __P_SAVEG__
 
+#include <stdio.h>
 
-#ifdef __GNUG__
-#pragma interface
-#endif
+// maximum size of a savegame description
+
+#define SAVESTRINGSIZE 24
+
+// temporary filename to use while saving.
+
+char *P_TempSaveGameFile(void);
+
+// filename to use for a savegame slot
 
+char *P_SaveGameFile(int slot);
+
+// Savegame file header read/write functions
+
+boolean P_ReadSaveGameHeader(void);
+void P_WriteSaveGameHeader(char *description);
+
+// Savegame end-of-file read/write functions
+
+boolean P_ReadSaveGameEOF(void);
+void P_WriteSaveGameEOF(void);
 
 // Persistent storage/archiving.
 // These are the load / save game routines.
@@ -40,12 +55,8 @@ void P_UnArchiveThinkers (void);
 void P_ArchiveSpecials (void);
 void P_UnArchiveSpecials (void);
 
-extern byte*           save_p; 
+extern FILE *save_stream;
+extern boolean savegame_error;
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index e5d3667fd1e6e90085476017884e46ef5a817086..00306e84c043e00509b656e56fdca0711bbc5a71 100644 (file)
@@ -1,36 +1,31 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Do all the WAD I/O, get map description,
 //     set up initial state and misc. LUTs.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: p_setup.c,v 1.5 1997/02/03 22:45:12 b1 Exp $";
 
 
 #include <math.h>
 
 #include "z_zone.h"
 
-#include "m_swap.h"
+#include "deh_main.h"
+#include "i_swap.h"
+#include "m_argv.h"
 #include "m_bbox.h"
 
 #include "g_game.h"
@@ -74,6 +69,7 @@ line_t*               lines;
 int            numsides;
 side_t*                sides;
 
+static int      totallines;
 
 // BLOCKMAP
 // Created from axis aligned bounding box
@@ -134,7 +130,7 @@ void P_LoadVertexes (int lump)
     vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0);     
 
     // Load data into cache.
-    data = W_CacheLumpNum (lump,PU_STATIC);
+    data = W_CacheLumpNum (lump, PU_STATIC);
        
     ml = (mapvertex_t *)data;
     li = vertexes;
@@ -148,10 +144,27 @@ void P_LoadVertexes (int lump)
     }
 
     // Free buffer memory.
-    Z_Free (data);
+    W_ReleaseLumpNum(lump);
 }
 
+//
+// GetSectorAtNullAddress
+//
+sector_t* GetSectorAtNullAddress(void)
+{
+    static boolean null_sector_is_initialized = false;
+    static sector_t null_sector;
+
+    if (!null_sector_is_initialized)
+    {
+        memset(&null_sector, 0, sizeof(null_sector));
+        I_GetMemoryValue(0, &null_sector.floorheight, 4);
+        I_GetMemoryValue(4, &null_sector.ceilingheight, 4);
+        null_sector_is_initialized = true;
+    }
 
+    return &null_sector;
+}
 
 //
 // P_LoadSegs
@@ -165,6 +178,7 @@ void P_LoadSegs (int lump)
     line_t*            ldef;
     int                        linedef;
     int                        side;
+    int                 sidenum;
        
     numsegs = W_LumpLength (lump) / sizeof(mapseg_t);
     segs = Z_Malloc (numsegs*sizeof(seg_t),PU_LEVEL,0);        
@@ -177,7 +191,7 @@ void P_LoadSegs (int lump)
     {
        li->v1 = &vertexes[SHORT(ml->v1)];
        li->v2 = &vertexes[SHORT(ml->v2)];
-                                       
+
        li->angle = (SHORT(ml->angle))<<16;
        li->offset = (SHORT(ml->offset))<<16;
        linedef = SHORT(ml->linedef);
@@ -186,13 +200,33 @@ void P_LoadSegs (int lump)
        side = SHORT(ml->side);
        li->sidedef = &sides[ldef->sidenum[side]];
        li->frontsector = sides[ldef->sidenum[side]].sector;
-       if (ldef-> flags & ML_TWOSIDED)
-           li->backsector = sides[ldef->sidenum[side^1]].sector;
-       else
+
+        if (ldef-> flags & ML_TWOSIDED)
+        {
+            sidenum = ldef->sidenum[side ^ 1];
+
+            // If the sidenum is out of range, this may be a "glass hack"
+            // impassible window.  Point at side #0 (this may not be
+            // the correct Vanilla behavior; however, it seems to work for
+            // OTTAWAU.WAD, which is the one place I've seen this trick
+            // used).
+
+            if (sidenum < 0 || sidenum >= numsides)
+            {
+                li->backsector = GetSectorAtNullAddress();
+            }
+            else
+            {
+                li->backsector = sides[sidenum].sector;
+            }
+        }
+        else
+        {
            li->backsector = 0;
+        }
     }
        
-    Z_Free (data);
+    W_ReleaseLumpNum(lump);
 }
 
 
@@ -220,7 +254,7 @@ void P_LoadSubsectors (int lump)
        ss->firstline = SHORT(ms->firstseg);
     }
        
-    Z_Free (data);
+    W_ReleaseLumpNum(lump);
 }
 
 
@@ -254,7 +288,7 @@ void P_LoadSectors (int lump)
        ss->thinglist = NULL;
     }
        
-    Z_Free (data);
+    W_ReleaseLumpNum(lump);
 }
 
 
@@ -291,7 +325,7 @@ void P_LoadNodes (int lump)
        }
     }
        
-    Z_Free (data);
+    W_ReleaseLumpNum(lump);
 }
 
 
@@ -300,12 +334,13 @@ void P_LoadNodes (int lump)
 //
 void P_LoadThings (int lump)
 {
-    byte*              data;
+    byte               *data;
     int                        i;
-    mapthing_t*                mt;
+    mapthing_t         *mt;
+    mapthing_t          spawnthing;
     int                        numthings;
     boolean            spawn;
-       
+
     data = W_CacheLumpNum (lump,PU_STATIC);
     numthings = W_LumpLength (lump) / sizeof(mapthing_t);
        
@@ -315,9 +350,9 @@ void P_LoadThings (int lump)
        spawn = true;
 
        // Do not spawn cool, new monsters if !commercial
-       if ( gamemode != commercial)
+       if (gamemode != commercial)
        {
-           switch(mt->type)
+           switch (SHORT(mt->type))
            {
              case 68:  // Arachnotron
              case 64:  // Archvile
@@ -337,16 +372,16 @@ void P_LoadThings (int lump)
            break;
 
        // Do spawn all other stuff. 
-       mt->x = SHORT(mt->x);
-       mt->y = SHORT(mt->y);
-       mt->angle = SHORT(mt->angle);
-       mt->type = SHORT(mt->type);
-       mt->options = SHORT(mt->options);
+       spawnthing.x = SHORT(mt->x);
+       spawnthing.y = SHORT(mt->y);
+       spawnthing.angle = SHORT(mt->angle);
+       spawnthing.type = SHORT(mt->type);
+       spawnthing.options = SHORT(mt->options);
        
-       P_SpawnMapThing (mt);
+       P_SpawnMapThing(&spawnthing);
     }
-       
-    Z_Free (data);
+
+    W_ReleaseLumpNum(lump);
 }
 
 
@@ -427,8 +462,8 @@ void P_LoadLineDefs (int lump)
        else
            ld->backsector = 0;
     }
-       
-    Z_Free (data);
+
+    W_ReleaseLumpNum(lump);
 }
 
 
@@ -458,8 +493,8 @@ void P_LoadSideDefs (int lump)
        sd->midtexture = R_TextureNumForName(msd->midtexture);
        sd->sector = &sectors[SHORT(msd->sector)];
     }
-       
-    Z_Free (data);
+
+    W_ReleaseLumpNum(lump);
 }
 
 
@@ -468,25 +503,36 @@ void P_LoadSideDefs (int lump)
 //
 void P_LoadBlockMap (int lump)
 {
-    int                i;
-    int                count;
+    int i;
+    int count;
+    int lumplen;
+
+    lumplen = W_LumpLength(lump);
+    count = lumplen / 2;
        
-    blockmaplump = W_CacheLumpNum (lump,PU_LEVEL);
-    blockmap = blockmaplump+4;
-    count = W_LumpLength (lump)/2;
+    blockmaplump = Z_Malloc(lumplen, PU_LEVEL, NULL);
+    W_ReadLump(lump, blockmaplump);
+    blockmap = blockmaplump + 4;
 
-    for (i=0 ; i<count ; i++)
+    // Swap all short integers to native byte ordering.
+  
+    for (i=0; i<count; i++)
+    {
        blockmaplump[i] = SHORT(blockmaplump[i]);
+    }
                
+    // Read the header
+
     bmaporgx = blockmaplump[0]<<FRACBITS;
     bmaporgy = blockmaplump[1]<<FRACBITS;
     bmapwidth = blockmaplump[2];
     bmapheight = blockmaplump[3];
        
-    // clear out mobj chains
-    count = sizeof(*blocklinks)* bmapwidth*bmapheight;
-    blocklinks = Z_Malloc (count,PU_LEVEL, 0);
-    memset (blocklinks, 0, count);
+    // Clear out mobj chains
+
+    count = sizeof(*blocklinks) * bmapwidth * bmapheight;
+    blocklinks = Z_Malloc(count, PU_LEVEL, 0);
+    memset(blocklinks, 0, count);
 }
 
 
@@ -501,7 +547,6 @@ void P_GroupLines (void)
     line_t**           linebuffer;
     int                        i;
     int                        j;
-    int                        total;
     line_t*            li;
     sector_t*          sector;
     subsector_t*       ss;
@@ -519,39 +564,73 @@ void P_GroupLines (void)
 
     // count number of lines in each sector
     li = lines;
-    total = 0;
+    totallines = 0;
     for (i=0 ; i<numlines ; i++, li++)
     {
-       total++;
+       totallines++;
        li->frontsector->linecount++;
 
        if (li->backsector && li->backsector != li->frontsector)
        {
            li->backsector->linecount++;
-           total++;
+           totallines++;
        }
     }
-       
+
     // build line tables for each sector       
-    linebuffer = Z_Malloc (total*4, PU_LEVEL, 0);
+    linebuffer = Z_Malloc (totallines*sizeof(line_t *), PU_LEVEL, 0);
+
+    for (i=0; i<numsectors; ++i)
+    {
+        // Assign the line buffer for this sector
+
+        sectors[i].lines = linebuffer;
+        linebuffer += sectors[i].linecount;
+
+        // Reset linecount to zero so in the next stage we can count
+        // lines into the list.
+
+        sectors[i].linecount = 0;
+    }
+
+    // Assign lines to sectors
+
+    for (i=0; i<numlines; ++i)
+    { 
+        li = &lines[i];
+
+        if (li->frontsector != NULL)
+        {
+            sector = li->frontsector;
+
+            sector->lines[sector->linecount] = li;
+            ++sector->linecount;
+        }
+
+        if (li->backsector != NULL && li->frontsector != li->backsector)
+        {
+            sector = li->backsector;
+
+            sector->lines[sector->linecount] = li;
+            ++sector->linecount;
+        }
+    }
+    
+    // Generate bounding boxes for sectors
+       
     sector = sectors;
     for (i=0 ; i<numsectors ; i++, sector++)
     {
        M_ClearBox (bbox);
-       sector->lines = linebuffer;
-       li = lines;
-       for (j=0 ; j<numlines ; j++, li++)
+
+       for (j=0 ; j<sector->linecount; j++)
        {
-           if (li->frontsector == sector || li->backsector == sector)
-           {
-               *linebuffer++ = li;
-               M_AddToBox (bbox, li->v1->x, li->v1->y);
-               M_AddToBox (bbox, li->v2->x, li->v2->y);
-           }
+            li = sector->lines[j];
+
+            M_AddToBox (bbox, li->v1->x, li->v1->y);
+            M_AddToBox (bbox, li->v2->x, li->v2->y);
        }
-       if (linebuffer - sector->lines != sector->linecount)
-           I_Error ("P_GroupLines: miscounted");
-                       
+
        // set the degenmobj_t to the middle of the bounding box
        sector->soundorg.x = (bbox[BOXRIGHT]+bbox[BOXLEFT])/2;
        sector->soundorg.y = (bbox[BOXTOP]+bbox[BOXBOTTOM])/2;
@@ -576,6 +655,87 @@ void P_GroupLines (void)
        
 }
 
+// Pad the REJECT lump with extra data when the lump is too small,
+// to simulate a REJECT buffer overflow in Vanilla Doom.
+
+static void PadRejectArray(byte *array, unsigned int len)
+{
+    unsigned int i;
+    unsigned int byte_num;
+    byte *dest;
+    unsigned int padvalue;
+
+    // Values to pad the REJECT array with:
+
+    unsigned int rejectpad[4] =
+    {
+        ((totallines * 4 + 3) & ~3) + 24,     // Size
+        0,                                    // Part of z_zone block header
+        50,                                   // PU_LEVEL
+        0x1d4a11                              // DOOM_CONST_ZONEID
+    };
+
+    // Copy values from rejectpad into the destination array.
+
+    dest = array;
+
+    for (i=0; i<len && i<sizeof(rejectpad); ++i)
+    {
+        byte_num = i % 4;
+        *dest = (rejectpad[i / 4] >> (byte_num * 8)) & 0xff;
+        ++dest;
+    }
+
+    // We only have a limited pad size.  Print a warning if the
+    // REJECT lump is too small.
+
+    if (len > sizeof(rejectpad))
+    {
+        fprintf(stderr, "PadRejectArray: REJECT lump too short to pad! (%i > %i)\n",
+                        len, (int) sizeof(rejectpad));
+
+        // Pad remaining space with 0 (or 0xff, if specified on command line).
+
+        if (M_CheckParm("-reject_pad_with_ff"))
+        {
+            padvalue = 0xff;
+        }
+        else
+        {
+            padvalue = 0xf00;
+        }
+
+        memset(array + sizeof(rejectpad), padvalue, len - sizeof(rejectpad));
+    }
+}
+
+static void P_LoadReject(int lumpnum)
+{
+    int minlength;
+    int lumplen;
+
+    // Calculate the size that the REJECT lump *should* be.
+
+    minlength = (numsectors * numsectors + 7) / 8;
+
+    // If the lump meets the minimum length, it can be loaded directly.
+    // Otherwise, we need to allocate a buffer of the correct size
+    // and pad it with appropriate data.
+
+    lumplen = W_LumpLength(lumpnum);
+
+    if (lumplen >= minlength)
+    {
+        rejectmatrix = W_CacheLumpNum(lumpnum, PU_LEVEL);
+    }
+    else
+    {
+        rejectmatrix = Z_Malloc(minlength, PU_LEVEL, &rejectmatrix);
+        W_ReadLump(lumpnum, rejectmatrix);
+
+        PadRejectArray(rejectmatrix + lumplen, minlength - lumplen);
+    }
+}
 
 //
 // P_SetupLevel
@@ -606,31 +766,18 @@ P_SetupLevel
     // Make sure all sounds are stopped before Z_FreeTags.
     S_Start ();                        
 
-    
-#if 0 // UNUSED
-    if (debugfile)
-    {
-       Z_FreeTags (PU_LEVEL, MAXINT);
-       Z_FileDumpHeap (debugfile);
-    }
-    else
-#endif
-       Z_FreeTags (PU_LEVEL, PU_PURGELEVEL-1);
-
+    Z_FreeTags (PU_LEVEL, PU_PURGELEVEL-1);
 
     // UNUSED W_Profile ();
     P_InitThinkers ();
-
-    // if working with a devlopment map, reload it
-    W_Reload ();                       
           
     // find map name
     if ( gamemode == commercial)
     {
        if (map<10)
-           sprintf (lumpname,"map0%i", map);
+           DEH_snprintf(lumpname, 9, "map0%i", map);
        else
-           sprintf (lumpname,"map%i", map);
+           DEH_snprintf(lumpname, 9, "map%i", map);
     }
     else
     {
@@ -655,9 +802,9 @@ P_SetupLevel
     P_LoadSubsectors (lumpnum+ML_SSECTORS);
     P_LoadNodes (lumpnum+ML_NODES);
     P_LoadSegs (lumpnum+ML_SEGS);
-       
-    rejectmatrix = W_CacheLumpNum (lumpnum+ML_REJECT,PU_LEVEL);
+
     P_GroupLines ();
+    P_LoadReject (lumpnum+ML_REJECT);
 
     bodyqueslot = 0;
     deathmatch_p = deathmatchstarts;
index 92b7f36b7dc2ffa65a2f6aaf8d37c66c2ea79e72..9df741629aa5ccd1485c85493ab9bdd7e608376f 100644 (file)
@@ -1,32 +1,26 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //   Setup a game, startup stuff.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __P_SETUP__
 #define __P_SETUP__
 
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 
 // NOT called by W_Ticker. Fixme.
@@ -41,8 +35,3 @@ P_SetupLevel
 void P_Init (void);
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 6aaba6e85fca1dc06c11fde23dae32fd61fa2145..48ba68384bc50867e3d4865323e6cf444f619040 100644 (file)
@@ -1,28 +1,21 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     LineOfSight/Visibility checks, uses REJECT Lookup Table.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: p_sight.c,v 1.3 1997/01/28 22:08:28 b1 Exp $";
 
 
 #include "doomdef.h"
@@ -172,7 +165,7 @@ boolean P_CrossSubsector (int num)
            continue;
        
        line->validcount = validcount;
-               
+
        v1 = line->v1;
        v2 = line->v2;
        s1 = P_DivlineSide (v1->x,v1->y, &strace);
@@ -193,6 +186,14 @@ boolean P_CrossSubsector (int num)
        if (s1 == s2)
            continue;   
 
+        // Backsector may be NULL if this is an "impassible
+        // glass" hack line.
+
+        if (line->backsector == NULL)
+        {
+            return false;
+        }
+
        // stop because it is not two sided anyway
        // might do this after updating validcount?
        if ( !(line->flags & ML_TWOSIDED) )
index ba334607d37fb5aab8362a26cc3b54ee238e1dcc..17446b5dfb1f2b220ace8ace8513642cbd0a03eb 100644 (file)
@@ -1,20 +1,16 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Implements special effects:
 //      utility functions, etc.
 //     Line Tag handling. Line and Sector triggers.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: p_spec.c,v 1.6 1997/02/03 22:45:12 b1 Exp $";
 
 #include <stdlib.h>
 
 #include "doomdef.h"
 #include "doomstat.h"
 
+#include "deh_main.h"
 #include "i_system.h"
 #include "z_zone.h"
 #include "m_argv.h"
+#include "m_misc.h"
 #include "m_random.h"
 #include "w_wad.h"
 
@@ -72,7 +67,7 @@ typedef struct
 //
 typedef struct
 {
-    int            istexture;  // if false, it is a flat
+    int        istexture;      // if false, it is a flat
     char       endname[9];
     char       startname[9];
     int                speed;
@@ -128,7 +123,7 @@ animdef_t           animdefs[] =
     {true,     "WFALL4",       "WFALL1",       8},
     {true,     "DBRAIN4",      "DBRAIN1",      8},
        
-    {-1,    "",         "",         0}
+    {-1,        "",             "",             0},
 };
 
 anim_t         anims[MAXANIMS];
@@ -149,26 +144,32 @@ void P_InitPicAnims (void)
 {
     int                i;
 
+    
     // Init animation
     lastanim = anims;
     for (i=0 ; animdefs[i].istexture != -1 ; i++)
     {
+        char *startname, *endname;
+
+        startname = DEH_String(animdefs[i].startname);
+        endname = DEH_String(animdefs[i].endname);
+
        if (animdefs[i].istexture)
        {
            // different episode ?
-           if (R_CheckTextureNumForName(animdefs[i].startname) == -1)
+           if (R_CheckTextureNumForName(startname) == -1)
                continue;       
 
-           lastanim->picnum = R_TextureNumForName (animdefs[i].endname);
-           lastanim->basepic = R_TextureNumForName (animdefs[i].startname);
+           lastanim->picnum = R_TextureNumForName(endname);
+           lastanim->basepic = R_TextureNumForName(startname);
        }
        else
        {
-           if (W_CheckNumForName(animdefs[i].startname) == -1)
+           if (W_CheckNumForName(startname) == -1)
                continue;
 
-           lastanim->picnum = R_FlatNumForName (animdefs[i].endname);
-           lastanim->basepic = R_FlatNumForName (animdefs[i].startname);
+           lastanim->picnum = R_FlatNumForName(endname);
+           lastanim->basepic = R_FlatNumForName(startname);
        }
 
        lastanim->istexture = animdefs[i].istexture;
@@ -176,8 +177,7 @@ void P_InitPicAnims (void)
 
        if (lastanim->numpics < 2)
            I_Error ("P_InitPicAnims: bad cycle from %s to %s",
-                    animdefs[i].startname,
-                    animdefs[i].endname);
+                    startname, endname);
        
        lastanim->speed = animdefs[i].speed;
        lastanim++;
@@ -321,59 +321,70 @@ fixed_t   P_FindHighestFloorSurrounding(sector_t *sec)
 // FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS
 // Note: this should be doable w/o a fixed array.
 
+// Thanks to entryway for the Vanilla overflow emulation.
+
 // 20 adjoining sectors max!
-#define MAX_ADJOINING_SECTORS          20
+#define MAX_ADJOINING_SECTORS     20
 
 fixed_t
 P_FindNextHighestFloor
-( sector_t*    sec,
-  int          currentheight )
+( sector_t* sec,
+  int       currentheight )
 {
-    int                        i;
-    int                        h;
-    int                        min;
-    line_t*            check;
-    sector_t*          other;
-    fixed_t            height = currentheight;
-
-    
-    fixed_t            heightlist[MAX_ADJOINING_SECTORS];              
-
-    for (i=0, h=0 ;i < sec->linecount ; i++)
+    int         i;
+    int         h;
+    int         min;
+    line_t*     check;
+    sector_t*   other;
+    fixed_t     height = currentheight;
+    fixed_t     heightlist[MAX_ADJOINING_SECTORS + 2];
+
+    for (i=0, h=0; i < sec->linecount; i++)
     {
-       check = sec->lines[i];
-       other = getNextSector(check,sec);
-
-       if (!other)
-           continue;
-       
-       if (other->floorheight > height)
-           heightlist[h++] = other->floorheight;
-
-       // Check for overflow. Exit.
-       if ( h >= MAX_ADJOINING_SECTORS )
-       {
-           fprintf( stderr,
-                    "Sector with more than 20 adjoining sectors\n" );
-           break;
-       }
+        check = sec->lines[i];
+        other = getNextSector(check,sec);
+
+        if (!other)
+            continue;
+        
+        if (other->floorheight > height)
+        {
+            // Emulation of memory (stack) overflow
+            if (h == MAX_ADJOINING_SECTORS + 1)
+            {
+                height = other->floorheight;
+            }
+            else if (h == MAX_ADJOINING_SECTORS + 2)
+            {
+                // Fatal overflow: game crashes at 22 textures
+                I_Error("Sector with more than 22 adjoining sectors. "
+                        "Vanilla will crash here");
+            }
+
+            heightlist[h++] = other->floorheight;
+        }
     }
     
     // Find lowest height in list
     if (!h)
-       return currentheight;
-               
+    {
+        return currentheight;
+    }
+        
     min = heightlist[0];
     
     // Range checking? 
-    for (i = 1;i < h;i++)
-       if (heightlist[i] < min)
-           min = heightlist[i];
-                       
+    for (i = 1; i < h; i++)
+    {
+        if (heightlist[i] < min)
+        {
+            min = heightlist[i];
+        }
+    }
+
     return min;
 }
 
-
 //
 // FIND LOWEST CEILING IN THE SURROUNDING SECTORS
 //
@@ -383,7 +394,7 @@ P_FindLowestCeilingSurrounding(sector_t* sec)
     int                        i;
     line_t*            check;
     sector_t*          other;
-    fixed_t            height = MAXINT;
+    fixed_t            height = INT_MAX;
        
     for (i=0 ;i < sec->linecount ; i++)
     {
@@ -541,19 +552,19 @@ P_CrossSpecialLine
        // All from here to RETRIGGERS.
       case 2:
        // Open Door
-       EV_DoDoor(line,open);
+       EV_DoDoor(line,vld_open);
        line->special = 0;
        break;
 
       case 3:
        // Close Door
-       EV_DoDoor(line,close);
+       EV_DoDoor(line,vld_close);
        line->special = 0;
        break;
 
       case 4:
        // Raise Door
-       EV_DoDoor(line,normal);
+       EV_DoDoor(line,vld_normal);
        line->special = 0;
        break;
        
@@ -595,7 +606,7 @@ P_CrossSpecialLine
        
       case 16:
        // Close Door 30
-       EV_DoDoor(line,close30ThenOpen);
+       EV_DoDoor(line,vld_close30ThenOpen);
        line->special = 0;
        break;
        
@@ -722,13 +733,13 @@ P_CrossSpecialLine
        
       case 108:
        // Blazing Door Raise (faster than TURBO!)
-       EV_DoDoor (line,blazeRaise);
+       EV_DoDoor (line,vld_blazeRaise);
        line->special = 0;
        break;
        
       case 109:
        // Blazing Door Open (faster than TURBO!)
-       EV_DoDoor (line,blazeOpen);
+       EV_DoDoor (line,vld_blazeOpen);
        line->special = 0;
        break;
        
@@ -740,7 +751,7 @@ P_CrossSpecialLine
        
       case 110:
        // Blazing Door Close (faster than TURBO!)
-       EV_DoDoor (line,blazeClose);
+       EV_DoDoor (line,vld_blazeClose);
        line->special = 0;
        break;
 
@@ -800,12 +811,12 @@ P_CrossSpecialLine
        
       case 75:
        // Close Door
-       EV_DoDoor(line,close);
+       EV_DoDoor(line,vld_close);
        break;
        
       case 76:
        // Close Door 30
-       EV_DoDoor(line,close30ThenOpen);
+       EV_DoDoor(line,vld_close30ThenOpen);
        break;
        
       case 77:
@@ -845,7 +856,7 @@ P_CrossSpecialLine
 
       case 86:
        // Open Door
-       EV_DoDoor(line,open);
+       EV_DoDoor(line,vld_open);
        break;
        
       case 87:
@@ -865,7 +876,7 @@ P_CrossSpecialLine
        
       case 90:
        // Raise Door
-       EV_DoDoor(line,normal);
+       EV_DoDoor(line,vld_normal);
        break;
        
       case 91:
@@ -912,17 +923,17 @@ P_CrossSpecialLine
 
       case 105:
        // Blazing Door Raise (faster than TURBO!)
-       EV_DoDoor (line,blazeRaise);
+       EV_DoDoor (line,vld_blazeRaise);
        break;
        
       case 106:
        // Blazing Door Open (faster than TURBO!)
-       EV_DoDoor (line,blazeOpen);
+       EV_DoDoor (line,vld_blazeOpen);
        break;
 
       case 107:
        // Blazing Door Close (faster than TURBO!)
-       EV_DoDoor (line,blazeClose);
+       EV_DoDoor (line,vld_blazeClose);
        break;
 
       case 120:
@@ -986,7 +997,7 @@ P_ShootSpecialLine
        
       case 46:
        // OPEN DOOR
-       EV_DoDoor(line,open);
+       EV_DoDoor(line,vld_open);
        P_ChangeSwitchTexture(line,1);
        break;
        
@@ -1147,14 +1158,98 @@ void P_UpdateSpecials (void)
                        buttonlist[i].btexture;
                    break;
                }
-               S_StartSound((mobj_t *)&buttonlist[i].soundorg,sfx_swtchn);
+               S_StartSound(&buttonlist[i].soundorg,sfx_swtchn);
                memset(&buttonlist[i],0,sizeof(button_t));
            }
        }
-       
 }
 
 
+//
+// Donut overrun emulation
+//
+// Derived from the code from PrBoom+.  Thanks go to Andrey Budko (entryway)
+// as usual :-)
+//
+
+#define DONUT_FLOORHEIGHT_DEFAULT 0x00000000
+#define DONUT_FLOORPIC_DEFAULT 0x16
+
+static void DonutOverrun(fixed_t *s3_floorheight, short *s3_floorpic,
+                         line_t *line, sector_t *pillar_sector)
+{
+    static int first = 1;
+    static int tmp_s3_floorheight;
+    static int tmp_s3_floorpic;
+
+    extern int numflats;
+
+    if (first)
+    {
+        int p;
+
+        // This is the first time we have had an overrun.
+        first = 0;
+
+        // Default values
+        tmp_s3_floorheight = DONUT_FLOORHEIGHT_DEFAULT;
+        tmp_s3_floorpic = DONUT_FLOORPIC_DEFAULT;
+
+        //!
+        // @category compat
+        // @arg <x> <y>
+        //
+        // Use the specified magic values when emulating behavior caused
+        // by memory overruns from improperly constructed donuts.
+        // In Vanilla Doom this can differ depending on the operating
+        // system.  The default (if this option is not specified) is to
+        // emulate the behavior when running under Windows 98.
+
+        p = M_CheckParmWithArgs("-donut", 2);
+
+        if (p > 0)
+        {
+            // Dump of needed memory: (fixed_t)0000:0000 and (short)0000:0008
+            //
+            // C:\>debug
+            // -d 0:0
+            //
+            // DOS 6.22:
+            // 0000:0000    (57 92 19 00) F4 06 70 00-(16 00)
+            // DOS 7.1:
+            // 0000:0000    (9E 0F C9 00) 65 04 70 00-(16 00)
+            // Win98:
+            // 0000:0000    (00 00 00 00) 65 04 70 00-(16 00)
+            // DOSBox under XP:
+            // 0000:0000    (00 00 00 F1) ?? ?? ?? 00-(07 00)
+
+            M_StrToInt(myargv[p + 1], &tmp_s3_floorheight);
+            M_StrToInt(myargv[p + 2], &tmp_s3_floorpic);
+
+            if (tmp_s3_floorpic >= numflats)
+            {
+                fprintf(stderr,
+                        "DonutOverrun: The second parameter for \"-donut\" "
+                        "switch should be greater than 0 and less than number "
+                        "of flats (%d). Using default value (%d) instead. \n",
+                        numflats, DONUT_FLOORPIC_DEFAULT);
+                tmp_s3_floorpic = DONUT_FLOORPIC_DEFAULT;
+            }
+        }
+    }
+
+    /*
+    fprintf(stderr,
+            "Linedef: %d; Sector: %d; "
+            "New floor height: %d; New floor pic: %d\n",
+            line->iLineID, pillar_sector->iSectorID,
+            tmp_s3_floorheight >> 16, tmp_s3_floorpic);
+     */
+
+    *s3_floorheight = (fixed_t) tmp_s3_floorheight;
+    *s3_floorpic = (short) tmp_s3_floorpic;
+}
+
 
 //
 // Special Stuff that can not be categorized
@@ -1168,26 +1263,67 @@ int EV_DoDonut(line_t*  line)
     int                        rtn;
     int                        i;
     floormove_t*       floor;
-       
+    fixed_t s3_floorheight;
+    short s3_floorpic;
+
     secnum = -1;
     rtn = 0;
     while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
     {
        s1 = &sectors[secnum];
-               
+
        // ALREADY MOVING?  IF SO, KEEP GOING...
        if (s1->specialdata)
            continue;
-                       
+
        rtn = 1;
        s2 = getNextSector(s1->lines[0],s1);
-       for (i = 0;i < s2->linecount;i++)
+
+        // Vanilla Doom does not check if the linedef is one sided.  The
+        // game does not crash, but reads invalid memory and causes the
+        // sector floor to move "down" to some unknown height.
+        // DOSbox prints a warning about an invalid memory access.
+        //
+        // I'm not sure exactly what invalid memory is being read.  This
+        // isn't something that should be done, anyway.
+        // Just print a warning and return.
+
+        if (s2 == NULL)
+        {
+            fprintf(stderr,
+                    "EV_DoDonut: linedef had no second sidedef! "
+                    "Unexpected behavior may occur in Vanilla Doom. \n");
+           break;
+        }
+
+       for (i = 0; i < s2->linecount; i++)
        {
-           if ((!(s2->lines[i]->flags & ML_TWOSIDED)) ||
-               (s2->lines[i]->backsector == s1))
-               continue;
            s3 = s2->lines[i]->backsector;
-           
+
+           if (s3 == s1)
+               continue;
+
+            if (s3 == NULL)
+            {
+                // e6y
+                // s3 is NULL, so
+                // s3->floorheight is an int at 0000:0000
+                // s3->floorpic is a short at 0000:0008
+                // Trying to emulate
+
+                fprintf(stderr,
+                        "EV_DoDonut: WARNING: emulating buffer overrun due to "
+                        "NULL back sector. "
+                        "Unexpected behavior may occur in Vanilla Doom.\n");
+
+                DonutOverrun(&s3_floorheight, &s3_floorpic, line, s1);
+            }
+            else
+            {
+                s3_floorheight = s3->floorheight;
+                s3_floorpic = s3->floorpic;
+            }
+
            //  Spawn rising slime
            floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
            P_AddThinker (&floor->thinker);
@@ -1198,9 +1334,9 @@ int EV_DoDonut(line_t*    line)
            floor->direction = 1;
            floor->sector = s2;
            floor->speed = FLOORSPEED / 2;
-           floor->texture = s3->floorpic;
+           floor->texture = s3_floorpic;
            floor->newspecial = 0;
-           floor->floordestheight = s3->floorheight;
+           floor->floordestheight = s3_floorheight;
            
            //  Spawn lowering donut-hole
            floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
@@ -1212,7 +1348,7 @@ int EV_DoDonut(line_t*    line)
            floor->direction = -1;
            floor->sector = s1;
            floor->speed = FLOORSPEED / 2;
-           floor->floordestheight = s3->floorheight;
+           floor->floordestheight = s3_floorheight;
            break;
        }
     }
@@ -1239,32 +1375,19 @@ void P_SpawnSpecials (void)
 {
     sector_t*  sector;
     int                i;
-    //int              episode;
 
-    //episode = 1;
-    if (W_CheckNumForName("texture2") >= 0)
-       //episode = 2;
+    // See if -TIMER was specified.
 
-    
-    // See if -TIMER needs to be used.
-    levelTimer = false;
-       
-    i = M_CheckParm("-avg");
-    if (i && deathmatch)
+    if (timelimit > 0 && deathmatch)
     {
-       levelTimer = true;
-       levelTimeCount = 20 * 60 * 35;
+        levelTimer = true;
+        levelTimeCount = timelimit * 60 * TICRATE;
     }
-       
-    i = M_CheckParm("-timer");
-    if (i && deathmatch)
+    else
     {
-       int     time;
-       time = atoi(myargv[i+1]) * 60 * 35;
-       levelTimer = true;
-       levelTimeCount = time;
+       levelTimer = false;
     }
-    
+
     // Init special SECTORs.
     sector = sectors;
     for (i=0 ; i<numsectors ; i++, sector++)
@@ -1338,6 +1461,11 @@ void P_SpawnSpecials (void)
        switch(lines[i].special)
        {
          case 48:
+            if (numlinespecials >= MAXLINEANIMS)
+            {
+                I_Error("Too many scrolling wall linedefs! "
+                        "(Vanilla limit is 64)");
+            }
            // EFFECT FIRSTCOL SCROLL+
            linespeciallist[numlinespecials] = &lines[i];
            numlinespecials++;
index 39155bf36d6033154b3f259f84a5d613c0e3422e..a1343bfa398f22e685ea33d1333789ca9c1ce084 100644 (file)
@@ -1,18 +1,16 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:  none
 //     Implements special effects:
@@ -20,7 +18,6 @@
 //      according to adjacent sectors, respective
 //      utility functions, etc.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __P_SPEC__
@@ -230,7 +227,7 @@ typedef struct
     bwhere_e   where;
     int                btexture;
     int                btimer;
-    mobj_t*    soundorg;
+    degenmobj_t *soundorg;
 
 } button_t;
 
@@ -327,14 +324,14 @@ void    P_ActivateInStasis(int tag);
 //
 typedef enum
 {
-    normal,
-    close30ThenOpen,
-    close,
-    open,
-    raiseIn5Mins,
-    blazeRaise,
-    blazeOpen,
-    blazeClose
+    vld_normal,
+    vld_close30ThenOpen,
+    vld_close,
+    vld_open,
+    vld_raiseIn5Mins,
+    vld_blazeRaise,
+    vld_blazeOpen,
+    vld_blazeClose
 
 } vldoor_e;
 
@@ -638,8 +635,3 @@ EV_Teleport
   mobj_t*      thing );
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 58807325157248584c4efac153f214edd24dd57d..ed4feeca0896f6621a6cad898e5410e481819bd2 100644 (file)
@@ -1,32 +1,26 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
-// $Log:$
 //
 // DESCRIPTION:
 //     Switches, buttons. Two-state animation. Exits.
 //
-//-----------------------------------------------------------------------------
-
-static const char
-rcsid[] = "$Id: p_switch.c,v 1.3 1997/01/28 22:08:29 b1 Exp $";
 
+#include <stdio.h>
 
 #include "i_system.h"
+#include "deh_main.h"
 #include "doomdef.h"
 #include "p_local.h"
 
@@ -112,7 +106,7 @@ void P_InitSwitchList(void)
        
     episode = 1;
 
-    if (gamemode == registered)
+    if (gamemode == registered || gamemode == retail)
        episode = 2;
     else
        if ( gamemode == commercial )
@@ -141,8 +135,8 @@ void P_InitSwitchList(void)
            
            value = R_TextureNumForName(alphSwitchList[i].name1);
 #endif
-           switchlist[index++] = R_TextureNumForName(alphSwitchList[i].name1);
-           switchlist[index++] = R_TextureNumForName(alphSwitchList[i].name2);
+           switchlist[index++] = R_TextureNumForName(DEH_String(alphSwitchList[i].name1));
+           switchlist[index++] = R_TextureNumForName(DEH_String(alphSwitchList[i].name2));
        }
     }
 }
@@ -181,7 +175,7 @@ P_StartButton
            buttonlist[i].where = w;
            buttonlist[i].btexture = texture;
            buttonlist[i].btimer = time;
-           buttonlist[i].soundorg = (mobj_t *)&line->frontsector->soundorg;
+           buttonlist[i].soundorg = &line->frontsector->soundorg;
            return;
        }
     }
@@ -400,7 +394,7 @@ P_UseSpecialLine
        
       case 29:
        // Raise Door
-       if (EV_DoDoor(line,normal))
+       if (EV_DoDoor(line,vld_normal))
            P_ChangeSwitchTexture(line,0);
        break;
        
@@ -424,7 +418,7 @@ P_UseSpecialLine
        
       case 50:
        // Close Door
-       if (EV_DoDoor(line,close))
+       if (EV_DoDoor(line,vld_close))
            P_ChangeSwitchTexture(line,0);
        break;
        
@@ -454,25 +448,25 @@ P_UseSpecialLine
        
       case 103:
        // Open Door
-       if (EV_DoDoor(line,open))
+       if (EV_DoDoor(line,vld_open))
            P_ChangeSwitchTexture(line,0);
        break;
        
       case 111:
        // Blazing Door Raise (faster than TURBO!)
-       if (EV_DoDoor (line,blazeRaise))
+       if (EV_DoDoor (line,vld_blazeRaise))
            P_ChangeSwitchTexture(line,0);
        break;
        
       case 112:
        // Blazing Door Open (faster than TURBO!)
-       if (EV_DoDoor (line,blazeOpen))
+       if (EV_DoDoor (line,vld_blazeOpen))
            P_ChangeSwitchTexture(line,0);
        break;
        
       case 113:
        // Blazing Door Close (faster than TURBO!)
-       if (EV_DoDoor (line,blazeClose))
+       if (EV_DoDoor (line,vld_blazeClose))
            P_ChangeSwitchTexture(line,0);
        break;
        
@@ -500,7 +494,7 @@ P_UseSpecialLine
        // BlzOpenDoor RED
       case 137:
        // BlzOpenDoor YELLOW
-       if (EV_DoLockedDoor (line,blazeOpen,thing))
+       if (EV_DoLockedDoor (line,vld_blazeOpen,thing))
            P_ChangeSwitchTexture(line,0);
        break;
        
@@ -513,7 +507,7 @@ P_UseSpecialLine
        // BUTTONS
       case 42:
        // Close Door
-       if (EV_DoDoor(line,close))
+       if (EV_DoDoor(line,vld_close))
            P_ChangeSwitchTexture(line,1);
        break;
        
@@ -537,7 +531,7 @@ P_UseSpecialLine
        
       case 61:
        // Open Door
-       if (EV_DoDoor(line,open))
+       if (EV_DoDoor(line,vld_open))
            P_ChangeSwitchTexture(line,1);
        break;
        
@@ -549,7 +543,7 @@ P_UseSpecialLine
        
       case 63:
        // Raise Door
-       if (EV_DoDoor(line,normal))
+       if (EV_DoDoor(line,vld_normal))
            P_ChangeSwitchTexture(line,1);
        break;
        
@@ -597,19 +591,19 @@ P_UseSpecialLine
        
       case 114:
        // Blazing Door Raise (faster than TURBO!)
-       if (EV_DoDoor (line,blazeRaise))
+       if (EV_DoDoor (line,vld_blazeRaise))
            P_ChangeSwitchTexture(line,1);
        break;
        
       case 115:
        // Blazing Door Open (faster than TURBO!)
-       if (EV_DoDoor (line,blazeOpen))
+       if (EV_DoDoor (line,vld_blazeOpen))
            P_ChangeSwitchTexture(line,1);
        break;
        
       case 116:
        // Blazing Door Close (faster than TURBO!)
-       if (EV_DoDoor (line,blazeClose))
+       if (EV_DoDoor (line,vld_blazeClose))
            P_ChangeSwitchTexture(line,1);
        break;
        
@@ -631,7 +625,7 @@ P_UseSpecialLine
        // BlzOpenDoor RED
       case 136:
        // BlzOpenDoor YELLOW
-       if (EV_DoLockedDoor (line,blazeOpen,thing))
+       if (EV_DoLockedDoor (line,vld_blazeOpen,thing))
            P_ChangeSwitchTexture(line,1);
        break;
        
index 56ba3d7109234445271d4acc77c4e28ee20cf064..45cdfb0164e4331781cb328296df14b282754ba2 100644 (file)
@@ -1,32 +1,26 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Teleportation.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: p_telept.c,v 1.3 1997/01/28 22:08:29 b1 Exp $";
 
 
 
 #include "doomdef.h"
+#include "doomstat.h"
 
 #include "s_sound.h"
 
@@ -102,11 +96,18 @@ EV_Teleport
                                
                if (!P_TeleportMove (thing, m->x, m->y))
                    return 0;
-               
-               thing->z = thing->floorz;  //fixme: not needed?
+
+                // The first Final Doom executable does not set thing->z
+                // when teleporting. This quirk is unique to this
+                // particular version; the later version included in
+                // some versions of the Id Anthology fixed this.
+
+                if (gameversion != exe_final)
+                   thing->z = thing->floorz;
+
                if (thing->player)
                    thing->player->viewz = thing->z+thing->player->viewheight;
-                               
+
                // spawn teleport fog at source and destination
                fog = P_SpawnMobj (oldx, oldy, oldz, MT_TFOG);
                S_StartSound (fog, sfx_telept);
index 9b16a6de309a7c3136cbdb2509cac93f822f730a..2289350012bd78d1ed7093251f98cada7a798555 100644 (file)
@@ -1,29 +1,22 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Archiving: SaveGame I/O.
 //     Thinker, Ticker.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: p_tick.c,v 1.4 1997/02/03 16:47:55 b1 Exp $";
 
 #include "z_zone.h"
 #include "p_local.h"
index 0841998c30b9d7ffb9272717d666928ee7a7b090..ddfcd74fc8426a4eeb122d3fbe80621719782e69 100644 (file)
@@ -1,32 +1,26 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     ?
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __P_TICK__
 #define __P_TICK__
 
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 
 // Called by C_Ticker,
@@ -37,8 +31,3 @@ void P_Ticker (void);
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 22fd6ed44e9d368e31988d8c11bdc528a28ffaeb..73c0dc9434fc424918affa3bf3ae51e8fbc8fb99 100644 (file)
@@ -1,31 +1,24 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Player related stuff.
 //     Bobbing POV/weapon, movement.
 //     Pending weapon.
 //
-//-----------------------------------------------------------------------------
 
 
-static const char
-rcsid[] = "$Id: p_user.c,v 1.3 1997/01/28 22:08:29 b1 Exp $";
 
 
 #include "doomdef.h"
index adc9f75a9e2d1959d9033c41b20700f3f7d0d2b2..9a788122ad6f0357b217f9912c3c4a6db40b375e 100644 (file)
@@ -1,29 +1,22 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     BSP traversal, handling of LineSegs for rendering.
 //
-//-----------------------------------------------------------------------------
 
 
-static const char
-rcsid[] = "$Id: r_bsp.c,v 1.4 1997/02/03 22:45:12 b1 Exp $";
 
 
 #include "doomdef.h"
index 743adb9563239fdf5b4ef6c6d5f108205e3e885f..1723e6861470325e9d745d78e0f46614c826fa1f 100644 (file)
@@ -1,31 +1,25 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Refresh module, BSP traversal and handling.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __R_BSP__
 #define __R_BSP__
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 
 extern seg_t*          curline;
@@ -65,8 +59,3 @@ void R_RenderBSPNode (int bspnum);
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index cb29313925f16dfed2c969d69fcfc95f28831023..2d4b65bb5dd5563b09241979784d2ea47c525782 100644 (file)
@@ -1,51 +1,40 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
-// Revision 1.3  1997/01/29 20:10
 // DESCRIPTION:
 //     Preparation of data for rendering,
 //     generation of lookups, caching, retrieval by name.
 //
-//-----------------------------------------------------------------------------
 
+#include <stdio.h>
 
-static const char
-rcsid[] = "$Id: r_data.c,v 1.4 1997/02/03 16:47:55 b1 Exp $";
-
+#include "deh_main.h"
+#include "i_swap.h"
 #include "i_system.h"
 #include "z_zone.h"
 
-#include "m_swap.h"
 
 #include "w_wad.h"
 
 #include "doomdef.h"
+#include "m_misc.h"
 #include "r_local.h"
 #include "p_local.h"
 
 #include "doomstat.h"
 #include "r_sky.h"
 
-#ifdef LINUX
-#include  <alloca.h>
-#endif
-#include  <stdlib.h>
-
 
 #include "r_data.h"
 
@@ -74,7 +63,7 @@ typedef struct
     short      patch;
     short      stepdir;
     short      colormap;
-} mappatch_t;
+} PACKEDATTR mappatch_t;
 
 
 //
@@ -85,13 +74,13 @@ typedef struct
 typedef struct
 {
     char               name[8];
-    boolean            masked; 
+    int                        masked; 
     short              width;
     short              height;
-    void               **columndirectory;      // OBSOLETE
+    int                 obsolete;
     short              patchcount;
     mappatch_t patches[1];
-} maptexture_t;
+} PACKEDATTR maptexture_t;
 
 
 // A single patch from a texture definition,
@@ -102,8 +91,8 @@ typedef struct
     // Block origin (allways UL),
     // which has allready accounted
     // for the internal origin of the patch.
-    int                originx;        
-    int                originy;
+    short      originx;        
+    short      originy;
     int                patch;
 } texpatch_t;
 
@@ -111,19 +100,29 @@ typedef struct
 // A maptexturedef_t describes a rectangular texture,
 //  which is composed of one or more mappatch_t structures
 //  that arrange graphic patches.
-typedef struct
+
+typedef struct texture_s texture_t;
+
+struct texture_s
 {
     // Keep name for switch changing, etc.
     char       name[8];                
     short      width;
     short      height;
+
+    // Index in textures list
+
+    int         index;
+
+    // Next in hash table chain
+
+    texture_t  *next;
     
     // All the patches[patchcount]
     //  are drawn back to front into the cached texture.
     short      patchcount;
     texpatch_t patches[1];             
-    
-} texture_t;
+};
 
 
 
@@ -141,6 +140,7 @@ int         numspritelumps;
 
 int            numtextures;
 texture_t**    textures;
+texture_t**     textures_hashtable;
 
 
 int*                   texturewidthmask;
@@ -192,10 +192,7 @@ R_DrawColumnInCache
     int                count;
     int                position;
     byte*      source;
-    //byte*    dest;
-       //
-    //dest = (byte *)cache + 3;
-       
+
     while (patch->topdelta != 0xff)
     {
        source = (byte *)patch + 3;
@@ -298,7 +295,6 @@ void R_GenerateLookup (int texnum)
 {
     texture_t*         texture;
     byte*              patchcount;     // patchcount[texture->width]
-    byte*              patchcount_alloc;
     texpatch_t*                patch;  
     patch_t*           realpatch;
     int                        x;
@@ -321,14 +317,10 @@ void R_GenerateLookup (int texnum)
     //  that are covered by more than one patch.
     // Fill in the lump / offset, so columns
     //  with only a single patch are all done.
-    //XXX patchcount = (byte *)alloca (texture->width);
-    patchcount = (byte *)malloc (texture->width);
-    patchcount_alloc = patchcount;
-    if (!patchcount)
-        return;
+    patchcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &patchcount);
     memset (patchcount, 0, texture->width);
     patch = texture->patches;
-               
+
     for (i=0 , patch = texture->patches;
         i<texture->patchcount;
         i++, patch++)
@@ -378,7 +370,7 @@ void R_GenerateLookup (int texnum)
        }
     }
 
-    free(patchcount_alloc);
+    Z_Free(patchcount);
 }
 
 
@@ -409,6 +401,46 @@ R_GetColumn
 }
 
 
+static void GenerateTextureHashTable(void)
+{
+    texture_t **rover;
+    int i;
+    int key;
+
+    textures_hashtable 
+            = Z_Malloc(sizeof(texture_t *) * numtextures, PU_STATIC, 0);
+
+    memset(textures_hashtable, 0, sizeof(texture_t *) * numtextures);
+
+    // Add all textures to hash table
+
+    for (i=0; i<numtextures; ++i)
+    {
+        // Store index
+
+        textures[i]->index = i;
+
+        // Vanilla Doom does a linear search of the texures array
+        // and stops at the first entry it finds.  If there are two
+        // entries with the same name, the first one in the array
+        // wins. The new entry must therefore be added at the end
+        // of the hash chain, so that earlier entries win.
+
+        key = W_LumpNameHash(textures[i]->name) % numtextures;
+
+        rover = &textures_hashtable[key];
+
+        while (*rover != NULL)
+        {
+            rover = &(*rover)->next;
+        }
+
+        // Hook into hash table
+
+        textures[i]->next = NULL;
+        *rover = textures[i];
+    }
+}
 
 
 //
@@ -435,7 +467,6 @@ void R_InitTextures (void)
     char*              name_p;
     
     int*               patchlookup;
-    int*               patchlookup_alloc;
     
     int                        totalwidth;
     int                        nummappatches;
@@ -453,36 +484,32 @@ void R_InitTextures (void)
 
     
     // Load the patch names from pnames.lmp.
-    name[8] = 0;       
-    names = W_CacheLumpName ("PNAMES", PU_STATIC);
+    name[8] = 0;
+    names = W_CacheLumpName (DEH_String("PNAMES"), PU_STATIC);
     nummappatches = LONG ( *((int *)names) );
-    name_p = names+4;
-    //XXX patchlookup = alloca (nummappatches*sizeof(*patchlookup));
-    patchlookup = malloc (nummappatches*sizeof(*patchlookup));
-    patchlookup_alloc = patchlookup;
-    if (!patchlookup)
-        return;
-    
-    for (i=0 ; i<nummappatches ; i++)
+    name_p = names + 4;
+    patchlookup = Z_Malloc(nummappatches*sizeof(*patchlookup), PU_STATIC, NULL);
+
+    for (i = 0; i < nummappatches; i++)
     {
-       strncpy (name,name_p+i*8, 8);
-       patchlookup[i] = W_CheckNumForName (name);
+        M_StringCopy(name, name_p + i * 8, sizeof(name));
+        patchlookup[i] = W_CheckNumForName(name);
     }
-    Z_Free (names);
-    
+    W_ReleaseLumpName(DEH_String("PNAMES"));
+
     // Load the map texture definitions from textures.lmp.
     // The data is contained in one or two lumps,
     //  TEXTURE1 for shareware, plus TEXTURE2 for commercial.
-    maptex = maptex1 = W_CacheLumpName ("TEXTURE1", PU_STATIC);
+    maptex = maptex1 = W_CacheLumpName (DEH_String("TEXTURE1"), PU_STATIC);
     numtextures1 = LONG(*maptex);
-    maxoff = W_LumpLength (W_GetNumForName ("TEXTURE1"));
+    maxoff = W_LumpLength (W_GetNumForName (DEH_String("TEXTURE1")));
     directory = maptex+1;
        
-    if (W_CheckNumForName ("TEXTURE2") != -1)
+    if (W_CheckNumForName (DEH_String("TEXTURE2")) != -1)
     {
-       maptex2 = W_CacheLumpName ("TEXTURE2", PU_STATIC);
+       maptex2 = W_CacheLumpName (DEH_String("TEXTURE2"), PU_STATIC);
        numtextures2 = LONG(*maptex2);
-       maxoff2 = W_LumpLength (W_GetNumForName ("TEXTURE2"));
+       maxoff2 = W_LumpLength (W_GetNumForName (DEH_String("TEXTURE2")));
     }
     else
     {
@@ -492,27 +519,34 @@ void R_InitTextures (void)
     }
     numtextures = numtextures1 + numtextures2;
        
-    textures = Z_Malloc (numtextures*4, PU_STATIC, 0);
-    texturecolumnlump = Z_Malloc (numtextures*4, PU_STATIC, 0);
-    texturecolumnofs = Z_Malloc (numtextures*4, PU_STATIC, 0);
-    texturecomposite = Z_Malloc (numtextures*4, PU_STATIC, 0);
-    texturecompositesize = Z_Malloc (numtextures*4, PU_STATIC, 0);
-    texturewidthmask = Z_Malloc (numtextures*4, PU_STATIC, 0);
-    textureheight = Z_Malloc (numtextures*4, PU_STATIC, 0);
+    textures = Z_Malloc (numtextures * sizeof(*textures), PU_STATIC, 0);
+    texturecolumnlump = Z_Malloc (numtextures * sizeof(*texturecolumnlump), PU_STATIC, 0);
+    texturecolumnofs = Z_Malloc (numtextures * sizeof(*texturecolumnofs), PU_STATIC, 0);
+    texturecomposite = Z_Malloc (numtextures * sizeof(*texturecomposite), PU_STATIC, 0);
+    texturecompositesize = Z_Malloc (numtextures * sizeof(*texturecompositesize), PU_STATIC, 0);
+    texturewidthmask = Z_Malloc (numtextures * sizeof(*texturewidthmask), PU_STATIC, 0);
+    textureheight = Z_Malloc (numtextures * sizeof(*textureheight), PU_STATIC, 0);
 
     totalwidth = 0;
     
     // Really complex printing shit...
-    temp1 = W_GetNumForName ("S_START");  // P_???????
-    temp2 = W_GetNumForName ("S_END") - 1;
+    temp1 = W_GetNumForName (DEH_String("S_START"));  // P_???????
+    temp2 = W_GetNumForName (DEH_String("S_END")) - 1;
     temp3 = ((temp2-temp1+63)/64) + ((numtextures+63)/64);
-    printf("[");
-    for (i = 0; i < temp3; i++)
-       printf(" ");
-    printf("         ]");
-    for (i = 0; i < temp3; i++)
-       printf("\x8");
-    printf("\x8\x8\x8\x8\x8\x8\x8\x8\x8\x8");  
+
+    // If stdout is a real console, use the classic vanilla "filling
+    // up the box" effect, which uses backspace to "step back" inside
+    // the box.  If stdout is a file, don't draw the box.
+
+    if (I_ConsoleStdout())
+    {
+        printf("[");
+        for (i = 0; i < temp3 + 9; i++)
+            printf(" ");
+        printf("]");
+        for (i = 0; i < temp3 + 10; i++)
+            printf("\b");
+    }
        
     for (i=0 ; i<numtextures ; i++, directory++)
     {
@@ -542,7 +576,7 @@ void R_InitTextures (void)
        texture->width = SHORT(mtexture->width);
        texture->height = SHORT(mtexture->height);
        texture->patchcount = SHORT(mtexture->patchcount);
-
+       
        memcpy (texture->name, mtexture->name, sizeof(texture->name));
        mpatch = &mtexture->patches[0];
        patch = &texture->patches[0];
@@ -558,8 +592,8 @@ void R_InitTextures (void)
                         texture->name);
            }
        }               
-       texturecolumnlump[i] = Z_Malloc (texture->width*2, PU_STATIC,0);
-       texturecolumnofs[i] = Z_Malloc (texture->width*2, PU_STATIC,0);
+       texturecolumnlump[i] = Z_Malloc (texture->width*sizeof(**texturecolumnlump), PU_STATIC,0);
+       texturecolumnofs[i] = Z_Malloc (texture->width*sizeof(**texturecolumnofs), PU_STATIC,0);
 
        j = 1;
        while (j*2 <= texture->width)
@@ -571,21 +605,24 @@ void R_InitTextures (void)
        totalwidth += texture->width;
     }
 
-    Z_Free (maptex1);
+    Z_Free(patchlookup);
+
+    W_ReleaseLumpName(DEH_String("TEXTURE1"));
     if (maptex2)
-       Z_Free (maptex2);
+        W_ReleaseLumpName(DEH_String("TEXTURE2"));
     
     // Precalculate whatever possible. 
+
     for (i=0 ; i<numtextures ; i++)
        R_GenerateLookup (i);
     
     // Create translation table for global animation.
-    texturetranslation = Z_Malloc ((numtextures+1)*4, PU_STATIC, 0);
+    texturetranslation = Z_Malloc ((numtextures+1)*sizeof(*texturetranslation), PU_STATIC, 0);
     
     for (i=0 ; i<numtextures ; i++)
        texturetranslation[i] = i;
 
-    free(patchlookup_alloc);
+    GenerateTextureHashTable();
 }
 
 
@@ -597,12 +634,12 @@ void R_InitFlats (void)
 {
     int                i;
        
-    firstflat = W_GetNumForName ("F_START") + 1;
-    lastflat = W_GetNumForName ("F_END") - 1;
+    firstflat = W_GetNumForName (DEH_String("F_START")) + 1;
+    lastflat = W_GetNumForName (DEH_String("F_END")) - 1;
     numflats = lastflat - firstflat + 1;
        
     // Create translation table for global animation.
-    flattranslation = Z_Malloc ((numflats+1)*4, PU_STATIC, 0);
+    flattranslation = Z_Malloc ((numflats+1)*sizeof(*flattranslation), PU_STATIC, 0);
     
     for (i=0 ; i<numflats ; i++)
        flattranslation[i] = i;
@@ -620,13 +657,13 @@ void R_InitSpriteLumps (void)
     int                i;
     patch_t    *patch;
        
-    firstspritelump = W_GetNumForName ("S_START") + 1;
-    lastspritelump = W_GetNumForName ("S_END") - 1;
+    firstspritelump = W_GetNumForName (DEH_String("S_START")) + 1;
+    lastspritelump = W_GetNumForName (DEH_String("S_END")) - 1;
     
     numspritelumps = lastspritelump - firstspritelump + 1;
-    spritewidth = Z_Malloc (numspritelumps*4, PU_STATIC, 0);
-    spriteoffset = Z_Malloc (numspritelumps*4, PU_STATIC, 0);
-    spritetopoffset = Z_Malloc (numspritelumps*4, PU_STATIC, 0);
+    spritewidth = Z_Malloc (numspritelumps*sizeof(*spritewidth), PU_STATIC, 0);
+    spriteoffset = Z_Malloc (numspritelumps*sizeof(*spriteoffset), PU_STATIC, 0);
+    spritetopoffset = Z_Malloc (numspritelumps*sizeof(*spritetopoffset), PU_STATIC, 0);
        
     for (i=0 ; i< numspritelumps ; i++)
     {
@@ -647,15 +684,12 @@ void R_InitSpriteLumps (void)
 //
 void R_InitColormaps (void)
 {
-    int        lump, length;
-    
+    int        lump;
+
     // Load in the light tables, 
     //  256 byte align tables.
-    lump = W_GetNumForName("COLORMAP"); 
-    length = W_LumpLength (lump) + 255; 
-    colormaps = Z_Malloc (length, PU_STATIC, 0); 
-    colormaps = (byte *)( ((int)colormaps + 255)&~0xff); 
-    W_ReadLump (lump,colormaps); 
+    lump = W_GetNumForName(DEH_String("COLORMAP"));
+    colormaps = W_CacheLumpNum(lump, PU_STATIC);
 }
 
 
@@ -669,13 +703,12 @@ void R_InitColormaps (void)
 void R_InitData (void)
 {
     R_InitTextures ();
-    printf ("\nInitTextures");
+    printf (".");
     R_InitFlats ();
-    printf ("\nInitFlats");
+    printf (".");
     R_InitSpriteLumps ();
-    printf ("\nInitSprites");
+    printf (".");
     R_InitColormaps ();
-    printf ("\nInitColormaps");
 }
 
 
@@ -710,16 +743,25 @@ int R_FlatNumForName (char* name)
 //
 int    R_CheckTextureNumForName (char *name)
 {
-    int                i;
+    texture_t *texture;
+    int key;
 
     // "NoTexture" marker.
     if (name[0] == '-')                
        return 0;
                
-    for (i=0 ; i<numtextures ; i++)
-       if (!strncasecmp (textures[i]->name, name, 8) )
-           return i;
-               
+    key = W_LumpNameHash(name) % numtextures;
+
+    texture=textures_hashtable[key]; 
+    
+    while (texture != NULL)
+    {
+       if (!strncasecmp (texture->name, name, 8) )
+           return texture->index;
+
+        texture = texture->next;
+    }
+    
     return -1;
 }
 
@@ -758,11 +800,8 @@ int                spritememory;
 void R_PrecacheLevel (void)
 {
     char*              flatpresent;
-    char*              flatpresent_alloc;
     char*              texturepresent;
-    char*              texturepresent_alloc;
     char*              spritepresent;
-    char*              spritepresent_alloc;
 
     int                        i;
     int                        j;
@@ -777,11 +816,7 @@ void R_PrecacheLevel (void)
        return;
     
     // Precache flats.
-    //XXX flatpresent = alloca(numflats);
-    flatpresent = malloc(numflats);
-    flatpresent_alloc = flatpresent;
-    if (!flatpresent)
-        return;
+    flatpresent = Z_Malloc(numflats, PU_STATIC, NULL);
     memset (flatpresent,0,numflats);   
 
     for (i=0 ; i<numsectors ; i++)
@@ -802,14 +837,10 @@ void R_PrecacheLevel (void)
        }
     }
 
-    free(flatpresent_alloc);
+    Z_Free(flatpresent);
     
     // Precache textures.
-    //XXX texturepresent = alloca(numtextures);
-    texturepresent = malloc(numtextures);
-    texturepresent_alloc = texturepresent;
-    if (!texturepresent)
-        return;
+    texturepresent = Z_Malloc(numtextures, PU_STATIC, NULL);
     memset (texturepresent,0, numtextures);
        
     for (i=0 ; i<numsides ; i++)
@@ -843,14 +874,10 @@ void R_PrecacheLevel (void)
        }
     }
 
-    free(texturepresent_alloc);
+    Z_Free(texturepresent);
     
     // Precache sprites.
-    //XXX spritepresent = alloca(numsprites);
-    spritepresent = malloc(numsprites);
-    spritepresent_alloc = spritepresent;
-    if (!spritepresent)
-        return;
+    spritepresent = Z_Malloc(numsprites, PU_STATIC, NULL);
     memset (spritepresent,0, numsprites);
        
     for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
@@ -877,7 +904,7 @@ void R_PrecacheLevel (void)
        }
     }
 
-    free(spritepresent_alloc);
+    Z_Free(spritepresent);
 }
 
 
index 7f5a23dfab7e85cbff3d19414846ec9d7b660fac..66425afad7cd7c0d0aeb561b981fa5d5a35ae5b4 100644 (file)
@@ -1,24 +1,21 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //  Refresh module, data I/O, caching, retrieval of graphics
 //  by name.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __R_DATA__
@@ -27,9 +24,6 @@
 #include "r_defs.h"
 #include "r_state.h"
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 // Retrieve column data for span blitting.
 byte*
@@ -55,8 +49,3 @@ int R_TextureNumForName (char *name);
 int R_CheckTextureNumForName (char *name);
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 6c842a5194c35f0241dfd35bc180539e20322efa..a64ac8424acd9bb24161f3ba58e9e5fbe16e191d 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //      Refresh/rendering module, shared data struct definitions.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __R_DEFS__
 // SECTORS do store MObjs anyway.
 #include "p_mobj.h"
 
+#include "i_video.h"
 
+#include "v_patch.h"
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 
 
@@ -281,18 +277,6 @@ typedef struct
 
 
 
-// posts are runs of non masked source pixels
-typedef struct
-{
-    byte               topdelta;       // -1 is the last post in a column
-    byte               length;         // length data bytes follows
-} post_t;
-
-// column_t is a list of 0 or more post_t, (byte)-1 terminated
-typedef post_t column_t;
-
-
-
 // PC direct to screen pointers
 //B UNUSED - keep till detailshift in r_draw.c resolved
 //extern byte* destview;
@@ -348,27 +332,6 @@ typedef struct drawseg_s
 
 
 
-// Patches.
-// A patch holds one or more columns.
-// Patches are used for sprites and all masked pictures,
-// and we compose textures from the TEXTURE1/2 lists
-// of patches.
-typedef struct 
-{ 
-    short              width;          // bounding box size 
-    short              height; 
-    short              leftoffset;     // pixels to the left of origin 
-    short              topoffset;      // pixels below the origin 
-    int                        columnofs[8];   // only [width] used
-    // the [0] is &columnofs[width] 
-} patch_t;
-
-
-
-
-
-
-
 // A vissprite_t is a thing
 //  that will be drawn during a refresh.
 // I.e. a sprite object that is partly visible.
@@ -483,8 +446,3 @@ typedef struct
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 014504496246d963b74291e7bc153034e74ba98f..9271bcd554bce0d4af63232a09074b799403b58e 100644 (file)
@@ -1,34 +1,28 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     The actual span/column drawing functions.
 //     Here find the main potential for optimization,
 //      e.g. inline assembly, different algorithms.
 //
-//-----------------------------------------------------------------------------
 
 
-static const char
-rcsid[] = "$Id: r_draw.c,v 1.4 1997/02/03 16:47:55 b1 Exp $";
 
 
 #include "doomdef.h"
+#include "deh_main.h"
 
 #include "i_system.h"
 #include "z_zone.h"
@@ -75,7 +69,10 @@ int          columnofs[MAXWIDTH];
 //
 byte           translations[3][256];   
  
+// Backing buffer containing the bezel drawn around the screen and 
+// surrounding background.
+
+static byte *background_buffer = NULL;
 
 
 //
@@ -215,6 +212,7 @@ void R_DrawColumnLow (void)
     byte*              dest2;
     fixed_t            frac;
     fixed_t            fracstep;        
+    int                 x;
  
     count = dc_yh - dc_yl; 
 
@@ -233,10 +231,10 @@ void R_DrawColumnLow (void)
     // dccount++; 
 #endif 
     // Blocky mode, need to multiply by 2.
-    dc_x <<= 1;
+    x = dc_x << 1;
     
-    dest = ylookup[dc_yl] + columnofs[dc_x];
-    dest2 = ylookup[dc_yl] + columnofs[dc_x+1];
+    dest = ylookup[dc_yl] + columnofs[x];
+    dest2 = ylookup[dc_yl] + columnofs[x+1];
     
     fracstep = dc_iscale; 
     frac = dc_texturemid + (dc_yl-centery)*fracstep;
@@ -303,7 +301,6 @@ void R_DrawFuzzColumn (void)
     if (count < 0) 
        return; 
 
-    
 #ifdef RANGECHECK 
     if ((unsigned)dc_x >= SCREENWIDTH
        || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
@@ -312,35 +309,74 @@ void R_DrawFuzzColumn (void)
                 dc_yl, dc_yh, dc_x);
     }
 #endif
+    
+    dest = ylookup[dc_yl] + columnofs[dc_x];
 
+    // Looks familiar.
+    fracstep = dc_iscale; 
+    frac = dc_texturemid + (dc_yl-centery)*fracstep; 
 
-    // Keep till detailshift bug in blocky mode fixed,
-    //  or blocky mode removed.
-    /* WATCOM code 
-    if (detailshift)
-    {
-       if (dc_x & 1)
-       {
-           outpw (GC_INDEX,GC_READMAP+(2<<8) ); 
-           outp (SC_INDEX+1,12); 
-       }
-       else
-       {
-           outpw (GC_INDEX,GC_READMAP); 
-           outp (SC_INDEX+1,3); 
-       }
-       dest = destview + dc_yl*80 + (dc_x>>1); 
-    }
-    else
+    // Looks like an attempt at dithering,
+    //  using the colormap #6 (of 0-31, a bit
+    //  brighter than average).
+    do 
     {
-       outpw (GC_INDEX,GC_READMAP+((dc_x&3)<<8) ); 
-       outp (SC_INDEX+1,1<<(dc_x&3)); 
-       dest = destview + dc_yl*80 + (dc_x>>2); 
-    }*/
+       // Lookup framebuffer, and retrieve
+       //  a pixel that is either one column
+       //  left or right of the current one.
+       // Add index from colormap to index.
+       *dest = colormaps[6*256+dest[fuzzoffset[fuzzpos]]]; 
+
+       // Clamp table lookup index.
+       if (++fuzzpos == FUZZTABLE) 
+           fuzzpos = 0;
+       
+       dest += SCREENWIDTH;
+
+       frac += fracstep; 
+    } while (count--); 
+} 
+
+// low detail mode version
+void R_DrawFuzzColumnLow (void) 
+{ 
+    int                        count; 
+    byte*              dest; 
+    byte*              dest2; 
+    fixed_t            frac;
+    fixed_t            fracstep;        
+    int x;
 
+    // Adjust borders. Low... 
+    if (!dc_yl) 
+       dc_yl = 1;
+
+    // .. and high.
+    if (dc_yh == viewheight-1) 
+       dc_yh = viewheight - 2; 
+                
+    count = dc_yh - dc_yl; 
+
+    // Zero length.
+    if (count < 0) 
+       return; 
+
+    // low detail mode, need to multiply by 2
     
-    // Does not work with blocky mode.
-    dest = ylookup[dc_yl] + columnofs[dc_x];
+    x = dc_x << 1;
+    
+#ifdef RANGECHECK 
+    if ((unsigned)x >= SCREENWIDTH
+       || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+    {
+       I_Error ("R_DrawFuzzColumn: %i to %i at %i",
+                dc_yl, dc_yh, dc_x);
+    }
+#endif
+    
+    dest = ylookup[dc_yl] + columnofs[x];
+    dest2 = ylookup[dc_yl] + columnofs[x+1];
 
     // Looks familiar.
     fracstep = dc_iscale; 
@@ -356,18 +392,21 @@ void R_DrawFuzzColumn (void)
        //  left or right of the current one.
        // Add index from colormap to index.
        *dest = colormaps[6*256+dest[fuzzoffset[fuzzpos]]]; 
+       *dest2 = colormaps[6*256+dest2[fuzzoffset[fuzzpos]]]; 
 
        // Clamp table lookup index.
        if (++fuzzpos == FUZZTABLE) 
            fuzzpos = 0;
        
        dest += SCREENWIDTH;
+       dest2 += SCREENWIDTH;
 
        frac += fracstep; 
     } while (count--); 
 } 
  
   
+  
  
 
 //
@@ -405,27 +444,57 @@ void R_DrawTranslatedColumn (void)
 #endif 
 
 
-    // WATCOM VGA specific.
-    /* Keep for fixing.
-    if (detailshift)
+    dest = ylookup[dc_yl] + columnofs[dc_x]; 
+
+    // Looks familiar.
+    fracstep = dc_iscale; 
+    frac = dc_texturemid + (dc_yl-centery)*fracstep; 
+
+    // Here we do an additional index re-mapping.
+    do 
     {
-       if (dc_x & 1)
-           outp (SC_INDEX+1,12); 
-       else
-           outp (SC_INDEX+1,3);
+       // Translation tables are used
+       //  to map certain colorramps to other ones,
+       //  used with PLAY sprites.
+       // Thus the "green" ramp of the player 0 sprite
+       //  is mapped to gray, red, black/indigo. 
+       *dest = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]];
+       dest += SCREENWIDTH;
        
-       dest = destview + dc_yl*80 + (dc_x>>1); 
-    }
-    else
-    {
-       outp (SC_INDEX+1,1<<(dc_x&3)); 
+       frac += fracstep; 
+    } while (count--); 
+} 
 
-       dest = destview + dc_yl*80 + (dc_x>>2); 
-    }*/
+void R_DrawTranslatedColumnLow (void) 
+{ 
+    int                        count; 
+    byte*              dest; 
+    byte*              dest2; 
+    fixed_t            frac;
+    fixed_t            fracstep;        
+    int                 x;
+    count = dc_yh - dc_yl; 
+    if (count < 0) 
+       return; 
 
+    // low detail, need to scale by 2
+    x = dc_x << 1;
+                                
+#ifdef RANGECHECK 
+    if ((unsigned)x >= SCREENWIDTH
+       || dc_yl < 0
+       || dc_yh >= SCREENHEIGHT)
+    {
+       I_Error ( "R_DrawColumn: %i to %i at %i",
+                 dc_yl, dc_yh, x);
+    }
     
-    // FIXME. As above.
-    dest = ylookup[dc_yl] + columnofs[dc_x]; 
+#endif 
+
+
+    dest = ylookup[dc_yl] + columnofs[x]; 
+    dest2 = ylookup[dc_yl] + columnofs[x+1]; 
 
     // Looks familiar.
     fracstep = dc_iscale; 
@@ -440,7 +509,9 @@ void R_DrawTranslatedColumn (void)
        // Thus the "green" ramp of the player 0 sprite
        //  is mapped to gray, red, black/indigo. 
        *dest = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]];
+       *dest2 = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]];
        dest += SCREENWIDTH;
+       dest2 += SCREENWIDTH;
        
        frac += fracstep; 
     } while (count--); 
@@ -460,8 +531,7 @@ void R_InitTranslationTables (void)
 {
     int                i;
        
-    translationtables = Z_Malloc (256*3+255, PU_STATIC, 0);
-    translationtables = (byte *)(( (int)translationtables + 255 )& ~255);
+    translationtables = Z_Malloc (256*3, PU_STATIC, 0);
     
     // translate just the 16 green colors
     for (i=0 ; i<256 ; i++)
@@ -519,48 +589,54 @@ int                       dscount;
 // Draws the actual span.
 void R_DrawSpan (void) 
 { 
-    fixed_t            xfrac;
-    fixed_t            yfrac; 
-    byte*              dest; 
-    int                        count;
-    int                        spot; 
-        
-#ifdef RANGECHECK 
+    unsigned int position, step;
+    byte *dest;
+    int count;
+    int spot;
+    unsigned int xtemp, ytemp;
+
+#ifdef RANGECHECK
     if (ds_x2 < ds_x1
        || ds_x1<0
-       || ds_x2>=SCREENWIDTH  
+       || ds_x2>=SCREENWIDTH
        || (unsigned)ds_y>SCREENHEIGHT)
     {
        I_Error( "R_DrawSpan: %i to %i at %i",
                 ds_x1,ds_x2,ds_y);
     }
-//     dscount++; 
-#endif 
+//     dscount++;
+#endif
+
+    // Pack position and step variables into a single 32-bit integer,
+    // with x in the top 16 bits and y in the bottom 16 bits.  For
+    // each 16-bit part, the top 6 bits are the integer part and the
+    // bottom 10 bits are the fractional part of the pixel position.
+
+    position = ((ds_xfrac << 10) & 0xffff0000)
+             | ((ds_yfrac >> 6)  & 0x0000ffff);
+    step = ((ds_xstep << 10) & 0xffff0000)
+         | ((ds_ystep >> 6)  & 0x0000ffff);
 
-    
-    xfrac = ds_xfrac; 
-    yfrac = ds_yfrac; 
-        
     dest = ylookup[ds_y] + columnofs[ds_x1];
 
     // We do not check for zero spans here?
-    count = ds_x2 - ds_x1; 
+    count = ds_x2 - ds_x1;
 
-    do 
+    do
     {
-       // Current texture index in u,v.
-       spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63);
+       // Calculate current texture index in u,v.
+        ytemp = (position >> 4) & 0x0fc0;
+        xtemp = (position >> 26);
+        spot = xtemp | ytemp;
 
        // Lookup pixel from flat texture tile,
        //  re-index using light/colormap.
        *dest++ = ds_colormap[ds_source[spot]];
 
-       // Next step in u,v.
-       xfrac += ds_xstep; 
-       yfrac += ds_ystep;
-       
-    } while (count--); 
-} 
+        position += step;
+
+    } while (count--);
+}
 
 
 
@@ -640,49 +716,54 @@ void R_DrawSpan (void)
 //
 // Again..
 //
-void R_DrawSpanLow (void) 
-{ 
-    fixed_t            xfrac;
-    fixed_t            yfrac; 
-    byte*              dest; 
-    int                        count;
-    int                        spot; 
-        
-#ifdef RANGECHECK 
+void R_DrawSpanLow (void)
+{
+    unsigned int position, step;
+    unsigned int xtemp, ytemp;
+    byte *dest;
+    int count;
+    int spot;
+
+#ifdef RANGECHECK
     if (ds_x2 < ds_x1
        || ds_x1<0
-       || ds_x2>=SCREENWIDTH  
+       || ds_x2>=SCREENWIDTH
        || (unsigned)ds_y>SCREENHEIGHT)
     {
        I_Error( "R_DrawSpan: %i to %i at %i",
                 ds_x1,ds_x2,ds_y);
     }
 //     dscount++; 
-#endif 
-        
-    xfrac = ds_xfrac; 
-    yfrac = ds_yfrac; 
+#endif
+
+    position = ((ds_xfrac << 10) & 0xffff0000)
+             | ((ds_yfrac >> 6)  & 0x0000ffff);
+    step = ((ds_xstep << 10) & 0xffff0000)
+         | ((ds_ystep >> 6)  & 0x0000ffff);
+
+    count = (ds_x2 - ds_x1);
 
     // Blocky mode, need to multiply by 2.
     ds_x1 <<= 1;
     ds_x2 <<= 1;
-    
+
     dest = ylookup[ds_y] + columnofs[ds_x1];
-  
-    
-    count = ds_x2 - ds_x1; 
-    do 
-    { 
-       spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63);
+
+    do
+    {
+       // Calculate current texture index in u,v.
+        ytemp = (position >> 4) & 0x0fc0;
+        xtemp = (position >> 26);
+        spot = xtemp | ytemp;
+
        // Lowres/blocky mode does it twice,
        //  while scale is adjusted appropriately.
-       *dest++ = ds_colormap[ds_source[spot]]; 
        *dest++ = ds_colormap[ds_source[spot]];
-       
-       xfrac += ds_xstep; 
-       yfrac += ds_ystep; 
+       *dest++ = ds_colormap[ds_source[spot]];
 
-    } while (count--); 
+       position += step;
+
+    } while (count--);
 }
 
 //
@@ -716,7 +797,7 @@ R_InitBuffer
 
     // Preclaculate all row offsets.
     for (i=0 ; i<height ; i++) 
-       ylookup[i] = screens[0] + (i+viewwindowy)*SCREENWIDTH; 
+       ylookup[i] = I_VideoBuffer + (i+viewwindowy)*SCREENWIDTH; 
 } 
  
  
@@ -737,23 +818,42 @@ void R_FillBackScreen (void)
     patch_t*   patch;
 
     // DOOM border patch.
-    char       name1[] = "FLOOR7_2";
+    char       *name1 = DEH_String("FLOOR7_2");
 
     // DOOM II border patch.
-    char       name2[] = "GRNROCK";    
+    char *name2 = DEH_String("GRNROCK");
+
+    char *name;
+
+    // If we are running full screen, there is no need to do any of this,
+    // and the background buffer can be freed if it was previously in use.
+
+    if (scaledviewwidth == SCREENWIDTH)
+    {
+        if (background_buffer != NULL)
+        {
+            Z_Free(background_buffer);
+            background_buffer = NULL;
+        }
 
-    char*      name;
-       
-    if (scaledviewwidth == 320)
        return;
+    }
+
+    // Allocate the background buffer if necessary
        
-    if ( gamemode == commercial)
+    if (background_buffer == NULL)
+    {
+        background_buffer = Z_Malloc(SCREENWIDTH * (SCREENHEIGHT - SBARHEIGHT),
+                                     PU_STATIC, NULL);
+    }
+
+    if (gamemode == commercial)
        name = name2;
     else
        name = name1;
     
-    src = W_CacheLumpName (name, PU_CACHE); 
-    dest = screens[1]; 
+    src = W_CacheLumpName(name, PU_CACHE); 
+    dest = background_buffer;
         
     for (y=0 ; y<SCREENHEIGHT-SBARHEIGHT ; y++) 
     { 
@@ -769,45 +869,46 @@ void R_FillBackScreen (void)
            dest += (SCREENWIDTH&63); 
        } 
     } 
-       
-    patch = W_CacheLumpName ("brdr_t",PU_CACHE);
+     
+    // Draw screen and bezel; this is done to a separate screen buffer.
+
+    V_UseBuffer(background_buffer);
+
+    patch = W_CacheLumpName(DEH_String("brdr_t"),PU_CACHE);
 
     for (x=0 ; x<scaledviewwidth ; x+=8)
-       V_DrawPatch (viewwindowx+x,viewwindowy-8,1,patch);
-    patch = W_CacheLumpName ("brdr_b",PU_CACHE);
+       V_DrawPatch(viewwindowx+x, viewwindowy-8, patch);
+    patch = W_CacheLumpName(DEH_String("brdr_b"),PU_CACHE);
 
     for (x=0 ; x<scaledviewwidth ; x+=8)
-       V_DrawPatch (viewwindowx+x,viewwindowy+viewheight,1,patch);
-    patch = W_CacheLumpName ("brdr_l",PU_CACHE);
+       V_DrawPatch(viewwindowx+x, viewwindowy+viewheight, patch);
+    patch = W_CacheLumpName(DEH_String("brdr_l"),PU_CACHE);
 
     for (y=0 ; y<viewheight ; y+=8)
-       V_DrawPatch (viewwindowx-8,viewwindowy+y,1,patch);
-    patch = W_CacheLumpName ("brdr_r",PU_CACHE);
+       V_DrawPatch(viewwindowx-8, viewwindowy+y, patch);
+    patch = W_CacheLumpName(DEH_String("brdr_r"),PU_CACHE);
 
     for (y=0 ; y<viewheight ; y+=8)
-       V_DrawPatch (viewwindowx+scaledviewwidth,viewwindowy+y,1,patch);
-
+       V_DrawPatch(viewwindowx+scaledviewwidth, viewwindowy+y, patch);
 
     // Draw beveled edge. 
-    V_DrawPatch (viewwindowx-8,
-                viewwindowy-8,
-                1,
-                W_CacheLumpName ("brdr_tl",PU_CACHE));
+    V_DrawPatch(viewwindowx-8,
+                viewwindowy-8,
+                W_CacheLumpName(DEH_String("brdr_tl"),PU_CACHE));
     
-    V_DrawPatch (viewwindowx+scaledviewwidth,
-                viewwindowy-8,
-                1,
-                W_CacheLumpName ("brdr_tr",PU_CACHE));
+    V_DrawPatch(viewwindowx+scaledviewwidth,
+                viewwindowy-8,
+                W_CacheLumpName(DEH_String("brdr_tr"),PU_CACHE));
     
-    V_DrawPatch (viewwindowx-8,
-                viewwindowy+viewheight,
-                1,
-                W_CacheLumpName ("brdr_bl",PU_CACHE));
+    V_DrawPatch(viewwindowx-8,
+                viewwindowy+viewheight,
+                W_CacheLumpName(DEH_String("brdr_bl"),PU_CACHE));
     
-    V_DrawPatch (viewwindowx+scaledviewwidth,
-                viewwindowy+viewheight,
-                1,
-                W_CacheLumpName ("brdr_br",PU_CACHE));
+    V_DrawPatch(viewwindowx+scaledviewwidth,
+                viewwindowy+viewheight,
+                W_CacheLumpName(DEH_String("brdr_br"),PU_CACHE));
+
+    V_RestoreBuffer();
 } 
  
 
@@ -824,7 +925,11 @@ R_VideoErase
   //  is not optiomal, e.g. byte by byte on
   //  a 32bit CPU, as GNU GCC/Linux libc did
   //  at one point.
-    memcpy (screens[0]+ofs, screens[1]+ofs, count); 
+
+    if (background_buffer != NULL)
+    {
+        memcpy(I_VideoBuffer + ofs, background_buffer + ofs, count); 
+    }
 } 
 
 
@@ -833,13 +938,6 @@ R_VideoErase
 // Draws the border around the view
 //  for different size windows?
 //
-void
-V_MarkRect
-( int          x,
-  int          y,
-  int          width,
-  int          height ); 
 void R_DrawViewBorder (void) 
 { 
     int                top;
index 534fffd94409c4256dde6d63edcac228fe9993d7..5b0c818b599d2843043fef4e082514d992edaa68 100644 (file)
@@ -1,32 +1,26 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     System specific interface stuff.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __R_DRAW__
 #define __R_DRAW__
 
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 
 extern lighttable_t*   dc_colormap;
@@ -108,8 +102,3 @@ void R_DrawViewBorder (void);
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index af23f2a03877366b7c562f2d4f2f739a1337edf4..1b9249210cd90f30da1398179544247559fc0a5a 100644 (file)
@@ -1,24 +1,21 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Refresh (R_*) module, global header.
 //     All the rendering/drawing stuff is here.
 //
-//-----------------------------------------------------------------------------
 
 #ifndef __R_LOCAL__
 #define __R_LOCAL__
@@ -46,8 +43,3 @@
 #include "r_draw.h"
 
 #endif         // __R_LOCAL__
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index ad942c7c66334369bc90f4b32de3cb7e1213e087..22278fe36a9d316e3fd5430833bb3352567c73a8 100644 (file)
@@ -1,30 +1,24 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Rendering main loop and setup functions,
 //      utility functions (BSP, geometry, trigonometry).
 //     See tables.c, too.
 //
-//-----------------------------------------------------------------------------
 
 
-static const char rcsid[] = "$Id: r_main.c,v 1.5 1997/02/03 22:45:12 b1 Exp $";
 
 
 
@@ -33,9 +27,10 @@ static const char rcsid[] = "$Id: r_main.c,v 1.5 1997/02/03 22:45:12 b1 Exp $";
 
 
 #include "doomdef.h"
-#include "d_net.h"
+#include "d_loop.h"
 
 #include "m_bbox.h"
+#include "m_menu.h"
 
 #include "r_local.h"
 #include "r_sky.h"
@@ -102,17 +97,6 @@ int                 viewangletox[FINEANGLES/2];
 // from clipangle to -clipangle.
 angle_t                        xtoviewangle[SCREENWIDTH+1];
 
-
-// UNUSED.
-// The finetangentgent[angle+FINEANGLES/4] table
-// holds the fixed_t tangent values for view angles,
-// ranging from MININT to 0 to MAXINT.
-// fixed_t             finetangent[FINEANGLES/2];
-
-// fixed_t             finesine[5*FINEANGLES/4];
-fixed_t*               finecosine = &finesine[FINEANGLES/4];
-
-
 lighttable_t*          scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
 lighttable_t*          scalelightfixed[MAXLIGHTSCALE];
 lighttable_t*          zlight[LIGHTLEVELS][MAXLIGHTZ];
@@ -398,6 +382,7 @@ R_PointToDist
     fixed_t    dy;
     fixed_t    temp;
     fixed_t    dist;
+    fixed_t     frac;
        
     dx = abs(x - viewx);
     dy = abs(y - viewy);
@@ -408,8 +393,19 @@ R_PointToDist
        dx = dy;
        dy = temp;
     }
+
+    // Fix crashes in udm1.wad
+
+    if (dx != 0)
+    {
+        frac = FixedDiv(dy, dx);
+    }
+    else
+    {
+       frac = 0;
+    }
        
-    angle = (tantoangle[ FixedDiv(dy,dx)>>DBITS ]+ANG90) >> ANGLETOFINESHIFT;
+    angle = (tantoangle[frac>>DBITS]+ANG90) >> ANGLETOFINESHIFT;
 
     // use as cosine
     dist = FixedDiv (dx, finesine[angle] );    
@@ -453,8 +449,8 @@ void R_InitPointToAngle (void)
 fixed_t R_ScaleFromGlobalAngle (angle_t visangle)
 {
     fixed_t            scale;
-    int                        anglea;
-    int                        angleb;
+    angle_t            anglea;
+    angle_t            angleb;
     int                        sinea;
     int                        sineb;
     fixed_t            num;
@@ -709,8 +705,8 @@ void R_ExecuteSetViewSize (void)
     else
     {
        colfunc = basecolfunc = R_DrawColumnLow;
-       fuzzcolfunc = R_DrawFuzzColumn;
-       transcolfunc = R_DrawTranslatedColumn;
+       fuzzcolfunc = R_DrawFuzzColumnLow;
+       transcolfunc = R_DrawTranslatedColumnLow;
        spanfunc = R_DrawSpanLow;
     }
 
@@ -765,30 +761,27 @@ void R_ExecuteSetViewSize (void)
 //
 // R_Init
 //
-extern int     detailLevel;
-extern int     screenblocks;
 
 
 
 void R_Init (void)
 {
     R_InitData ();
-    printf ("\nR_InitData");
+    printf (".");
     R_InitPointToAngle ();
-    printf ("\nR_InitPointToAngle");
+    printf (".");
     R_InitTables ();
     // viewwidth / viewheight / detailLevel are set by the defaults
-    printf ("\nR_InitTables");
+    printf (".");
 
     R_SetViewSize (screenblocks, detailLevel);
     R_InitPlanes ();
-    printf ("\nR_InitPlanes");
+    printf (".");
     R_InitLightTables ();
-    printf ("\nR_InitLightTables");
+    printf (".");
     R_InitSkyMap ();
-    printf ("\nR_InitSkyMap");
     R_InitTranslationTables ();
-    printf ("\nR_InitTranslationsTables");
+    printf (".");
        
     framecount = 0;
 }
index dff69d8afb18fff69feeb5a5686deaf76f47a76a..c05a9a01353476573a8a5fb2336b80720143120a 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     System specific interface stuff.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __R_MAIN__
@@ -27,9 +24,6 @@
 #include "r_data.h"
 
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 
 //
@@ -38,8 +32,6 @@
 extern fixed_t         viewcos;
 extern fixed_t         viewsin;
 
-extern int             viewwidth;
-extern int             viewheight;
 extern int             viewwindowx;
 extern int             viewwindowy;
 
@@ -98,6 +90,7 @@ extern        int             detailshift;
 // Used to select shadow mode etc.
 //
 extern void            (*colfunc) (void);
+extern void            (*transcolfunc) (void);
 extern void            (*basecolfunc) (void);
 extern void            (*fuzzcolfunc) (void);
 // No shadow effects on floors.
@@ -165,8 +158,3 @@ void R_Init (void);
 void R_SetViewSize (int blocks, int detail);
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index f6ac8e2225828d01d8429237c2d817464ecb0545..ea1611c2e2d2a0919963e3e62f23cf2c086d8a40 100644 (file)
@@ -1,32 +1,25 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Here is a core component: drawing the floors and ceilings,
 //      while maintaining a per column clipping list only.
 //     Moreover, the sky areas have to be determined.
 //
-//-----------------------------------------------------------------------------
-
 
-static const char
-rcsid[] = "$Id: r_plane.c,v 1.4 1997/02/03 16:47:55 b1 Exp $";
 
+#include <stdio.h>
 #include <stdlib.h>
 
 #include "i_system.h"
@@ -130,9 +123,9 @@ R_MapPlane
        
 #ifdef RANGECHECK
     if (x2 < x1
-       || x1<0
-       || x2>=viewwidth
-       || (unsigned)y>viewheight)
+     || x1 < 0
+     || x2 >= viewwidth
+     || y > viewheight)
     {
        I_Error ("R_MapPlane: %i, %i at %i",x1,x2,y);
     }
@@ -371,6 +364,7 @@ void R_DrawPlanes (void)
     int                        x;
     int                        stop;
     int                        angle;
+    int                 lumpnum;
                                
 #ifdef RANGECHECK
     if (ds_p - drawsegs > MAXDRAWSEGS)
@@ -420,9 +414,8 @@ void R_DrawPlanes (void)
        }
        
        // regular flat
-       ds_source = W_CacheLumpNum(firstflat +
-                                  flattranslation[pl->picnum],
-                                  PU_STATIC);
+        lumpnum = firstflat + flattranslation[pl->picnum];
+       ds_source = W_CacheLumpNum(lumpnum, PU_STATIC);
        
        planeheight = abs(pl->height-viewz);
        light = (pl->lightlevel >> LIGHTSEGSHIFT)+extralight;
@@ -448,6 +441,6 @@ void R_DrawPlanes (void)
                        pl->bottom[x]);
        }
        
-       Z_ChangeTag (ds_source, PU_CACHE);
+        W_ReleaseLumpNum(lumpnum);
     }
 }
index d2662336136bef656fb0e6d484e4916b10b0d85b..57b50e5bc5ee8c5840832a094c67418de143ac35 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Refresh, visplane stuff (floor, ceilings).
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __R_PLANE__
@@ -26,9 +23,6 @@
 
 #include "r_data.h"
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 
 // Visplane related.
@@ -80,8 +74,3 @@ R_CheckPlane
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 1962d9237381bddbe658e2a031e46dd0e1839eee..9b4e413c856345d46b2ccdd263a58c02c72f86e1 100644 (file)
@@ -1,34 +1,27 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     All the clipping: columns, horizontal spans, sky columns.
 //
-//-----------------------------------------------------------------------------
-
 
-static const char
-rcsid[] = "$Id: r_segs.c,v 1.3 1997/01/29 20:10:19 b1 Exp $";
 
 
 
 
 
+#include <stdio.h>
 #include <stdlib.h>
 
 #include "i_system.h"
@@ -162,7 +155,7 @@ R_RenderMaskedSegRange
     for (dc_x = x1 ; dc_x <= x2 ; dc_x++)
     {
        // calculate lighting
-       if (maskedtexturecol[dc_x] != MAXSHORT)
+       if (maskedtexturecol[dc_x] != SHRT_MAX)
        {
            if (!fixedcolormap)
            {
@@ -182,7 +175,7 @@ R_RenderMaskedSegRange
                (byte *)R_GetColumn(texnum,maskedtexturecol[dc_x]) -3);
                        
            R_DrawMaskedColumn (col);
-           maskedtexturecol[dc_x] = MAXSHORT;
+           maskedtexturecol[dc_x] = SHRT_MAX;
        }
        spryscale += rw_scalestep;
     }
@@ -214,8 +207,6 @@ void R_RenderSegLoop (void)
     int                        top;
     int                        bottom;
 
-    //texturecolumn = 0;                               // shut up compiler warning
-       
     for ( ; rw_x < rw_stopx ; rw_x++)
     {
        // mark floor / ceiling areas
@@ -275,6 +266,12 @@ void R_RenderSegLoop (void)
            dc_x = rw_x;
            dc_iscale = 0xffffffffu / (unsigned)rw_scale;
        }
+        else
+        {
+            // purely to shut up the compiler
+
+            texturecolumn = 0;
+        }
        
        // draw the wall tiers
        if (midtexture)
@@ -476,8 +473,8 @@ R_StoreWallRange
        ds_p->silhouette = SIL_BOTH;
        ds_p->sprtopclip = screenheightarray;
        ds_p->sprbottomclip = negonearray;
-       ds_p->bsilheight = MAXINT;
-       ds_p->tsilheight = MININT;
+       ds_p->bsilheight = INT_MAX;
+       ds_p->tsilheight = INT_MIN;
     }
     else
     {
@@ -493,7 +490,7 @@ R_StoreWallRange
        else if (backsector->floorheight > viewz)
        {
            ds_p->silhouette = SIL_BOTTOM;
-           ds_p->bsilheight = MAXINT;
+           ds_p->bsilheight = INT_MAX;
            // ds_p->sprbottomclip = negonearray;
        }
        
@@ -505,21 +502,21 @@ R_StoreWallRange
        else if (backsector->ceilingheight < viewz)
        {
            ds_p->silhouette |= SIL_TOP;
-           ds_p->tsilheight = MININT;
+           ds_p->tsilheight = INT_MIN;
            // ds_p->sprtopclip = screenheightarray;
        }
                
        if (backsector->ceilingheight <= frontsector->floorheight)
        {
            ds_p->sprbottomclip = negonearray;
-           ds_p->bsilheight = MAXINT;
+           ds_p->bsilheight = INT_MAX;
            ds_p->silhouette |= SIL_BOTTOM;
        }
        
        if (backsector->floorheight >= frontsector->ceilingheight)
        {
            ds_p->sprtopclip = screenheightarray;
-           ds_p->tsilheight = MININT;
+           ds_p->tsilheight = INT_MIN;
            ds_p->silhouette |= SIL_TOP;
        }
        
@@ -734,12 +731,12 @@ R_StoreWallRange
     if (maskedtexture && !(ds_p->silhouette&SIL_TOP))
     {
        ds_p->silhouette |= SIL_TOP;
-       ds_p->tsilheight = MININT;
+       ds_p->tsilheight = INT_MIN;
     }
     if (maskedtexture && !(ds_p->silhouette&SIL_BOTTOM))
     {
        ds_p->silhouette |= SIL_BOTTOM;
-       ds_p->bsilheight = MAXINT;
+       ds_p->bsilheight = INT_MAX;
     }
     ds_p++;
 }
index 1c376500007f1bb1e5b7b0c96cbcb65e2ed9bda3..d4a4d89964eaca9d9db051804d9509b9f6fae0db 100644 (file)
@@ -1,32 +1,26 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Refresh module, drawing LineSegs from BSP.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __R_SEGS__
 #define __R_SEGS__
 
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 
 void
@@ -37,8 +31,3 @@ R_RenderMaskedSegRange
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index b090ec07667fb321b2149ecd298a9c569b1c09f3..667c88d339e7574c8f25b99d6553d521fae045da 100644 (file)
@@ -1,20 +1,16 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //  Sky rendering. The DOOM sky is a texture map like any
 //  on a 320 screen?
 //  
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $";
 
 
 // Needed for FRACUNIT.
@@ -36,9 +29,6 @@ rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $";
 #include "r_data.h"
 
 
-#ifdef __GNUG__
-#pragma implementation "r_sky.h"
-#endif
 #include "r_sky.h"
 
 //
index 663f007bbe20e640f0bc405ee0a711e0b80666af..8ad6680aa5f475d798f76bafc4198fb0a5ea377e 100644 (file)
@@ -1,32 +1,26 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Sky rendering.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __R_SKY__
 #define __R_SKY__
 
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 // SKY, store the number for name.
 #define                        SKYFLATNAME  "F_SKY1"
@@ -41,8 +35,3 @@ extern int            skytexturemid;
 void R_InitSkyMap (void);
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 1fb6bf9df4ff5a1fce102c769a4af6c1ae0053df..2a60e2fe8e1a2176cd0d79dfb6680bb97d6dc0ee 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Refresh/render internal state variables (global).
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __R_STATE__
@@ -29,9 +26,6 @@
 
 
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 
 
@@ -131,8 +125,3 @@ extern visplane_t*  ceilingplane;
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 09c3653214052ea4c485d003e8d1031be0cf80ae..74e7369b8638f1b24f253775f238e87ab4ff8ee5 100644 (file)
@@ -1,38 +1,32 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Refresh of things, i.e. objects represented by sprites.
 //
-//-----------------------------------------------------------------------------
 
 
-static const char
-rcsid[] = "$Id: r_things.c,v 1.5 1997/02/03 16:47:56 b1 Exp $";
 
 
 #include <stdio.h>
 #include <stdlib.h>
 
 
+#include "deh_main.h"
 #include "doomdef.h"
-#include "m_swap.h"
 
+#include "i_swap.h"
 #include "i_system.h"
 #include "z_zone.h"
 #include "w_wad.h"
@@ -179,7 +173,6 @@ void R_InitSpriteDefs (char** namelist)
     char**     check;
     int                i;
     int                l;
-    int                intname;
     int                frame;
     int                rotation;
     int                start;
@@ -189,7 +182,7 @@ void R_InitSpriteDefs (char** namelist)
     // count the number of sprite names
     check = namelist;
     while (*check != NULL)
-        check++;
+       check++;
 
     numsprites = check-namelist;
        
@@ -206,17 +199,16 @@ void R_InitSpriteDefs (char** namelist)
     // Just compare 4 characters as ints
     for (i=0 ; i<numsprites ; i++)
     {
-       spritename = namelist[i];
+       spritename = DEH_String(namelist[i]);
        memset (sprtemp,-1, sizeof(sprtemp));
                
        maxframe = -1;
-       intname = *(int *)namelist[i];
        
        // scan the lumps,
        //  filling in the frames for whatever is found
        for (l=start+1 ; l<end ; l++)
        {
-           if (*(int *)lumpinfo[l].name == intname)
+           if (!strncasecmp(lumpinfo[l].name, spritename, 4))
            {
                frame = lumpinfo[l].name[4] - 'A';
                rotation = lumpinfo[l].name[5] - '0';
@@ -253,7 +245,7 @@ void R_InitSpriteDefs (char** namelist)
              case -1:
                // no rotations were found for that frame at all
                I_Error ("R_InitSprites: No patches found "
-                        "for %s frame %c", namelist[i], frame+'A');
+                        "for %s frame %c", spritename, frame+'A');
                break;
                
              case 0:
@@ -266,7 +258,7 @@ void R_InitSpriteDefs (char** namelist)
                    if (sprtemp[frame].lump[rotation] == -1)
                        I_Error ("R_InitSprites: Sprite %s frame %c "
                                 "is missing rotations",
-                                namelist[i], frame+'A');
+                                spritename, frame+'A');
                break;
            }
        }
@@ -416,7 +408,7 @@ R_DrawVisSprite
     }
     else if (vis->mobjflags & MF_TRANSLATION)
     {
-       colfunc = R_DrawTranslatedColumn;
+       colfunc = transcolfunc;
        dc_translation = translationtables - 256 +
            ( (vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT-8) );
     }
@@ -504,7 +496,7 @@ void R_ProjectSprite (mobj_t* thing)
     
     // decide which patch to use for sprite relative to player
 #ifdef RANGECHECK
-    if ((unsigned)thing->sprite >= numsprites)
+    if ((unsigned int) thing->sprite >= (unsigned int) numsprites)
        I_Error ("R_ProjectSprite: invalid sprite number %i ",
                 thing->sprite);
 #endif
@@ -657,7 +649,7 @@ void R_DrawPSprite (pspdef_t* psp)
     
     // decide which patch to use
 #ifdef RANGECHECK
-    if ( (unsigned)psp->state->sprite >= numsprites)
+    if ( (unsigned)psp->state->sprite >= (unsigned int) numsprites)
        I_Error ("R_ProjectSprite: invalid sprite number %i ",
                 psp->state->sprite);
 #endif
@@ -812,11 +804,12 @@ void R_SortVisSprites (void)
     unsorted.prev = vissprite_p-1;
     
     // pull the vissprites out by scale
-    //best = 0;                // shut up the compiler warning
+
     vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead;
     for (i=0 ; i<count ; i++)
     {
-       bestscale = MAXINT;
+       bestscale = INT_MAX;
+        best = unsorted.next;
        for (ds=unsorted.next ; ds!= &unsorted ; ds=ds->next)
        {
            if (ds->scale < bestscale)
@@ -839,9 +832,8 @@ void R_SortVisSprites (void)
 //
 // R_DrawSprite
 //
-//
-short          clipbot[SCREENWIDTH];
-short          cliptop[SCREENWIDTH];
+static short           clipbot[SCREENWIDTH];
+static short           cliptop[SCREENWIDTH];
 void R_DrawSprite (vissprite_t* spr)
 {
     drawseg_t*         ds;
index 299361d61a6cf0ff3a86a23ac762975a7861724d..256a5ebbeeb8f31f21771171ed38f8138d5a7760 100644 (file)
@@ -1,32 +1,26 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Rendering of moving objects, sprites.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __R_THINGS__
 #define __R_THINGS__
 
 
-#ifdef __GNUG__
-#pragma interface
-#endif
 
 #define MAXVISSPRITES          128
 
@@ -69,8 +63,3 @@ R_ClipVisSprite
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index b0cdd686f7bc6f1a1e9d91aa6a1a34eb073c4cae..f6d8be1388944e172291a48b7ed12748c5e528bb 100644 (file)
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:  none
 //
-//-----------------------------------------------------------------------------
-
-
-static const char
-rcsid[] = "$Id: s_sound.c,v 1.6 1997/02/03 22:45:12 b1 Exp $";
-
-
 
 #include <stdio.h>
 #include <stdlib.h>
 
-#include "i_system.h"
 #include "i_sound.h"
-#include "sounds.h"
-#include "s_sound.h"
-
-#include "z_zone.h"
-#include "m_random.h"
-#include "w_wad.h"
+#include "i_system.h"
 
-#include "doomdef.h"
-#include "p_local.h"
+#include "doomfeatures.h"
+#include "deh_str.h"
 
 #include "doomstat.h"
+#include "doomtype.h"
 
+#include "sounds.h"
+#include "s_sound.h"
 
-// Purpose?
-const char snd_prefixen[]
-= { 'P', 'P', 'A', 'S', 'S', 'S', 'M', 'M', 'M', 'S', 'S', 'S' };
+#include "m_misc.h"
+#include "m_random.h"
+#include "m_argv.h"
 
-#define S_MAX_VOLUME           127
+#include "p_local.h"
+#include "w_wad.h"
+#include "z_zone.h"
 
 // when to clip out sounds
 // Does not fit the large outdoor areas.
-#define S_CLIPPING_DIST                (1200*0x10000)
+
+#define S_CLIPPING_DIST (1200 * FRACUNIT)
 
 // Distance tp origin when sounds should be maxed out.
 // This should relate to movement clipping resolution
 // (see BLOCKMAP handling).
-// Originally: (200*0x10000).
-#define S_CLOSE_DIST           (160*0x10000)
-
-
-#define S_ATTENUATOR           ((S_CLIPPING_DIST-S_CLOSE_DIST)>>FRACBITS)
-
-// Adjustable by menu.
-#define NORM_VOLUME                    snd_MaxVolume
-
-#define NORM_PITCH                     128
-#define NORM_PRIORITY          64
-#define NORM_SEP               128
+// In the source code release: (160*FRACUNIT).  Changed back to the 
+// Vanilla value of 200 (why was this changed?)
 
-#define S_PITCH_PERTURB                1
-#define S_STEREO_SWING         (96*0x10000)
+#define S_CLOSE_DIST (200 * FRACUNIT)
 
-// percent attenuation from front to back
-#define S_IFRACVOL             30
+// The range over which sound attenuates
 
-#define NA                     0
-#define S_NUMCHANNELS          2
+#define S_ATTENUATOR ((S_CLIPPING_DIST - S_CLOSE_DIST) >> FRACBITS)
 
+// Stereo separation
 
-// Current music/sfx card - index useless
-//  w/o a reference LUT in a sound module.
-extern int snd_MusicDevice;
-extern int snd_SfxDevice;
-// Config file? Same disclaimer as above.
-extern int snd_DesiredMusicDevice;
-extern int snd_DesiredSfxDevice;
-
+#define S_STEREO_SWING (96 * FRACUNIT)
 
+#define NORM_PITCH 128
+#define NORM_PRIORITY 64
+#define NORM_SEP 128
 
 typedef struct
 {
     // sound information (if null, channel avail.)
-    sfxinfo_tsfxinfo;
+    sfxinfo_t *sfxinfo;
 
     // origin of sound
-    void*      origin;
+    mobj_t *origin;
 
     // handle of the sound being played
-    int                handle;
+    int handle;
     
 } channel_t;
 
+// The set of channels available
 
-// the set of channels available
-static channel_t*      channels;
+static channel_t *channels;
 
-// These are not used, but should be (menu).
 // Maximum volume of a sound effect.
 // Internal default is max out of 0-15.
-int            snd_SfxVolume = 15;
-
-// Maximum volume of music. Useless so far.
-int            snd_MusicVolume = 15; 
-
-
 
-// whether songs are mus_paused
-static boolean         mus_paused;     
+int sfxVolume = 8;
 
-// music currently being played
-static musicinfo_t*    mus_playing=0;
+// Maximum volume of music. 
 
-// following is set
-//  by the defaults code in M_misc:
-// number of channels available
-int                    numChannels;    
+int musicVolume = 8;
 
-static int             nextcleanup;
+// Internal volume level, ranging from 0-127
 
+static int snd_SfxVolume;
 
+// Whether songs are mus_paused
 
-//
-// Internals.
-//
-int
-S_getChannel
-( void*                origin,
-  sfxinfo_t*   sfxinfo );
+static boolean mus_paused;        
 
+// Music currently being played
 
-int
-S_AdjustSoundParams
-( mobj_t*      listener,
-  mobj_t*      source,
-  int*         vol,
-  int*         sep,
-  int*         pitch );
-
-void S_StopChannel(int cnum);
+static musicinfo_t *mus_playing = NULL;
 
+// Number of channels to use
 
+int snd_channels = 8;
 
 //
 // Initializes sound stuff, including volume
 // Sets channels, SFX and music volume,
 //  allocates channel buffer, sets S_sfx lookup.
 //
-void S_Init
-( int          sfxVolume,
-  int          musicVolume )
+
+void S_Init(int sfxVolume, int musicVolume)
 {  
-  int          i;
-
-  fprintf( stderr, "S_Init: default sfx volume %d\n", sfxVolume);
-
-  // Whatever these did with DMX, these are rather dummies now.
-  I_SetChannels();
-  
-  S_SetSfxVolume(sfxVolume);
-  // No music with Linux - another dummy.
-  S_SetMusicVolume(musicVolume);
-
-  // Allocating the internal channels for mixing
-  // (the maximum numer of sounds rendered
-  // simultaneously) within zone memory.
-  channels =
-    (channel_t *) Z_Malloc(numChannels*sizeof(channel_t), PU_STATIC, 0);
-  
-  // Free all channels for use
-  for (i=0 ; i<numChannels ; i++)
-    channels[i].sfxinfo = 0;
-  
-  // no sounds are playing, and they are not mus_paused
-  mus_paused = 0;
-
-  // Note that sounds have not been cached (yet).
-  for (i=1 ; i<NUMSFX ; i++)
-    S_sfx[i].lumpnum = S_sfx[i].usefulness = -1;
+    int i;
+
+    I_PrecacheSounds(S_sfx, NUMSFX);
+
+    S_SetSfxVolume(sfxVolume);
+    S_SetMusicVolume(musicVolume);
+
+    // Allocating the internal channels for mixing
+    // (the maximum numer of sounds rendered
+    // simultaneously) within zone memory.
+    channels = Z_Malloc(snd_channels*sizeof(channel_t), PU_STATIC, 0);
+
+    // Free all channels for use
+    for (i=0 ; i<snd_channels ; i++)
+    {
+        channels[i].sfxinfo = 0;
+    }
+
+    // no sounds are playing, and they are not mus_paused
+    mus_paused = 0;
+
+    // Note that sounds have not been cached (yet).
+    for (i=1 ; i<NUMSFX ; i++)
+    {
+        S_sfx[i].lumpnum = S_sfx[i].usefulness = -1;
+    }
+
+    I_AtExit(S_Shutdown, true);
+}
+
+void S_Shutdown(void)
+{
+    I_ShutdownSound();
+    I_ShutdownMusic();
 }
 
+static void S_StopChannel(int cnum)
+{
+    int i;
+    channel_t *c;
 
+    c = &channels[cnum];
 
+    if (c->sfxinfo)
+    {
+        // stop the sound playing
+
+        if (I_SoundIsPlaying(c->handle))
+        {
+            I_StopSound(c->handle);
+        }
+
+        // check to see if other channels are playing the sound
+
+        for (i=0; i<snd_channels; i++)
+        {
+            if (cnum != i && c->sfxinfo == channels[i].sfxinfo)
+            {
+                break;
+            }
+        }
+        
+        // degrade usefulness of sound data
+
+        c->sfxinfo->usefulness--;
+        c->sfxinfo = NULL;
+    }
+}
 
 //
 // Per level startup code.
 // Kills playing sounds at start of level,
 //  determines music if any, changes music.
 //
+
 void S_Start(void)
 {
-  int cnum;
-  int mnum;
-
-  // kill all playing sounds at start of level
-  //  (trust me - a good idea)
-  for (cnum=0 ; cnum<numChannels ; cnum++)
-    if (channels[cnum].sfxinfo)
-      S_StopChannel(cnum);
-  
-  // start new music for the level
-  mus_paused = 0;
-  
-  if (gamemode == commercial)
-    mnum = mus_runnin + gamemap - 1;
-  else
-  {
-    int spmus[]=
-    {
-      // Song - Who? - Where?
-      
-      mus_e3m4,        // American     e4m1
-      mus_e3m2,        // Romero       e4m2
-      mus_e3m3,        // Shawn        e4m3
-      mus_e1m5,        // American     e4m4
-      mus_e2m7,        // Tim  e4m5
-      mus_e2m4,        // Romero       e4m6
-      mus_e2m6,        // J.Anderson   e4m7 CHIRON.WAD
-      mus_e2m5,        // Shawn        e4m8
-      mus_e1m9 // Tim          e4m9
-    };
-    
-    if (gameepisode < 4)
-      mnum = mus_e1m1 + (gameepisode-1)*9 + gamemap-1;
+    int cnum;
+    int mnum;
+
+    // kill all playing sounds at start of level
+    //  (trust me - a good idea)
+    for (cnum=0 ; cnum<snd_channels ; cnum++)
+    {
+        if (channels[cnum].sfxinfo)
+        {
+            S_StopChannel(cnum);
+        }
+    }
+
+    // start new music for the level
+    mus_paused = 0;
+
+    if (gamemode == commercial)
+    {
+        mnum = mus_runnin + gamemap - 1;
+    }
     else
-      mnum = spmus[gamemap-1];
-    }  
-  
-  // HACK FOR COMMERCIAL
-  //  if (commercial && mnum > mus_e3m9)       
-  //      mnum -= mus_e3m9;
-  
-  S_ChangeMusic(mnum, true);
-  
-  nextcleanup = 15;
-}      
+    {
+        int spmus[]=
+        {
+            // Song - Who? - Where?
+
+            mus_e3m4,        // American     e4m1
+            mus_e3m2,        // Romero       e4m2
+            mus_e3m3,        // Shawn        e4m3
+            mus_e1m5,        // American     e4m4
+            mus_e2m7,        // Tim          e4m5
+            mus_e2m4,        // Romero       e4m6
+            mus_e2m6,        // J.Anderson   e4m7 CHIRON.WAD
+            mus_e2m5,        // Shawn        e4m8
+            mus_e1m9,        // Tim          e4m9
+        };
+
+        if (gameepisode < 4)
+        {
+            mnum = mus_e1m1 + (gameepisode-1)*9 + gamemap-1;
+        }
+        else
+        {
+            mnum = spmus[gamemap-1];
+        }
+    }        
+
+    S_ChangeMusic(mnum, true);
+}        
+
+void S_StopSound(mobj_t *origin)
+{
+    int cnum;
+
+    for (cnum=0 ; cnum<snd_channels ; cnum++)
+    {
+        if (channels[cnum].sfxinfo && channels[cnum].origin == origin)
+        {
+            S_StopChannel(cnum);
+            break;
+        }
+    }
+}
+
+//
+// S_GetChannel :
+//   If none available, return -1.  Otherwise channel #.
+//
+
+static int S_GetChannel(mobj_t *origin, sfxinfo_t *sfxinfo)
+{
+    // channel number to use
+    int                cnum;
+    
+    channel_t*        c;
+
+    // Find an open channel
+    for (cnum=0 ; cnum<snd_channels ; cnum++)
+    {
+        if (!channels[cnum].sfxinfo)
+        {
+            break;
+        }
+        else if (origin && channels[cnum].origin == origin)
+        {
+            S_StopChannel(cnum);
+            break;
+        }
+    }
 
+    // None available
+    if (cnum == snd_channels)
+    {
+        // Look for lower priority
+        for (cnum=0 ; cnum<snd_channels ; cnum++)
+        {
+            if (channels[cnum].sfxinfo->priority >= sfxinfo->priority)
+            {
+                break;
+            }
+        }
+
+        if (cnum == snd_channels)
+        {
+            // FUCK!  No lower priority.  Sorry, Charlie.    
+            return -1;
+        }
+        else
+        {
+            // Otherwise, kick out lower priority.
+            S_StopChannel(cnum);
+        }
+    }
 
+    c = &channels[cnum];
 
+    // channel is decided to be cnum.
+    c->sfxinfo = sfxinfo;
+    c->origin = origin;
 
+    return cnum;
+}
 
-void
-S_StartSoundAtVolume
-( void*                origin_p,
-  int          sfx_id,
-  int          volume )
+//
+// Changes volume and stereo-separation variables
+//  from the norm of a sound effect to be played.
+// If the sound is not audible, returns a 0.
+// Otherwise, modifies parameters and returns 1.
+//
+
+static int S_AdjustSoundParams(mobj_t *listener, mobj_t *source,
+                               int *vol, int *sep)
 {
+    fixed_t        approx_dist;
+    fixed_t        adx;
+    fixed_t        ady;
+    angle_t        angle;
 
-  int          rc;
-  int          sep;
-  int          pitch;
-  int          priority;
-  sfxinfo_t*   sfx;
-  int          cnum;
-  
-  mobj_t*      origin = (mobj_t *) origin_p;
-  
-  
-  // Debug.
-  /*fprintf( stderr,
-          "S_StartSoundAtVolume: playing sound %d (%s)\n",
-          sfx_id, S_sfx[sfx_id].name );*/
-  
-  // check for bogus sound #
-  if (sfx_id < 1 || sfx_id > NUMSFX)
-    I_Error("Bad sfx #: %d", sfx_id);
-  
-  sfx = &S_sfx[sfx_id];
-  
-  // Initialize sound parameters
-  if (sfx->link)
-  {
-    pitch = sfx->pitch;
-    priority = sfx->priority;
-    volume += sfx->volume;
-    
-    if (volume < 1)
-      return;
+    // calculate the distance to sound origin
+    //  and clip it if necessary
+    adx = abs(listener->x - source->x);
+    ady = abs(listener->y - source->y);
+
+    // From _GG1_ p.428. Appox. eucledian distance fast.
+    approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1);
     
-    if (volume > snd_SfxVolume)
-      volume = snd_SfxVolume;
-  }    
-  else
-  {
-    pitch = NORM_PITCH;
-    priority = NORM_PRIORITY;
-  }
-
-
-  // Check to see if it is audible,
-  //  and if not, modify the params
-  if (origin && origin != players[consoleplayer].mo)
-  {
-    rc = S_AdjustSoundParams(players[consoleplayer].mo,
-                            origin,
-                            &volume,
-                            &sep,
-                            &pitch);
-       
-    if ( origin->x == players[consoleplayer].mo->x
-        && origin->y == players[consoleplayer].mo->y)
-    {  
-      sep      = NORM_SEP;
+    if (gamemap != 8 && approx_dist > S_CLIPPING_DIST)
+    {
+        return 0;
     }
     
-    if (!rc)
-      return;
-  }    
-  else
-  {
-    sep = NORM_SEP;
-  }
-  
-  // hacks to vary the sfx pitches
-  if (sfx_id >= sfx_sawup
-      && sfx_id <= sfx_sawhit)
-  {    
-    pitch += 8 - (M_Random()&15);
-    
-    if (pitch<0)
-      pitch = 0;
-    else if (pitch>255)
-      pitch = 255;
-  }
-  else if (sfx_id != sfx_itemup
-          && sfx_id != sfx_tink)
-  {
-    pitch += 16 - (M_Random()&31);
-    
-    if (pitch<0)
-      pitch = 0;
-    else if (pitch>255)
-      pitch = 255;
-  }
-
-  // kill old sound
-  S_StopSound(origin);
-
-  // try to find a channel
-  cnum = S_getChannel(origin, sfx);
-  
-  if (cnum<0)
-    return;
-
-  //
-  // This is supposed to handle the loading/caching.
-  // For some odd reason, the caching is done nearly
-  //  each time the sound is needed?
-  //
-  
-  // get lumpnum if necessary
-  if (sfx->lumpnum < 0)
-    sfx->lumpnum = I_GetSfxLumpNum(sfx);
-
-#ifndef SNDSERV
-  // cache data if necessary
-  if (!sfx->data)
-  {
-    fprintf( stderr,
-            "S_StartSoundAtVolume: 16bit and not pre-cached - wtf?\n");
-
-    // DOS remains, 8bit handling
-    //sfx->data = (void *) W_CacheLumpNum(sfx->lumpnum, PU_MUSIC);
-    // fprintf( stderr,
-    //      "S_StartSoundAtVolume: loading %d (lump %d) : 0x%x\n",
-    //       sfx_id, sfx->lumpnum, (int)sfx->data );
-    
-  }
-#endif
-  
-  // increase the usefulness
-  if (sfx->usefulness++ < 0)
-    sfx->usefulness = 1;
-  
-  // Assigns the handle to one of the channels in the
-  //  mix/output buffer.
-  channels[cnum].handle = I_StartSound(sfx_id,
-                                      /*sfx->data,*/
-                                      volume,
-                                      sep,
-                                      pitch,
-                                      priority);
-}      
-
-void
-S_StartSound
-( void*                origin,
-  int          sfx_id )
-{
-#ifdef SAWDEBUG
-    // if (sfx_id == sfx_sawful)
-    // sfx_id = sfx_itemup;
-#endif
-  
-    S_StartSoundAtVolume(origin, sfx_id, snd_SfxVolume);
-
+    // angle of source to listener
+    angle = R_PointToAngle2(listener->x,
+                            listener->y,
+                            source->x,
+                            source->y);
 
-    // UNUSED. We had problems, had we not?
-#ifdef SAWDEBUG
-{
-    int i;
-    int n;
-       
-    static mobj_t*      last_saw_origins[10] = {1,1,1,1,1,1,1,1,1,1};
-    static int         first_saw=0;
-    static int         next_saw=0;
-       
-    if (sfx_id == sfx_sawidl
-       || sfx_id == sfx_sawful
-       || sfx_id == sfx_sawhit)
-    {
-       for (i=first_saw;i!=next_saw;i=(i+1)%10)
-           if (last_saw_origins[i] != origin)
-               fprintf(stderr, "old origin 0x%lx != "
-                       "origin 0x%lx for sfx %d\n",
-                       last_saw_origins[i],
-                       origin,
-                       sfx_id);
-           
-       last_saw_origins[next_saw] = origin;
-       next_saw = (next_saw + 1) % 10;
-       if (next_saw == first_saw)
-           first_saw = (first_saw + 1) % 10;
-           
-       for (n=i=0; i<numChannels ; i++)
-       {
-           if (channels[i].sfxinfo == &S_sfx[sfx_sawidl]
-               || channels[i].sfxinfo == &S_sfx[sfx_sawful]
-               || channels[i].sfxinfo == &S_sfx[sfx_sawhit]) n++;
-       }
-           
-       if (n>1)
-       {
-           for (i=0; i<numChannels ; i++)
-           {
-               if (channels[i].sfxinfo == &S_sfx[sfx_sawidl]
-                   || channels[i].sfxinfo == &S_sfx[sfx_sawful]
-                   || channels[i].sfxinfo == &S_sfx[sfx_sawhit])
-               {
-                   fprintf(stderr,
-                           "chn: sfxinfo=0x%lx, origin=0x%lx, "
-                           "handle=%d\n",
-                           channels[i].sfxinfo,
-                           channels[i].origin,
-                           channels[i].handle);
-               }
-           }
-           fprintf(stderr, "\n");
-       }
+    if (angle > listener->angle)
+    {
+        angle = angle - listener->angle;
+    }
+    else
+    {
+        angle = angle + (0xffffffff - listener->angle);
     }
-}
-#endif
-}
 
+    angle >>= ANGLETOFINESHIFT;
 
+    // stereo separation
+    *sep = 128 - (FixedMul(S_STEREO_SWING, finesine[angle]) >> FRACBITS);
 
+    // volume calculation
+    if (approx_dist < S_CLOSE_DIST)
+    {
+        *vol = snd_SfxVolume;
+    }
+    else if (gamemap == 8)
+    {
+        if (approx_dist > S_CLIPPING_DIST)
+        {
+            approx_dist = S_CLIPPING_DIST;
+        }
+
+        *vol = 15+ ((snd_SfxVolume-15)
+                    *((S_CLIPPING_DIST - approx_dist)>>FRACBITS))
+            / S_ATTENUATOR;
+    }
+    else
+    {
+        // distance effect
+        *vol = (snd_SfxVolume
+                * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS))
+            / S_ATTENUATOR; 
+    }
+    
+    return (*vol > 0);
+}
 
-void S_StopSound(void *origin)
+void S_StartSound(void *origin_p, int sfx_id)
 {
-
+    sfxinfo_t *sfx;
+    mobj_t *origin;
+    int rc;
+    int sep;
     int cnum;
+    int volume;
+
+    origin = (mobj_t *) origin_p;
+    volume = snd_SfxVolume;
 
-    for (cnum=0 ; cnum<numChannels ; cnum++)
+    // check for bogus sound #
+    if (sfx_id < 1 || sfx_id > NUMSFX)
     {
-       if (channels[cnum].sfxinfo && channels[cnum].origin == origin)
-       {
-           S_StopChannel(cnum);
-           break;
-       }
+        I_Error("Bad sfx #: %d", sfx_id);
     }
-}
 
+    sfx = &S_sfx[sfx_id];
 
+    // Initialize sound parameters
+    if (sfx->link)
+    {
+        volume += sfx->volume;
+
+        if (volume < 1)
+        {
+            return;
+        }
+
+        if (volume > snd_SfxVolume)
+        {
+            volume = snd_SfxVolume;
+        }
+    }
+
+
+    // Check to see if it is audible,
+    //  and if not, modify the params
+    if (origin && origin != players[consoleplayer].mo)
+    {
+        rc = S_AdjustSoundParams(players[consoleplayer].mo,
+                                 origin,
+                                 &volume,
+                                 &sep);
+
+        if (origin->x == players[consoleplayer].mo->x
+         && origin->y == players[consoleplayer].mo->y)
+        {        
+            sep = NORM_SEP;
+        }
+
+        if (!rc)
+        {
+            return;
+        }
+    }        
+    else
+    {
+        sep = NORM_SEP;
+    }
 
+    // kill old sound
+    S_StopSound(origin);
 
+    // try to find a channel
+    cnum = S_GetChannel(origin, sfx);
 
+    if (cnum < 0)
+    {
+        return;
+    }
 
+    // increase the usefulness
+    if (sfx->usefulness++ < 0)
+    {
+        sfx->usefulness = 1;
+    }
 
+    if (sfx->lumpnum < 0)
+    {
+        sfx->lumpnum = I_GetSfxLumpNum(sfx);
+    }
 
+    channels[cnum].handle = I_StartSound(sfx, cnum, volume, sep);
+}        
 
 //
 // Stop and resume music, during game PAUSE.
 //
+
 void S_PauseSound(void)
 {
     if (mus_playing && !mus_paused)
     {
-       I_PauseSong(mus_playing->handle);
-       mus_paused = true;
+        I_PauseSong();
+        mus_paused = true;
     }
 }
 
@@ -507,163 +492,140 @@ void S_ResumeSound(void)
 {
     if (mus_playing && mus_paused)
     {
-       I_ResumeSong(mus_playing->handle);
-       mus_paused = false;
+        I_ResumeSong();
+        mus_paused = false;
     }
 }
 
-
 //
 // Updates music & sounds
 //
-void S_UpdateSounds(void* listener_p)
+
+void S_UpdateSounds(mobj_t *listener)
 {
-    int                audible;
-    int                cnum;
-    int                volume;
-    int                sep;
-    int                pitch;
-    sfxinfo_t* sfx;
-    channel_t* c;
-    
-    mobj_t*    listener = (mobj_t*)listener_p;
+    int                audible;
+    int                cnum;
+    int                volume;
+    int                sep;
+    sfxinfo_t*        sfx;
+    channel_t*        c;
 
+    I_UpdateSound();
 
-    
-    // Clean up unused data.
-    // This is currently not done for 16bit (sounds cached static).
-    // DOS 8bit remains. 
-    /*if (gametic > nextcleanup)
-    {
-       for (i=1 ; i<NUMSFX ; i++)
-       {
-           if (S_sfx[i].usefulness < 1
-               && S_sfx[i].usefulness > -1)
-           {
-               if (--S_sfx[i].usefulness == -1)
-               {
-                   Z_ChangeTag(S_sfx[i].data, PU_CACHE);
-                   S_sfx[i].data = 0;
-               }
-           }
-       }
-       nextcleanup = gametic + 15;
-    }*/
-    
-    for (cnum=0 ; cnum<numChannels ; cnum++)
-    {
-       c = &channels[cnum];
-       sfx = c->sfxinfo;
-
-       if (c->sfxinfo)
-       {
-           if (I_SoundIsPlaying(c->handle))
-           {
-               // initialize parameters
-               volume = snd_SfxVolume;
-               pitch = NORM_PITCH;
-               sep = NORM_SEP;
-
-               if (sfx->link)
-               {
-                   pitch = sfx->pitch;
-                   volume += sfx->volume;
-                   if (volume < 1)
-                   {
-                       S_StopChannel(cnum);
-                       continue;
-                   }
-                   else if (volume > snd_SfxVolume)
-                   {
-                       volume = snd_SfxVolume;
-                   }
-               }
-
-               // check non-local sounds for distance clipping
-               //  or modify their params
-               if (c->origin && listener_p != c->origin)
-               {
-                   audible = S_AdjustSoundParams(listener,
-                                                 c->origin,
-                                                 &volume,
-                                                 &sep,
-                                                 &pitch);
-                   
-                   if (!audible)
-                   {
-                       S_StopChannel(cnum);
-                   }
-                   else
-                       I_UpdateSoundParams(c->handle, volume, sep, pitch);
-               }
-           }
-           else
-           {
-               // if channel is allocated but sound has stopped,
-               //  free it
-               S_StopChannel(cnum);
-           }
-       }
+    for (cnum=0; cnum<snd_channels; cnum++)
+    {
+        c = &channels[cnum];
+        sfx = c->sfxinfo;
+
+        if (c->sfxinfo)
+        {
+            if (I_SoundIsPlaying(c->handle))
+            {
+                // initialize parameters
+                volume = snd_SfxVolume;
+                sep = NORM_SEP;
+
+                if (sfx->link)
+                {
+                    volume += sfx->volume;
+                    if (volume < 1)
+                    {
+                        S_StopChannel(cnum);
+                        continue;
+                    }
+                    else if (volume > snd_SfxVolume)
+                    {
+                        volume = snd_SfxVolume;
+                    }
+                }
+
+                // check non-local sounds for distance clipping
+                //  or modify their params
+                if (c->origin && listener != c->origin)
+                {
+                    audible = S_AdjustSoundParams(listener,
+                                                  c->origin,
+                                                  &volume,
+                                                  &sep);
+                    
+                    if (!audible)
+                    {
+                        S_StopChannel(cnum);
+                    }
+                    else
+                    {
+                        I_UpdateSoundParams(c->handle, volume, sep);
+                    }
+                }
+            }
+            else
+            {
+                // if channel is allocated but sound has stopped,
+                //  free it
+                S_StopChannel(cnum);
+            }
+        }
     }
-    // kill music if it is a single-play && finished
-    // if (    mus_playing
-    //      && !I_QrySongPlaying(mus_playing->handle)
-    //      && !mus_paused )
-    // S_StopMusic();
 }
 
-
 void S_SetMusicVolume(int volume)
 {
     if (volume < 0 || volume > 127)
     {
-       I_Error("Attempt to set music volume at %d",
-               volume);
+        I_Error("Attempt to set music volume at %d",
+                volume);
     }    
 
-    I_SetMusicVolume(127);
     I_SetMusicVolume(volume);
-    snd_MusicVolume = volume;
 }
 
-
-
 void S_SetSfxVolume(int volume)
 {
-
     if (volume < 0 || volume > 127)
-       I_Error("Attempt to set sfx volume at %d", volume);
+    {
+        I_Error("Attempt to set sfx volume at %d", volume);
+    }
 
     snd_SfxVolume = volume;
-
 }
 
 //
 // Starts some music with the music id found in sounds.h.
 //
+
 void S_StartMusic(int m_id)
 {
     S_ChangeMusic(m_id, false);
 }
 
-void
-S_ChangeMusic
-( int                  musicnum,
-  int                  looping )
+void S_ChangeMusic(int musicnum, int looping)
 {
-    musicinfo_t*       music;
-    char               namebuf[9];
+    musicinfo_t *music = NULL;
+    char namebuf[9];
+    void *handle;
+
+    // The Doom IWAD file has two versions of the intro music: d_intro
+    // and d_introa.  The latter is used for OPL playback.
+
+    if (musicnum == mus_intro && (snd_musicdevice == SNDDEVICE_ADLIB
+                               || snd_musicdevice == SNDDEVICE_SB))
+    {
+        musicnum = mus_introa;
+    }
 
-    if ( (musicnum <= mus_None)
-        || (musicnum >= NUMMUSIC) )
+    if (musicnum <= mus_None || musicnum >= NUMMUSIC)
     {
-       I_Error("Bad music number %d", musicnum);
+        I_Error("Bad music number %d", musicnum);
     }
     else
-       music = &S_music[musicnum];
+    {
+        music = &S_music[musicnum];
+    }
 
     if (mus_playing == music)
-       return;
+    {
+        return;
+    }
 
     // shutdown old music
     S_StopMusic();
@@ -671,209 +633,38 @@ S_ChangeMusic
     // get lumpnum if neccessary
     if (!music->lumpnum)
     {
-       sprintf(namebuf, "d_%s", music->name);
-       music->lumpnum = W_GetNumForName(namebuf);
+        M_snprintf(namebuf, sizeof(namebuf), "d_%s", DEH_String(music->name));
+        music->lumpnum = W_GetNumForName(namebuf);
     }
 
-    // load & register it
-    music->data = (void *) W_CacheLumpNum(music->lumpnum, PU_MUSIC);
-    music->handle = I_RegisterSong(music->data);
+    music->data = W_CacheLumpNum(music->lumpnum, PU_STATIC);
 
-    // play it
-    I_PlaySong(music->handle, looping);
+    handle = I_RegisterSong(music->data, W_LumpLength(music->lumpnum));
+    music->handle = handle;
+    I_PlaySong(handle, looping);
 
     mus_playing = music;
 }
 
-
-void S_StopMusic(void)
+boolean S_MusicPlaying(void)
 {
-    if (mus_playing)
-    {
-       if (mus_paused)
-           I_ResumeSong(mus_playing->handle);
-
-       I_StopSong(mus_playing->handle);
-       I_UnRegisterSong(mus_playing->handle);
-       Z_ChangeTag(mus_playing->data, PU_CACHE);
-       
-       mus_playing->data = 0;
-       mus_playing = 0;
-    }
-}
-
-
-
-
-void S_StopChannel(int cnum)
-{
-
-    int                i;
-    channel_t* c = &channels[cnum];
-
-    if (c->sfxinfo)
-    {
-       // stop the sound playing
-       if (I_SoundIsPlaying(c->handle))
-       {
-#ifdef SAWDEBUG
-           if (c->sfxinfo == &S_sfx[sfx_sawful])
-               fprintf(stderr, "stopped\n");
-#endif
-           I_StopSound(c->handle);
-       }
-
-       // check to see
-       //  if other channels are playing the sound
-       for (i=0 ; i<numChannels ; i++)
-       {
-           if (cnum != i
-               && c->sfxinfo == channels[i].sfxinfo)
-           {
-               break;
-           }
-       }
-       
-       // degrade usefulness of sound data
-       c->sfxinfo->usefulness--;
-
-       c->sfxinfo = 0;
-    }
+    return I_MusicIsPlaying();
 }
 
-
-
-//
-// Changes volume, stereo-separation, and pitch variables
-//  from the norm of a sound effect to be played.
-// If the sound is not audible, returns a 0.
-// Otherwise, modifies parameters and returns 1.
-//
-int
-S_AdjustSoundParams
-( mobj_t*      listener,
-  mobj_t*      source,
-  int*         vol,
-  int*         sep,
-  int*         pitch )
+void S_StopMusic(void)
 {
-    fixed_t    approx_dist;
-    fixed_t    adx;
-    fixed_t    ady;
-    angle_t    angle;
-
-    // calculate the distance to sound origin
-    //  and clip it if necessary
-    adx = abs(listener->x - source->x);
-    ady = abs(listener->y - source->y);
-
-    // From _GG1_ p.428. Appox. eucledian distance fast.
-    approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1);
-    
-    if (gamemap != 8
-       && approx_dist > S_CLIPPING_DIST)
-    {
-       return 0;
-    }
-    
-    // angle of source to listener
-    angle = R_PointToAngle2(listener->x,
-                           listener->y,
-                           source->x,
-                           source->y);
-
-    if (angle > listener->angle)
-       angle = angle - listener->angle;
-    else
-       angle = angle + (0xffffffff - listener->angle);
-
-    angle >>= ANGLETOFINESHIFT;
-
-    // stereo separation
-    *sep = 128 - (FixedMul(S_STEREO_SWING,finesine[angle])>>FRACBITS);
-
-    // volume calculation
-    if (approx_dist < S_CLOSE_DIST)
-    {
-       *vol = snd_SfxVolume;
-    }
-    else if (gamemap == 8)
-    {
-       if (approx_dist > S_CLIPPING_DIST)
-           approx_dist = S_CLIPPING_DIST;
-
-       *vol = 15+ ((snd_SfxVolume-15)
-                   *((S_CLIPPING_DIST - approx_dist)>>FRACBITS))
-           / S_ATTENUATOR;
-    }
-    else
+    if (mus_playing)
     {
-       // distance effect
-       *vol = (snd_SfxVolume
-               * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS))
-           / S_ATTENUATOR; 
+        if (mus_paused)
+        {
+            I_ResumeSong();
+        }
+
+        I_StopSong();
+        I_UnRegisterSong(mus_playing->handle);
+        W_ReleaseLumpNum(mus_playing->lumpnum);
+        mus_playing->data = NULL;
+        mus_playing = NULL;
     }
-    
-    return (*vol > 0);
 }
 
-
-
-
-//
-// S_getChannel :
-//   If none available, return -1.  Otherwise channel #.
-//
-int
-S_getChannel
-( void*                origin,
-  sfxinfo_t*   sfxinfo )
-{
-    // channel number to use
-    int                cnum;
-    
-    channel_t* c;
-
-    // Find an open channel
-    for (cnum=0 ; cnum<numChannels ; cnum++)
-    {
-       if (!channels[cnum].sfxinfo)
-           break;
-       else if (origin &&  channels[cnum].origin ==  origin)
-       {
-           S_StopChannel(cnum);
-           break;
-       }
-    }
-
-    // None available
-    if (cnum == numChannels)
-    {
-       // Look for lower priority
-       for (cnum=0 ; cnum<numChannels ; cnum++)
-           if (channels[cnum].sfxinfo->priority >= sfxinfo->priority) break;
-
-       if (cnum == numChannels)
-       {
-           // FUCK!  No lower priority.  Sorry, Charlie.    
-           return -1;
-       }
-       else
-       {
-           // Otherwise, kick out lower priority.
-           S_StopChannel(cnum);
-       }
-    }
-
-    c = &channels[cnum];
-
-    // channel is decided to be cnum.
-    c->sfxinfo = sfxinfo;
-    c->origin = origin;
-
-    return cnum;
-}
-
-
-
-
index ff95bccb6c9650a0ad3950a759e71f1d3e8c215d..bbd100a0c353451d52f292fb75b6060ff10f1dbf 100644 (file)
@@ -1,45 +1,40 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     The not so system specific sound interface.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __S_SOUND__
 #define __S_SOUND__
 
-
-#ifdef __GNUG__
-#pragma interface
-#endif
-
-
+#include "p_mobj.h"
+#include "sounds.h"
 
 //
 // Initializes sound stuff, including volume
 // Sets channels, SFX and music volume,
 //  allocates channel buffer, sets S_sfx lookup.
 //
-void
-S_Init
-( int          sfxVolume,
-  int          musicVolume );
 
+void S_Init(int sfxVolume, int musicVolume);
+
+
+// Shut down sound 
+
+void S_Shutdown(void);
 
 
 
@@ -48,30 +43,18 @@ S_Init
 // Kills playing sounds at start of level,
 //  determines music if any, changes music.
 //
-void S_Start(void);
 
+void S_Start(void);
 
 //
 // Start sound for thing at <origin>
 //  using <sound_id> from sounds.h
 //
-void
-S_StartSound
-( void*                origin,
-  int          sound_id );
-
-
-
-// Will start a sound at a given volume.
-void
-S_StartSoundAtVolume
-( void*                origin,
-  int          sound_id,
-  int          volume );
 
+void S_StartSound(void *origin, int sound_id);
 
 // Stop sound for thing at <origin>
-void S_StopSound(void* origin);
+void S_StopSound(mobj_t *origin);
 
 
 // Start music using <music_id> from sounds.h
@@ -79,10 +62,10 @@ void S_StartMusic(int music_id);
 
 // Start music using <music_id> from sounds.h,
 //  and set whether looping
-void
-S_ChangeMusic
-( int          music_id,
-  int          looping );
+void S_ChangeMusic(int music_id, int looping);
+
+// query if music is playing
+boolean S_MusicPlaying(void);
 
 // Stops the music fer sure.
 void S_StopMusic(void);
@@ -95,15 +78,12 @@ void S_ResumeSound(void);
 //
 // Updates music & sounds
 //
-void S_UpdateSounds(void* listener);
+void S_UpdateSounds(mobj_t *listener);
 
 void S_SetMusicVolume(int volume);
 void S_SetSfxVolume(int volume);
 
+extern int snd_channels;
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
+
diff --git a/frosted-doom/sha1.c b/frosted-doom/sha1.c
new file mode 100644 (file)
index 0000000..06ab40a
--- /dev/null
@@ -0,0 +1,319 @@
+/* sha1.c - SHA1 hash function
+ *     Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * Please see below for more legal information!
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/*  Test vectors:
+ *
+ *  "abc"
+ *  A999 3E36 4706 816A BA3E  2571 7850 C26C 9CD0 D89D
+ *
+ *  "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ *  8498 3E44 1C3B D26E BAAE  4AA1 F951 29E5 E546 70F1
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "i_swap.h"
+#include "sha1.h"
+
+void SHA1_Init(sha1_context_t *hd)
+{
+    hd->h0 = 0x67452301;
+    hd->h1 = 0xefcdab89;
+    hd->h2 = 0x98badcfe;
+    hd->h3 = 0x10325476;
+    hd->h4 = 0xc3d2e1f0;
+    hd->nblocks = 0;
+    hd->count = 0;
+}
+
+
+/****************
+ * Transform the message X which consists of 16 32-bit-words
+ */
+static void Transform(sha1_context_t *hd, byte *data)
+{
+    uint32_t a,b,c,d,e,tm;
+    uint32_t x[16];
+
+    /* get values from the chaining vars */
+    a = hd->h0;
+    b = hd->h1;
+    c = hd->h2;
+    d = hd->h3;
+    e = hd->h4;
+
+#ifdef SYS_BIG_ENDIAN
+    memcpy(x, data, 64);
+#else
+    {
+        int i;
+        byte *p2;
+        for(i=0, p2=(byte*)x; i < 16; i++, p2 += 4 )
+        {
+            p2[3] = *data++;
+            p2[2] = *data++;
+            p2[1] = *data++;
+            p2[0] = *data++;
+        }
+    }
+#endif
+
+
+#define K1  0x5A827999L
+#define K2  0x6ED9EBA1L
+#define K3  0x8F1BBCDCL
+#define K4  0xCA62C1D6L
+#define F1(x,y,z)   ( z ^ ( x & ( y ^ z ) ) )
+#define F2(x,y,z)   ( x ^ y ^ z )
+#define F3(x,y,z)   ( ( x & y ) | ( z & ( x | y ) ) )
+#define F4(x,y,z)   ( x ^ y ^ z )
+
+#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
+
+#define M(i) ( tm =   x[i&0x0f] ^ x[(i-14)&0x0f] \
+                   ^ x[(i-8)&0x0f] ^ x[(i-3)&0x0f] \
+              , (x[i&0x0f] = rol(tm,1)) )
+
+#define R(a,b,c,d,e,f,k,m)  do { e += rol( a, 5 )     \
+                                     + f( b, c, d )  \
+                                     + k             \
+                                     + m;            \
+                                b = rol( b, 30 );    \
+                              } while(0)
+    R( a, b, c, d, e, F1, K1, x[ 0] );
+    R( e, a, b, c, d, F1, K1, x[ 1] );
+    R( d, e, a, b, c, F1, K1, x[ 2] );
+    R( c, d, e, a, b, F1, K1, x[ 3] );
+    R( b, c, d, e, a, F1, K1, x[ 4] );
+    R( a, b, c, d, e, F1, K1, x[ 5] );
+    R( e, a, b, c, d, F1, K1, x[ 6] );
+    R( d, e, a, b, c, F1, K1, x[ 7] );
+    R( c, d, e, a, b, F1, K1, x[ 8] );
+    R( b, c, d, e, a, F1, K1, x[ 9] );
+    R( a, b, c, d, e, F1, K1, x[10] );
+    R( e, a, b, c, d, F1, K1, x[11] );
+    R( d, e, a, b, c, F1, K1, x[12] );
+    R( c, d, e, a, b, F1, K1, x[13] );
+    R( b, c, d, e, a, F1, K1, x[14] );
+    R( a, b, c, d, e, F1, K1, x[15] );
+    R( e, a, b, c, d, F1, K1, M(16) );
+    R( d, e, a, b, c, F1, K1, M(17) );
+    R( c, d, e, a, b, F1, K1, M(18) );
+    R( b, c, d, e, a, F1, K1, M(19) );
+    R( a, b, c, d, e, F2, K2, M(20) );
+    R( e, a, b, c, d, F2, K2, M(21) );
+    R( d, e, a, b, c, F2, K2, M(22) );
+    R( c, d, e, a, b, F2, K2, M(23) );
+    R( b, c, d, e, a, F2, K2, M(24) );
+    R( a, b, c, d, e, F2, K2, M(25) );
+    R( e, a, b, c, d, F2, K2, M(26) );
+    R( d, e, a, b, c, F2, K2, M(27) );
+    R( c, d, e, a, b, F2, K2, M(28) );
+    R( b, c, d, e, a, F2, K2, M(29) );
+    R( a, b, c, d, e, F2, K2, M(30) );
+    R( e, a, b, c, d, F2, K2, M(31) );
+    R( d, e, a, b, c, F2, K2, M(32) );
+    R( c, d, e, a, b, F2, K2, M(33) );
+    R( b, c, d, e, a, F2, K2, M(34) );
+    R( a, b, c, d, e, F2, K2, M(35) );
+    R( e, a, b, c, d, F2, K2, M(36) );
+    R( d, e, a, b, c, F2, K2, M(37) );
+    R( c, d, e, a, b, F2, K2, M(38) );
+    R( b, c, d, e, a, F2, K2, M(39) );
+    R( a, b, c, d, e, F3, K3, M(40) );
+    R( e, a, b, c, d, F3, K3, M(41) );
+    R( d, e, a, b, c, F3, K3, M(42) );
+    R( c, d, e, a, b, F3, K3, M(43) );
+    R( b, c, d, e, a, F3, K3, M(44) );
+    R( a, b, c, d, e, F3, K3, M(45) );
+    R( e, a, b, c, d, F3, K3, M(46) );
+    R( d, e, a, b, c, F3, K3, M(47) );
+    R( c, d, e, a, b, F3, K3, M(48) );
+    R( b, c, d, e, a, F3, K3, M(49) );
+    R( a, b, c, d, e, F3, K3, M(50) );
+    R( e, a, b, c, d, F3, K3, M(51) );
+    R( d, e, a, b, c, F3, K3, M(52) );
+    R( c, d, e, a, b, F3, K3, M(53) );
+    R( b, c, d, e, a, F3, K3, M(54) );
+    R( a, b, c, d, e, F3, K3, M(55) );
+    R( e, a, b, c, d, F3, K3, M(56) );
+    R( d, e, a, b, c, F3, K3, M(57) );
+    R( c, d, e, a, b, F3, K3, M(58) );
+    R( b, c, d, e, a, F3, K3, M(59) );
+    R( a, b, c, d, e, F4, K4, M(60) );
+    R( e, a, b, c, d, F4, K4, M(61) );
+    R( d, e, a, b, c, F4, K4, M(62) );
+    R( c, d, e, a, b, F4, K4, M(63) );
+    R( b, c, d, e, a, F4, K4, M(64) );
+    R( a, b, c, d, e, F4, K4, M(65) );
+    R( e, a, b, c, d, F4, K4, M(66) );
+    R( d, e, a, b, c, F4, K4, M(67) );
+    R( c, d, e, a, b, F4, K4, M(68) );
+    R( b, c, d, e, a, F4, K4, M(69) );
+    R( a, b, c, d, e, F4, K4, M(70) );
+    R( e, a, b, c, d, F4, K4, M(71) );
+    R( d, e, a, b, c, F4, K4, M(72) );
+    R( c, d, e, a, b, F4, K4, M(73) );
+    R( b, c, d, e, a, F4, K4, M(74) );
+    R( a, b, c, d, e, F4, K4, M(75) );
+    R( e, a, b, c, d, F4, K4, M(76) );
+    R( d, e, a, b, c, F4, K4, M(77) );
+    R( c, d, e, a, b, F4, K4, M(78) );
+    R( b, c, d, e, a, F4, K4, M(79) );
+
+    /* update chainig vars */
+    hd->h0 += a;
+    hd->h1 += b;
+    hd->h2 += c;
+    hd->h3 += d;
+    hd->h4 += e;
+}
+
+
+/* Update the message digest with the contents
+ * of INBUF with length INLEN.
+ */
+void SHA1_Update(sha1_context_t *hd, byte *inbuf, size_t inlen)
+{
+    if (hd->count == 64)
+    {
+        /* flush the buffer */
+       Transform(hd, hd->buf);
+       hd->count = 0;
+       hd->nblocks++;
+    }
+    if (!inbuf)
+       return;
+    if (hd->count)
+    {
+       for (; inlen && hd->count < 64; inlen--)
+           hd->buf[hd->count++] = *inbuf++;
+       SHA1_Update(hd, NULL, 0);
+       if (!inlen)
+           return;
+    }
+
+    while (inlen >= 64)
+    {
+       Transform(hd, inbuf);
+       hd->count = 0;
+       hd->nblocks++;
+       inlen -= 64;
+       inbuf += 64;
+    }
+    for (; inlen && hd->count < 64; inlen--)
+       hd->buf[hd->count++] = *inbuf++;
+}
+
+
+/* The routine final terminates the computation and
+ * returns the digest.
+ * The handle is prepared for a new cycle, but adding bytes to the
+ * handle will the destroy the returned buffer.
+ * Returns: 20 bytes representing the digest.
+ */
+
+void SHA1_Final(sha1_digest_t digest, sha1_context_t *hd)
+{
+    uint32_t t, msb, lsb;
+    byte *p;
+
+    SHA1_Update(hd, NULL, 0); /* flush */;
+
+    t = hd->nblocks;
+    /* multiply by 64 to make a byte count */
+    lsb = t << 6;
+    msb = t >> 26;
+    /* add the count */
+    t = lsb;
+    if ((lsb += hd->count) < t)
+       msb++;
+    /* multiply by 8 to make a bit count */
+    t = lsb;
+    lsb <<= 3;
+    msb <<= 3;
+    msb |= t >> 29;
+
+    if (hd->count < 56)
+    {
+        /* enough room */
+       hd->buf[hd->count++] = 0x80; /* pad */
+       while (hd->count < 56)
+           hd->buf[hd->count++] = 0;  /* pad */
+    }
+    else
+    {
+        /* need one extra block */
+       hd->buf[hd->count++] = 0x80; /* pad character */
+       while (hd->count < 64)
+           hd->buf[hd->count++] = 0;
+       SHA1_Update(hd, NULL, 0);  /* flush */;
+       memset(hd->buf, 0, 56 ); /* fill next block with zeroes */
+    }
+    /* append the 64 bit count */
+    hd->buf[56] = msb >> 24;
+    hd->buf[57] = msb >> 16;
+    hd->buf[58] = msb >>  8;
+    hd->buf[59] = msb     ;
+    hd->buf[60] = lsb >> 24;
+    hd->buf[61] = lsb >> 16;
+    hd->buf[62] = lsb >>  8;
+    hd->buf[63] = lsb     ;
+    Transform(hd, hd->buf);
+
+    p = hd->buf;
+#ifdef SYS_BIG_ENDIAN
+#define X(a) do { *(uint32_t*)p = hd->h##a ; p += 4; } while(0)
+#else /* little endian */
+#define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16;         \
+                     *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while(0)
+#endif
+    X(0);
+    X(1);
+    X(2);
+    X(3);
+    X(4);
+#undef X
+
+    memcpy(digest, hd->buf, sizeof(sha1_digest_t));
+}
+
+void SHA1_UpdateInt32(sha1_context_t *context, unsigned int val)
+{
+    byte buf[4];
+
+    buf[0] = (val >> 24) & 0xff;
+    buf[1] = (val >> 16) & 0xff;
+    buf[2] = (val >> 8) & 0xff;
+    buf[3] = val & 0xff;
+
+    SHA1_Update(context, buf, 4);
+}
+
+void SHA1_UpdateString(sha1_context_t *context, char *str)
+{
+    SHA1_Update(context, (byte *) str, strlen(str) + 1);
+}
+
diff --git a/frosted-doom/sha1.h b/frosted-doom/sha1.h
new file mode 100644 (file)
index 0000000..249571b
--- /dev/null
@@ -0,0 +1,40 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//     SHA-1 digest.
+//
+
+#ifndef __SHA1_H__
+#define __SHA1_H__
+
+#include "doomtype.h"
+
+typedef struct sha1_context_s sha1_context_t;
+typedef byte sha1_digest_t[20];
+
+struct sha1_context_s {
+    uint32_t h0,h1,h2,h3,h4;
+    uint32_t nblocks;
+    byte buf[64];
+    int count;
+};
+
+void SHA1_Init(sha1_context_t *context);
+void SHA1_Update(sha1_context_t *context, byte *buf, size_t len);
+void SHA1_Final(sha1_digest_t digest, sha1_context_t *context);
+void SHA1_UpdateInt32(sha1_context_t *context, unsigned int val);
+void SHA1_UpdateString(sha1_context_t *context, char *str);
+
+#endif /* #ifndef __SHA1_H__ */
+
index 0fea8a2ed2af04713330e1ab4dd41034b7954f48..e976bc84480e632b259cb63b52e64d89413547d2 100644 (file)
@@ -1,30 +1,24 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Created by a sound utility.
 //     Kept as a sample, DOOM2 sounds.
 //
-//-----------------------------------------------------------------------------
 
 
-static const char 
-rcsid[] = "$Id: sounds.c,v 1.3 1997/01/29 22:40:44 b1 Exp $";
+#include <stdlib.h>
 
 
 #include "doomtype.h"
@@ -34,76 +28,79 @@ rcsid[] = "$Id: sounds.c,v 1.3 1997/01/29 22:40:44 b1 Exp $";
 // Information about all the music
 //
 
+#define MUSIC(name) \
+    { name, 0, NULL, NULL }
+
 musicinfo_t S_music[] =
 {
-    { 0 },
-    { "e1m1", 0 },
-    { "e1m2", 0 },
-    { "e1m3", 0 },
-    { "e1m4", 0 },
-    { "e1m5", 0 },
-    { "e1m6", 0 },
-    { "e1m7", 0 },
-    { "e1m8", 0 },
-    { "e1m9", 0 },
-    { "e2m1", 0 },
-    { "e2m2", 0 },
-    { "e2m3", 0 },
-    { "e2m4", 0 },
-    { "e2m5", 0 },
-    { "e2m6", 0 },
-    { "e2m7", 0 },
-    { "e2m8", 0 },
-    { "e2m9", 0 },
-    { "e3m1", 0 },
-    { "e3m2", 0 },
-    { "e3m3", 0 },
-    { "e3m4", 0 },
-    { "e3m5", 0 },
-    { "e3m6", 0 },
-    { "e3m7", 0 },
-    { "e3m8", 0 },
-    { "e3m9", 0 },
-    { "inter", 0 },
-    { "intro", 0 },
-    { "bunny", 0 },
-    { "victor", 0 },
-    { "introa", 0 },
-    { "runnin", 0 },
-    { "stalks", 0 },
-    { "countd", 0 },
-    { "betwee", 0 },
-    { "doom", 0 },
-    { "the_da", 0 },
-    { "shawn", 0 },
-    { "ddtblu", 0 },
-    { "in_cit", 0 },
-    { "dead", 0 },
-    { "stlks2", 0 },
-    { "theda2", 0 },
-    { "doom2", 0 },
-    { "ddtbl2", 0 },
-    { "runni2", 0 },
-    { "dead2", 0 },
-    { "stlks3", 0 },
-    { "romero", 0 },
-    { "shawn2", 0 },
-    { "messag", 0 },
-    { "count2", 0 },
-    { "ddtbl3", 0 },
-    { "ampie", 0 },
-    { "theda3", 0 },
-    { "adrian", 0 },
-    { "messg2", 0 },
-    { "romer2", 0 },
-    { "tense", 0 },
-    { "shawn3", 0 },
-    { "openin", 0 },
-    { "evil", 0 },
-    { "ultima", 0 },
-    { "read_m", 0 },
-    { "dm2ttl", 0 },
-    { "dm2int", 0 } 
+    MUSIC(NULL),
+    MUSIC("e1m1"),
+    MUSIC("e1m2"),
+    MUSIC("e1m3"),
+    MUSIC("e1m4"),
+    MUSIC("e1m5"),
+    MUSIC("e1m6"),
+    MUSIC("e1m7"),
+    MUSIC("e1m8"),
+    MUSIC("e1m9"),
+    MUSIC("e2m1"),
+    MUSIC("e2m2"),
+    MUSIC("e2m3"),
+    MUSIC("e2m4"),
+    MUSIC("e2m5"),
+    MUSIC("e2m6"),
+    MUSIC("e2m7"),
+    MUSIC("e2m8"),
+    MUSIC("e2m9"),
+    MUSIC("e3m1"),
+    MUSIC("e3m2"),
+    MUSIC("e3m3"),
+    MUSIC("e3m4"),
+    MUSIC("e3m5"),
+    MUSIC("e3m6"),
+    MUSIC("e3m7"),
+    MUSIC("e3m8"),
+    MUSIC("e3m9"),
+    MUSIC("inter"),
+    MUSIC("intro"),
+    MUSIC("bunny"),
+    MUSIC("victor"),
+    MUSIC("introa"),
+    MUSIC("runnin"),
+    MUSIC("stalks"),
+    MUSIC("countd"),
+    MUSIC("betwee"),
+    MUSIC("doom"),
+    MUSIC("the_da"),
+    MUSIC("shawn"),
+    MUSIC("ddtblu"),
+    MUSIC("in_cit"),
+    MUSIC("dead"),
+    MUSIC("stlks2"),
+    MUSIC("theda2"),
+    MUSIC("doom2"),
+    MUSIC("ddtbl2"),
+    MUSIC("runni2"),
+    MUSIC("dead2"),
+    MUSIC("stlks3"),
+    MUSIC("romero"),
+    MUSIC("shawn2"),
+    MUSIC("messag"),
+    MUSIC("count2"),
+    MUSIC("ddtbl3"),
+    MUSIC("ampie"),
+    MUSIC("theda3"),
+    MUSIC("adrian"),
+    MUSIC("messg2"),
+    MUSIC("romer2"),
+    MUSIC("tense"),
+    MUSIC("shawn3"),
+    MUSIC("openin"),
+    MUSIC("evil"),
+    MUSIC("ultima"),
+    MUSIC("read_m"),
+    MUSIC("dm2ttl"),
+    MUSIC("dm2int") 
 };
 
 
@@ -111,118 +108,122 @@ musicinfo_t S_music[] =
 // Information about all the sfx
 //
 
+#define SOUND(name, priority) \
+  { NULL, name, priority, NULL, -1, -1, 0, 0, -1, NULL }
+#define SOUND_LINK(name, priority, link_id, pitch, volume) \
+  { NULL, name, priority, &S_sfx[link_id], pitch, volume, 0, 0, -1, NULL }
+
 sfxinfo_t S_sfx[] =
 {
   // S_sfx[0] needs to be a dummy for odd reasons.
-  { "none", false,  0, 0, -1, -1, 0 },
-
-  { "pistol", false, 64, 0, -1, -1, 0 },
-  { "shotgn", false, 64, 0, -1, -1, 0 },
-  { "sgcock", false, 64, 0, -1, -1, 0 },
-  { "dshtgn", false, 64, 0, -1, -1, 0 },
-  { "dbopn", false, 64, 0, -1, -1, 0 },
-  { "dbcls", false, 64, 0, -1, -1, 0 },
-  { "dbload", false, 64, 0, -1, -1, 0 },
-  { "plasma", false, 64, 0, -1, -1, 0 },
-  { "bfg", false, 64, 0, -1, -1, 0 },
-  { "sawup", false, 64, 0, -1, -1, 0 },
-  { "sawidl", false, 118, 0, -1, -1, 0 },
-  { "sawful", false, 64, 0, -1, -1, 0 },
-  { "sawhit", false, 64, 0, -1, -1, 0 },
-  { "rlaunc", false, 64, 0, -1, -1, 0 },
-  { "rxplod", false, 70, 0, -1, -1, 0 },
-  { "firsht", false, 70, 0, -1, -1, 0 },
-  { "firxpl", false, 70, 0, -1, -1, 0 },
-  { "pstart", false, 100, 0, -1, -1, 0 },
-  { "pstop", false, 100, 0, -1, -1, 0 },
-  { "doropn", false, 100, 0, -1, -1, 0 },
-  { "dorcls", false, 100, 0, -1, -1, 0 },
-  { "stnmov", false, 119, 0, -1, -1, 0 },
-  { "swtchn", false, 78, 0, -1, -1, 0 },
-  { "swtchx", false, 78, 0, -1, -1, 0 },
-  { "plpain", false, 96, 0, -1, -1, 0 },
-  { "dmpain", false, 96, 0, -1, -1, 0 },
-  { "popain", false, 96, 0, -1, -1, 0 },
-  { "vipain", false, 96, 0, -1, -1, 0 },
-  { "mnpain", false, 96, 0, -1, -1, 0 },
-  { "pepain", false, 96, 0, -1, -1, 0 },
-  { "slop", false, 78, 0, -1, -1, 0 },
-  { "itemup", true, 78, 0, -1, -1, 0 },
-  { "wpnup", true, 78, 0, -1, -1, 0 },
-  { "oof", false, 96, 0, -1, -1, 0 },
-  { "telept", false, 32, 0, -1, -1, 0 },
-  { "posit1", true, 98, 0, -1, -1, 0 },
-  { "posit2", true, 98, 0, -1, -1, 0 },
-  { "posit3", true, 98, 0, -1, -1, 0 },
-  { "bgsit1", true, 98, 0, -1, -1, 0 },
-  { "bgsit2", true, 98, 0, -1, -1, 0 },
-  { "sgtsit", true, 98, 0, -1, -1, 0 },
-  { "cacsit", true, 98, 0, -1, -1, 0 },
-  { "brssit", true, 94, 0, -1, -1, 0 },
-  { "cybsit", true, 92, 0, -1, -1, 0 },
-  { "spisit", true, 90, 0, -1, -1, 0 },
-  { "bspsit", true, 90, 0, -1, -1, 0 },
-  { "kntsit", true, 90, 0, -1, -1, 0 },
-  { "vilsit", true, 90, 0, -1, -1, 0 },
-  { "mansit", true, 90, 0, -1, -1, 0 },
-  { "pesit", true, 90, 0, -1, -1, 0 },
-  { "sklatk", false, 70, 0, -1, -1, 0 },
-  { "sgtatk", false, 70, 0, -1, -1, 0 },
-  { "skepch", false, 70, 0, -1, -1, 0 },
-  { "vilatk", false, 70, 0, -1, -1, 0 },
-  { "claw", false, 70, 0, -1, -1, 0 },
-  { "skeswg", false, 70, 0, -1, -1, 0 },
-  { "pldeth", false, 32, 0, -1, -1, 0 },
-  { "pdiehi", false, 32, 0, -1, -1, 0 },
-  { "podth1", false, 70, 0, -1, -1, 0 },
-  { "podth2", false, 70, 0, -1, -1, 0 },
-  { "podth3", false, 70, 0, -1, -1, 0 },
-  { "bgdth1", false, 70, 0, -1, -1, 0 },
-  { "bgdth2", false, 70, 0, -1, -1, 0 },
-  { "sgtdth", false, 70, 0, -1, -1, 0 },
-  { "cacdth", false, 70, 0, -1, -1, 0 },
-  { "skldth", false, 70, 0, -1, -1, 0 },
-  { "brsdth", false, 32, 0, -1, -1, 0 },
-  { "cybdth", false, 32, 0, -1, -1, 0 },
-  { "spidth", false, 32, 0, -1, -1, 0 },
-  { "bspdth", false, 32, 0, -1, -1, 0 },
-  { "vildth", false, 32, 0, -1, -1, 0 },
-  { "kntdth", false, 32, 0, -1, -1, 0 },
-  { "pedth", false, 32, 0, -1, -1, 0 },
-  { "skedth", false, 32, 0, -1, -1, 0 },
-  { "posact", true, 120, 0, -1, -1, 0 },
-  { "bgact", true, 120, 0, -1, -1, 0 },
-  { "dmact", true, 120, 0, -1, -1, 0 },
-  { "bspact", true, 100, 0, -1, -1, 0 },
-  { "bspwlk", true, 100, 0, -1, -1, 0 },
-  { "vilact", true, 100, 0, -1, -1, 0 },
-  { "noway", false, 78, 0, -1, -1, 0 },
-  { "barexp", false, 60, 0, -1, -1, 0 },
-  { "punch", false, 64, 0, -1, -1, 0 },
-  { "hoof", false, 70, 0, -1, -1, 0 },
-  { "metal", false, 70, 0, -1, -1, 0 },
-  { "chgun", false, 64, &S_sfx[sfx_pistol], 150, 0, 0 },
-  { "tink", false, 60, 0, -1, -1, 0 },
-  { "bdopn", false, 100, 0, -1, -1, 0 },
-  { "bdcls", false, 100, 0, -1, -1, 0 },
-  { "itmbk", false, 100, 0, -1, -1, 0 },
-  { "flame", false, 32, 0, -1, -1, 0 },
-  { "flamst", false, 32, 0, -1, -1, 0 },
-  { "getpow", false, 60, 0, -1, -1, 0 },
-  { "bospit", false, 70, 0, -1, -1, 0 },
-  { "boscub", false, 70, 0, -1, -1, 0 },
-  { "bossit", false, 70, 0, -1, -1, 0 },
-  { "bospn", false, 70, 0, -1, -1, 0 },
-  { "bosdth", false, 70, 0, -1, -1, 0 },
-  { "manatk", false, 70, 0, -1, -1, 0 },
-  { "mandth", false, 70, 0, -1, -1, 0 },
-  { "sssit", false, 70, 0, -1, -1, 0 },
-  { "ssdth", false, 70, 0, -1, -1, 0 },
-  { "keenpn", false, 70, 0, -1, -1, 0 },
-  { "keendt", false, 70, 0, -1, -1, 0 },
-  { "skeact", false, 70, 0, -1, -1, 0 },
-  { "skesit", false, 70, 0, -1, -1, 0 },
-  { "skeatk", false, 70, 0, -1, -1, 0 },
-  { "radio", false, 60, 0, -1, -1, 0 } 
+  SOUND("none",   0),
+  SOUND("pistol", 64),
+  SOUND("shotgn", 64),
+  SOUND("sgcock", 64),
+  SOUND("dshtgn", 64),
+  SOUND("dbopn",  64),
+  SOUND("dbcls",  64),
+  SOUND("dbload", 64),
+  SOUND("plasma", 64),
+  SOUND("bfg",    64),
+  SOUND("sawup",  64),
+  SOUND("sawidl", 118),
+  SOUND("sawful", 64),
+  SOUND("sawhit", 64),
+  SOUND("rlaunc", 64),
+  SOUND("rxplod", 70),
+  SOUND("firsht", 70),
+  SOUND("firxpl", 70),
+  SOUND("pstart", 100),
+  SOUND("pstop",  100),
+  SOUND("doropn", 100),
+  SOUND("dorcls", 100),
+  SOUND("stnmov", 119),
+  SOUND("swtchn", 78),
+  SOUND("swtchx", 78),
+  SOUND("plpain", 96),
+  SOUND("dmpain", 96),
+  SOUND("popain", 96),
+  SOUND("vipain", 96),
+  SOUND("mnpain", 96),
+  SOUND("pepain", 96),
+  SOUND("slop",   78),
+  SOUND("itemup", 78),
+  SOUND("wpnup",  78),
+  SOUND("oof",    96),
+  SOUND("telept", 32),
+  SOUND("posit1", 98),
+  SOUND("posit2", 98),
+  SOUND("posit3", 98),
+  SOUND("bgsit1", 98),
+  SOUND("bgsit2", 98),
+  SOUND("sgtsit", 98),
+  SOUND("cacsit", 98),
+  SOUND("brssit", 94),
+  SOUND("cybsit", 92),
+  SOUND("spisit", 90),
+  SOUND("bspsit", 90),
+  SOUND("kntsit", 90),
+  SOUND("vilsit", 90),
+  SOUND("mansit", 90),
+  SOUND("pesit",  90),
+  SOUND("sklatk", 70),
+  SOUND("sgtatk", 70),
+  SOUND("skepch", 70),
+  SOUND("vilatk", 70),
+  SOUND("claw",   70),
+  SOUND("skeswg", 70),
+  SOUND("pldeth", 32),
+  SOUND("pdiehi", 32),
+  SOUND("podth1", 70),
+  SOUND("podth2", 70),
+  SOUND("podth3", 70),
+  SOUND("bgdth1", 70),
+  SOUND("bgdth2", 70),
+  SOUND("sgtdth", 70),
+  SOUND("cacdth", 70),
+  SOUND("skldth", 70),
+  SOUND("brsdth", 32),
+  SOUND("cybdth", 32),
+  SOUND("spidth", 32),
+  SOUND("bspdth", 32),
+  SOUND("vildth", 32),
+  SOUND("kntdth", 32),
+  SOUND("pedth",  32),
+  SOUND("skedth", 32),
+  SOUND("posact", 120),
+  SOUND("bgact",  120),
+  SOUND("dmact",  120),
+  SOUND("bspact", 100),
+  SOUND("bspwlk", 100),
+  SOUND("vilact", 100),
+  SOUND("noway",  78),
+  SOUND("barexp", 60),
+  SOUND("punch",  64),
+  SOUND("hoof",   70),
+  SOUND("metal",  70),
+  SOUND_LINK("chgun", 64, sfx_pistol, 150, 0),
+  SOUND("tink",   60),
+  SOUND("bdopn",  100),
+  SOUND("bdcls",  100),
+  SOUND("itmbk",  100),
+  SOUND("flame",  32),
+  SOUND("flamst", 32),
+  SOUND("getpow", 60),
+  SOUND("bospit", 70),
+  SOUND("boscub", 70),
+  SOUND("bossit", 70),
+  SOUND("bospn",  70),
+  SOUND("bosdth", 70),
+  SOUND("manatk", 70),
+  SOUND("mandth", 70),
+  SOUND("sssit",  70),
+  SOUND("ssdth",  70),
+  SOUND("keenpn", 70),
+  SOUND("keendt", 70),
+  SOUND("skeact", 70),
+  SOUND("skesit", 70),
+  SOUND("skeatk", 70),
+  SOUND("radio",  60),
 };
 
index 02ceedf85204499cb36b1518ea451e3097de2fe9..1e8afc4051c4bc6e15f572bafd91a2a521e4b424 100644 (file)
@@ -1,90 +1,26 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Created by the sound utility written by Dave Taylor.
 //     Kept as a sample, DOOM2  sounds. Frozen.
 //
-//-----------------------------------------------------------------------------
 
 #ifndef __SOUNDS__
 #define __SOUNDS__
 
-
-//
-// SoundFX struct.
-//
-typedef struct sfxinfo_struct  sfxinfo_t;
-
-struct sfxinfo_struct
-{
-    // up to 6-character name
-    char*      name;
-
-    // Sfx singularity (only one at a time)
-    int                singularity;
-
-    // Sfx priority
-    int                priority;
-
-    // referenced sound if a link
-    sfxinfo_t* link;
-
-    // pitch if a link
-    int                pitch;
-
-    // volume if a link
-    int                volume;
-
-    // sound data
-    void*      data;
-
-    // this is checked every second to see if sound
-    // can be thrown out (if 0, then decrement, if -1,
-    // then throw out, if > 0, then it is in use)
-    int                usefulness;
-
-    // lump number of sfx
-    int                lumpnum;                
-};
-
-
-
-
-//
-// MusicInfo struct.
-//
-typedef struct
-{
-    // up to 6-character name
-    char*      name;
-
-    // lump number of music
-    int                lumpnum;
-    
-    // music data
-    void*      data;
-
-    // music handle once registered
-    int handle;
-    
-} musicinfo_t;
-
-
-
+#include "i_sound.h"
 
 // the complete set of sound effects
 extern sfxinfo_t       S_sfx[];
@@ -289,9 +225,3 @@ typedef enum
 } sfxenum_t;
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-
index 1f060cfc90b1c5f979da1fc4b1c0cbce9f947cae..7ce978d4456288a6964bbbeeeb69fd36e1010638 100644 (file)
@@ -1,39 +1,32 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     The status bar widget code.
 //
-//-----------------------------------------------------------------------------
 
 
-static const char
-rcsid[] = "$Id: st_lib.c,v 1.4 1997/02/03 16:47:56 b1 Exp $";
-
+#include <stdio.h>
 #include <ctype.h>
 
+#include "deh_main.h"
 #include "doomdef.h"
 
 #include "z_zone.h"
 #include "v_video.h"
 
-#include "m_swap.h"
-
+#include "i_swap.h"
 #include "i_system.h"
 
 #include "w_wad.h"
@@ -57,7 +50,7 @@ patch_t*              sttminus;
 
 void STlib_init(void)
 {
-    sttminus = (patch_t *) W_CacheLumpName("STTMINUS", PU_STATIC);
+    sttminus = (patch_t *) W_CacheLumpName(DEH_String("STTMINUS"), PU_STATIC);
 }
 
 
@@ -122,7 +115,7 @@ STlib_drawNum
     if (n->y - ST_Y < 0)
        I_Error("drawNum: n->y - ST_Y < 0");
 
-    V_CopyRect(x, n->y - ST_Y, BG, w*numdigits, h, x, n->y, FG);
+    V_CopyRect(x, n->y - ST_Y, st_backing_screen, w*numdigits, h, x, n->y);
 
     // if non-number, do not draw it
     if (num == 1994)
@@ -132,19 +125,19 @@ STlib_drawNum
 
     // in the special case of 0, you draw 0
     if (!num)
-       V_DrawPatch(x - w, n->y, FG, n->p[ 0 ]);
+       V_DrawPatch(x - w, n->y, n->p[ 0 ]);
 
     // draw the new number
     while (num && numdigits--)
     {
        x -= w;
-       V_DrawPatch(x, n->y, FG, n->p[ num % 10 ]);
+       V_DrawPatch(x, n->y, n->p[ num % 10 ]);
        num /= 10;
     }
 
     // draw a minus sign if necessary
     if (neg)
-       V_DrawPatch(x - 8, n->y, FG, sttminus);
+       V_DrawPatch(x - 8, n->y, sttminus);
 }
 
 
@@ -182,7 +175,7 @@ STlib_updatePercent
   int                  refresh )
 {
     if (refresh && *per->n.on)
-       V_DrawPatch(per->n.x, per->n.y, FG, per->p);
+       V_DrawPatch(per->n.x, per->n.y, per->p);
     
     STlib_updateNum(&per->n, refresh);
 }
@@ -218,9 +211,7 @@ STlib_updateMultIcon
     int                        x;
     int                        y;
 
-    if (*mi->on
-       && (mi->oldinum != *mi->inum || refresh)
-       && (*mi->inum!=-1))
+    if (*mi->on && (mi->oldinum != *mi->inum || refresh) && (*mi->inum != -1))
     {
        if (mi->oldinum != -1)
        {
@@ -232,9 +223,9 @@ STlib_updateMultIcon
            if (y - ST_Y < 0)
                I_Error("updateMultIcon: y - ST_Y < 0");
 
-           V_CopyRect(x, y-ST_Y, BG, w, h, x, y, FG);
+           V_CopyRect(x, y-ST_Y, st_backing_screen, w, h, x, y);
        }
-       V_DrawPatch(mi->x, mi->y, FG, mi->p[*mi->inum]);
+       V_DrawPatch(mi->x, mi->y, mi->p[*mi->inum]);
        mi->oldinum = *mi->inum;
     }
 }
@@ -252,7 +243,7 @@ STlib_initBinIcon
 {
     b->x       = x;
     b->y       = y;
-    b->oldval  = 0;
+    b->oldval  = false;
     b->val     = val;
     b->on      = on;
     b->p       = i;
@@ -271,7 +262,7 @@ STlib_updateBinIcon
     int                        h;
 
     if (*bi->on
-       && (bi->oldval != *bi->val || refresh))
+     && (bi->oldval != *bi->val || refresh))
     {
        x = bi->x - SHORT(bi->p->leftoffset);
        y = bi->y - SHORT(bi->p->topoffset);
@@ -282,9 +273,9 @@ STlib_updateBinIcon
            I_Error("updateBinIcon: y - ST_Y < 0");
 
        if (*bi->val)
-           V_DrawPatch(bi->x, bi->y, FG, bi->p);
+           V_DrawPatch(bi->x, bi->y, bi->p);
        else
-           V_CopyRect(x, y-ST_Y, BG, w, h, x, y, FG);
+           V_CopyRect(x, y-ST_Y, st_backing_screen, w, h, x, y);
 
        bi->oldval = *bi->val;
     }
index de0697740096add56c638892ea5a852ca9f4b298..3a8f5212512e4d7b7d34eb6e73c55799d63980bb 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     The status bar widget code.
 //
-//-----------------------------------------------------------------------------
 
 #ifndef __STLIB__
 #define __STLIB__
 // We are referring to patches.
 #include "r_defs.h"
 
-
-//
-// Background and foreground screen numbers
-//
-#define BG 4
-#define FG 0
-
-
-
 //
 // Typedefs of widgets
 //
@@ -122,7 +110,7 @@ typedef struct
     int                        y;
 
     // last icon value
-    int                        oldval;
+    boolean            oldval;
 
     // pointer to current icon status
     boolean*           val;
@@ -219,8 +207,3 @@ STlib_updateBinIcon
   boolean              refresh );
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 16f2e3f146b81f85ff51b45f0b73df57c042d0e6..e25acccb187096bd233a5dd2761acb771e631a1d 100644 (file)
@@ -1,30 +1,23 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Status bar code.
 //     Does the face/direction indicator animatin.
 //     Does palette indicators as well (red pain/berserk, bright pickup)
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: st_stuff.c,v 1.6 1997/02/03 22:45:13 b1 Exp $";
 
 
 #include <stdio.h>
@@ -32,10 +25,14 @@ rcsid[] = "$Id: st_stuff.c,v 1.6 1997/02/03 22:45:13 b1 Exp $";
 #include "i_system.h"
 #include "i_video.h"
 #include "z_zone.h"
+#include "m_misc.h"
 #include "m_random.h"
 #include "w_wad.h"
 
+#include "deh_main.h"
+#include "deh_misc.h"
 #include "doomdef.h"
+#include "doomkeys.h"
 
 #include "g_game.h"
 
@@ -256,15 +253,14 @@ rcsid[] = "$Id: st_stuff.c,v 1.6 1997/02/03 22:45:13 b1 Exp $";
  // Height, in lines. 
 #define ST_OUTHEIGHT           1
 
-#define ST_MAPWIDTH    \
-    (strlen(mapnames[(gameepisode-1)*9+(gamemap-1)]))
-
 #define ST_MAPTITLEX \
     (SCREENWIDTH - ST_MAPWIDTH * ST_CHATFONTWIDTH)
 
 #define ST_MAPTITLEY           0
 #define ST_MAPHEIGHT           1
 
+// graphics are drawn to a backing screen and blitted to the real screen
+byte                   *st_backing_screen;
            
 // main player in game
 static player_t*       plyr; 
@@ -272,9 +268,6 @@ static player_t*    plyr;
 // ST_Start() has just been called
 static boolean         st_firsttime;
 
-// used to execute ST_Init() only once
-static int             veryfirsttime = 1;
-
 // lump number for PLAYPAL
 static int             lu_palette;
 
@@ -392,103 +385,27 @@ static int       keyboxes[3];
 // a random number per tick
 static int     st_randomnumber;  
 
-
-
-// Massive bunches of cheat shit
-//  to keep it from being easy to figure them out.
-// Yeah, right...
-unsigned char  cheat_mus_seq[] =
-{
-    0xb2, 0x26, 0xb6, 0xae, 0xea, 1, 0, 0, 0xff
-};
-
-unsigned char  cheat_choppers_seq[] =
-{
-    0xb2, 0x26, 0xe2, 0x32, 0xf6, 0x2a, 0x2a, 0xa6, 0x6a, 0xea, 0xff // id...
-};
-
-unsigned char  cheat_god_seq[] =
-{
-    0xb2, 0x26, 0x26, 0xaa, 0x26, 0xff  // iddqd
-};
-
-unsigned char  cheat_ammo_seq[] =
-{
-    0xb2, 0x26, 0xf2, 0x66, 0xa2, 0xff // idkfa
-};
-
-unsigned char  cheat_ammonokey_seq[] =
-{
-    0xb2, 0x26, 0x66, 0xa2, 0xff       // idfa
-};
-
-
-// Smashing Pumpkins Into Samml Piles Of Putried Debris. 
-unsigned char  cheat_noclip_seq[] =
-{
-    0xb2, 0x26, 0xea, 0x2a, 0xb2,      // idspispopd
-    0xea, 0x2a, 0xf6, 0x2a, 0x26, 0xff
-};
-
-//
-unsigned char  cheat_commercial_noclip_seq[] =
-{
-    0xb2, 0x26, 0xe2, 0x36, 0xb2, 0x2a, 0xff   // idclip
-}; 
-
-
-
-unsigned char  cheat_powerup_seq[7][10] =
-{
-    { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0x6e, 0xff },    // beholdv
-    { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0xea, 0xff },    // beholds
-    { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0xb2, 0xff },    // beholdi
-    { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0x6a, 0xff },    // beholdr
-    { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0xa2, 0xff },    // beholda
-    { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0x36, 0xff },    // beholdl
-    { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0xff }           // behold
-};
-
-
-unsigned char  cheat_clev_seq[] =
-{
-    0xb2, 0x26,  0xe2, 0x36, 0xa6, 0x6e, 1, 0, 0, 0xff // idclev
-};
-
-
-// my position cheat
-unsigned char  cheat_mypos_seq[] =
-{
-    0xb2, 0x26, 0xb6, 0xba, 0x2a, 0xf6, 0xea, 0xff     // idmypos
-}; 
-
-
-// Now what?
-cheatseq_t     cheat_mus = { cheat_mus_seq, 0 };
-cheatseq_t     cheat_god = { cheat_god_seq, 0 };
-cheatseq_t     cheat_ammo = { cheat_ammo_seq, 0 };
-cheatseq_t     cheat_ammonokey = { cheat_ammonokey_seq, 0 };
-cheatseq_t     cheat_noclip = { cheat_noclip_seq, 0 };
-cheatseq_t     cheat_commercial_noclip = { cheat_commercial_noclip_seq, 0 };
+cheatseq_t cheat_mus = CHEAT("idmus", 2);
+cheatseq_t cheat_god = CHEAT("iddqd", 0);
+cheatseq_t cheat_ammo = CHEAT("idkfa", 0);
+cheatseq_t cheat_ammonokey = CHEAT("idfa", 0);
+cheatseq_t cheat_noclip = CHEAT("idspispopd", 0);
+cheatseq_t cheat_commercial_noclip = CHEAT("idclip", 0);
 
 cheatseq_t     cheat_powerup[7] =
 {
-    { cheat_powerup_seq[0], 0 },
-    { cheat_powerup_seq[1], 0 },
-    { cheat_powerup_seq[2], 0 },
-    { cheat_powerup_seq[3], 0 },
-    { cheat_powerup_seq[4], 0 },
-    { cheat_powerup_seq[5], 0 },
-    { cheat_powerup_seq[6], 0 }
+    CHEAT("idbeholdv", 0),
+    CHEAT("idbeholds", 0),
+    CHEAT("idbeholdi", 0),
+    CHEAT("idbeholdr", 0),
+    CHEAT("idbeholda", 0),
+    CHEAT("idbeholdl", 0),
+    CHEAT("idbehold", 0),
 };
 
-cheatseq_t     cheat_choppers = { cheat_choppers_seq, 0 };
-cheatseq_t     cheat_clev = { cheat_clev_seq, 0 };
-cheatseq_t     cheat_mypos = { cheat_mypos_seq, 0 };
-
-
-// 
-extern char*   mapnames[];
+cheatseq_t cheat_choppers = CHEAT("idchoppers", 0);
+cheatseq_t cheat_clev = CHEAT("idclev", 2);
+cheatseq_t cheat_mypos = CHEAT("idmypos", 0);
 
 
 //
@@ -501,12 +418,16 @@ void ST_refreshBackground(void)
 
     if (st_statusbaron)
     {
-       V_DrawPatch(ST_X, 0, BG, sbar);
+        V_UseBuffer(st_backing_screen);
+
+       V_DrawPatch(ST_X, 0, sbar);
 
        if (netgame)
-           V_DrawPatch(ST_FX, 0, BG, faceback);
+           V_DrawPatch(ST_FX, 0, faceback);
+
+        V_RestoreBuffer();
 
-       V_CopyRect(ST_X, 0, BG, ST_WIDTH, ST_HEIGHT, ST_X, ST_Y, FG);
+       V_CopyRect(ST_X, 0, st_backing_screen, ST_WIDTH, ST_HEIGHT, ST_X, ST_Y);
     }
 
 }
@@ -540,13 +461,10 @@ ST_Responder (event_t* ev)
   // if a user keypress...
   else if (ev->type == ev_keydown)
   {
-    if (!netgame)
+    if (!netgame && gameskill != sk_nightmare)
     {
-      // b. - enabled for more debug fun.
-      // if (gameskill != sk_nightmare) {
-      
       // 'dqd' cheat for toggleable god mode
-      if (cht_CheckCheat(&cheat_god, ev->data1))
+      if (cht_CheckCheat(&cheat_god, ev->data2))
       {
        plyr->cheats ^= CF_GODMODE;
        if (plyr->cheats & CF_GODMODE)
@@ -554,17 +472,17 @@ ST_Responder (event_t* ev)
          if (plyr->mo)
            plyr->mo->health = 100;
          
-         plyr->health = 100;
-         plyr->message = STSTR_DQDON;
+         plyr->health = deh_god_mode_health;
+         plyr->message = DEH_String(STSTR_DQDON);
        }
        else 
-         plyr->message = STSTR_DQDOFF;
+         plyr->message = DEH_String(STSTR_DQDOFF);
       }
       // 'fa' cheat for killer fucking arsenal
-      else if (cht_CheckCheat(&cheat_ammonokey, ev->data1))
+      else if (cht_CheckCheat(&cheat_ammonokey, ev->data2))
       {
-       plyr->armorpoints = 200;
-       plyr->armortype = 2;
+       plyr->armorpoints = deh_idfa_armor;
+       plyr->armortype = deh_idfa_armor_class;
        
        for (i=0;i<NUMWEAPONS;i++)
          plyr->weaponowned[i] = true;
@@ -572,13 +490,13 @@ ST_Responder (event_t* ev)
        for (i=0;i<NUMAMMO;i++)
          plyr->ammo[i] = plyr->maxammo[i];
        
-       plyr->message = STSTR_FAADDED;
+       plyr->message = DEH_String(STSTR_FAADDED);
       }
       // 'kfa' cheat for key full ammo
-      else if (cht_CheckCheat(&cheat_ammo, ev->data1))
+      else if (cht_CheckCheat(&cheat_ammo, ev->data2))
       {
-       plyr->armorpoints = 200;
-       plyr->armortype = 2;
+       plyr->armorpoints = deh_idkfa_armor;
+       plyr->armortype = deh_idkfa_armor_class;
        
        for (i=0;i<NUMWEAPONS;i++)
          plyr->weaponowned[i] = true;
@@ -589,24 +507,29 @@ ST_Responder (event_t* ev)
        for (i=0;i<NUMCARDS;i++)
          plyr->cards[i] = true;
        
-       plyr->message = STSTR_KFAADDED;
+       plyr->message = DEH_String(STSTR_KFAADDED);
       }
       // 'mus' cheat for changing music
-      else if (cht_CheckCheat(&cheat_mus, ev->data1))
+      else if (cht_CheckCheat(&cheat_mus, ev->data2))
       {
        
        char    buf[3];
        int             musnum;
        
-       plyr->message = STSTR_MUS;
+       plyr->message = DEH_String(STSTR_MUS);
        cht_GetParam(&cheat_mus, buf);
-       
-       if (gamemode == commercial)
+
+        // Note: The original v1.9 had a bug that tried to play back
+        // the Doom II music regardless of gamemode.  This was fixed
+        // in the Ultimate Doom executable so that it would work for
+        // the Doom 1 music as well.
+
+       if (gamemode == commercial || gameversion < exe_ultimate)
        {
          musnum = mus_runnin + (buf[0]-'0')*10 + buf[1]-'0' - 1;
          
          if (((buf[0]-'0')*10 + buf[1]-'0') > 35)
-           plyr->message = STSTR_NOMUS;
+           plyr->message = DEH_String(STSTR_NOMUS);
          else
            S_ChangeMusic(musnum, 1);
        }
@@ -615,27 +538,31 @@ ST_Responder (event_t* ev)
          musnum = mus_e1m1 + (buf[0]-'1')*9 + (buf[1]-'1');
          
          if (((buf[0]-'1')*9 + buf[1]-'1') > 31)
-           plyr->message = STSTR_NOMUS;
+           plyr->message = DEH_String(STSTR_NOMUS);
          else
            S_ChangeMusic(musnum, 1);
        }
       }
-      // Simplified, accepting both "noclip" and "idspispopd".
-      // no clipping mode cheat
-      else if ( cht_CheckCheat(&cheat_noclip, ev->data1) 
-               || cht_CheckCheat(&cheat_commercial_noclip,ev->data1) )
+      else if ( (logical_gamemission == doom 
+                 && cht_CheckCheat(&cheat_noclip, ev->data2))
+             || (logical_gamemission != doom 
+                 && cht_CheckCheat(&cheat_commercial_noclip,ev->data2)))
       {        
+        // Noclip cheat.
+        // For Doom 1, use the idspipsopd cheat; for all others, use
+        // idclip
+
        plyr->cheats ^= CF_NOCLIP;
        
        if (plyr->cheats & CF_NOCLIP)
-         plyr->message = STSTR_NCON;
+         plyr->message = DEH_String(STSTR_NCON);
        else
-         plyr->message = STSTR_NCOFF;
+         plyr->message = DEH_String(STSTR_NCOFF);
       }
       // 'behold?' power-up cheats
       for (i=0;i<6;i++)
       {
-       if (cht_CheckCheat(&cheat_powerup[i], ev->data1))
+       if (cht_CheckCheat(&cheat_powerup[i], ev->data2))
        {
          if (!plyr->powers[i])
            P_GivePower( plyr, i);
@@ -644,36 +571,36 @@ ST_Responder (event_t* ev)
          else
            plyr->powers[i] = 0;
          
-         plyr->message = STSTR_BEHOLDX;
+         plyr->message = DEH_String(STSTR_BEHOLDX);
        }
       }
       
       // 'behold' power-up menu
-      if (cht_CheckCheat(&cheat_powerup[6], ev->data1))
+      if (cht_CheckCheat(&cheat_powerup[6], ev->data2))
       {
-       plyr->message = STSTR_BEHOLD;
+       plyr->message = DEH_String(STSTR_BEHOLD);
       }
       // 'choppers' invulnerability & chainsaw
-      else if (cht_CheckCheat(&cheat_choppers, ev->data1))
+      else if (cht_CheckCheat(&cheat_choppers, ev->data2))
       {
        plyr->weaponowned[wp_chainsaw] = true;
        plyr->powers[pw_invulnerability] = true;
-       plyr->message = STSTR_CHOPPERS;
+       plyr->message = DEH_String(STSTR_CHOPPERS);
       }
       // 'mypos' for player position
-      else if (cht_CheckCheat(&cheat_mypos, ev->data1))
+      else if (cht_CheckCheat(&cheat_mypos, ev->data2))
       {
-       static char     buf[ST_MSGWIDTH];
-       sprintf(buf, "ang=0x%x;x,y=(0x%x,0x%x)",
-               players[consoleplayer].mo->angle,
-               players[consoleplayer].mo->x,
-               players[consoleplayer].mo->y);
-       plyr->message = buf;
+        static char buf[ST_MSGWIDTH];
+        M_snprintf(buf, sizeof(buf), "ang=0x%x;x,y=(0x%x,0x%x)",
+                   players[consoleplayer].mo->angle,
+                   players[consoleplayer].mo->x,
+                   players[consoleplayer].mo->y);
+        plyr->message = buf;
       }
     }
     
     // 'clev' change-level cheat
-    if (cht_CheckCheat(&cheat_clev, ev->data1))
+    if (!netgame && cht_CheckCheat(&cheat_clev, ev->data2))
     {
       char             buf[3];
       int              epsd;
@@ -683,7 +610,7 @@ ST_Responder (event_t* ev)
       
       if (gamemode == commercial)
       {
-       epsd = 0;
+       epsd = 1;
        map = (buf[0] - '0')*10 + buf[1] - '0';
       }
       else
@@ -692,13 +619,20 @@ ST_Responder (event_t* ev)
        map = buf[1] - '0';
       }
 
+      // Chex.exe always warps to episode 1.
+
+      if (gameversion == exe_chex)
+      {
+        epsd = 1;
+      }
+
       // Catch invalid maps.
       if (epsd < 1)
        return false;
 
       if (map < 1)
        return false;
-      
+
       // Ohmygod - this is not going to work.
       if ((gamemode == retail)
          && ((epsd > 4) || (map > 9)))
@@ -712,14 +646,16 @@ ST_Responder (event_t* ev)
          && ((epsd > 1) || (map > 9)))
        return false;
 
+      // The source release has this check as map > 34. However, Vanilla
+      // Doom allows IDCLEV up to MAP40 even though it normally crashes.
       if ((gamemode == commercial)
-       && (( epsd > 1) || (map > 34)))
+       && (( epsd > 1) || (map > 40)))
        return false;
 
       // So be it.
-      plyr->message = STSTR_CLEV;
+      plyr->message = DEH_String(STSTR_CLEV);
       G_DeferedInitNew(gameskill, epsd, map);
-    }    
+    }
   }
   return false;
 }
@@ -1042,6 +978,17 @@ void ST_doPaletteStuff(void)
     else
        palette = 0;
 
+    // In Chex Quest, the player never sees red.  Instead, the
+    // radiation suit palette is used to tint the screen green,
+    // as though the player is being covered in goo by an
+    // attacking flemoid.
+
+    if (gameversion == exe_chex
+     && palette >= STARTREDPALS && palette < STARTREDPALS + NUMREDPALS)
+    {
+        palette = RADIATIONPAL;
+    }
+
     if (palette != st_palette)
     {
        st_palette = palette;
@@ -1121,7 +1068,12 @@ void ST_Drawer (boolean fullscreen, boolean refresh)
 
 }
 
-void ST_loadGraphics(void)
+typedef void (*load_callback_t)(char *lumpname, patch_t **variable); 
+
+// Iterates through all graphics to be loaded or unloaded, along with
+// the variable they use, invoking the specified callback function.
+
+static void ST_loadUnloadGraphics(load_callback_t callback)
 {
 
     int                i;
@@ -1133,112 +1085,105 @@ void ST_loadGraphics(void)
     // Load the numbers, tall and short
     for (i=0;i<10;i++)
     {
-       sprintf(namebuf, "STTNUM%d", i);
-       tallnum[i] = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC);
+       DEH_snprintf(namebuf, 9, "STTNUM%d", i);
+        callback(namebuf, &tallnum[i]);
 
-       sprintf(namebuf, "STYSNUM%d", i);
-       shortnum[i] = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC);
+       DEH_snprintf(namebuf, 9, "STYSNUM%d", i);
+        callback(namebuf, &shortnum[i]);
     }
 
     // Load percent key.
     //Note: why not load STMINUS here, too?
-    tallpercent = (patch_t *) W_CacheLumpName("STTPRCNT", PU_STATIC);
+
+    callback(DEH_String("STTPRCNT"), &tallpercent);
 
     // key cards
     for (i=0;i<NUMCARDS;i++)
     {
-       sprintf(namebuf, "STKEYS%d", i);
-       keys[i] = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC);
+       DEH_snprintf(namebuf, 9, "STKEYS%d", i);
+        callback(namebuf, &keys[i]);
     }
 
     // arms background
-    armsbg = (patch_t *) W_CacheLumpName("STARMS", PU_STATIC);
+    callback(DEH_String("STARMS"), &armsbg);
 
     // arms ownership widgets
-    for (i=0;i<6;i++)
+    for (i=0; i<6; i++)
     {
-       sprintf(namebuf, "STGNUM%d", i+2);
+       DEH_snprintf(namebuf, 9, "STGNUM%d", i+2);
 
-       // gray #
-       arms[i][0] = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC);
+       // gray #
+        callback(namebuf, &arms[i][0]);
 
-       // yellow #
-       arms[i][1] = shortnum[i+2]; 
+        // yellow #
+        arms[i][1] = shortnum[i+2];
     }
 
     // face backgrounds for different color players
-    sprintf(namebuf, "STFB%d", consoleplayer);
-    faceback = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC);
+    DEH_snprintf(namebuf, 9, "STFB%d", consoleplayer);
+    callback(namebuf, &faceback);
 
     // status bar background bits
-    sbar = (patch_t *) W_CacheLumpName("STBAR", PU_STATIC);
+    callback(DEH_String("STBAR"), &sbar);
 
     // face states
     facenum = 0;
-    for (i=0;i<ST_NUMPAINFACES;i++)
+    for (i=0; i<ST_NUMPAINFACES; i++)
     {
-       for (j=0;j<ST_NUMSTRAIGHTFACES;j++)
+       for (j=0; j<ST_NUMSTRAIGHTFACES; j++)
        {
-           sprintf(namebuf, "STFST%d%d", i, j);
-           faces[facenum++] = W_CacheLumpName(namebuf, PU_STATIC);
+           DEH_snprintf(namebuf, 9, "STFST%d%d", i, j);
+            callback(namebuf, &faces[facenum]);
+            ++facenum;
        }
-       sprintf(namebuf, "STFTR%d0", i);        // turn right
-       faces[facenum++] = W_CacheLumpName(namebuf, PU_STATIC);
-       sprintf(namebuf, "STFTL%d0", i);        // turn left
-       faces[facenum++] = W_CacheLumpName(namebuf, PU_STATIC);
-       sprintf(namebuf, "STFOUCH%d", i);       // ouch!
-       faces[facenum++] = W_CacheLumpName(namebuf, PU_STATIC);
-       sprintf(namebuf, "STFEVL%d", i);        // evil grin ;)
-       faces[facenum++] = W_CacheLumpName(namebuf, PU_STATIC);
-       sprintf(namebuf, "STFKILL%d", i);       // pissed off
-       faces[facenum++] = W_CacheLumpName(namebuf, PU_STATIC);
+       DEH_snprintf(namebuf, 9, "STFTR%d0", i);        // turn right
+        callback(namebuf, &faces[facenum]);
+        ++facenum;
+       DEH_snprintf(namebuf, 9, "STFTL%d0", i);        // turn left
+        callback(namebuf, &faces[facenum]);
+        ++facenum;
+       DEH_snprintf(namebuf, 9, "STFOUCH%d", i);       // ouch!
+        callback(namebuf, &faces[facenum]);
+        ++facenum;
+       DEH_snprintf(namebuf, 9, "STFEVL%d", i);        // evil grin ;)
+        callback(namebuf, &faces[facenum]);
+        ++facenum;
+       DEH_snprintf(namebuf, 9, "STFKILL%d", i);       // pissed off
+        callback(namebuf, &faces[facenum]);
+        ++facenum;
     }
-    faces[facenum++] = W_CacheLumpName("STFGOD0", PU_STATIC);
-    faces[facenum++] = W_CacheLumpName("STFDEAD0", PU_STATIC);
 
+    callback(DEH_String("STFGOD0"), &faces[facenum]);
+    ++facenum;
+    callback(DEH_String("STFDEAD0"), &faces[facenum]);
+    ++facenum;
 }
 
-void ST_loadData(void)
+static void ST_loadCallback(char *lumpname, patch_t **variable)
 {
-    lu_palette = W_GetNumForName ("PLAYPAL");
-    ST_loadGraphics();
+    *variable = W_CacheLumpName(lumpname, PU_STATIC);
 }
 
-void ST_unloadGraphics(void)
+void ST_loadGraphics(void)
 {
+    ST_loadUnloadGraphics(ST_loadCallback);
+}
 
-    int i;
-
-    // unload the numbers, tall and short
-    for (i=0;i<10;i++)
-    {
-       Z_ChangeTag(tallnum[i], PU_CACHE);
-       Z_ChangeTag(shortnum[i], PU_CACHE);
-    }
-    // unload tall percent
-    Z_ChangeTag(tallpercent, PU_CACHE); 
-
-    // unload arms background
-    Z_ChangeTag(armsbg, PU_CACHE); 
-
-    // unload gray #'s
-    for (i=0;i<6;i++)
-       Z_ChangeTag(arms[i][0], PU_CACHE);
-    
-    // unload the key cards
-    for (i=0;i<NUMCARDS;i++)
-       Z_ChangeTag(keys[i], PU_CACHE);
-
-    Z_ChangeTag(sbar, PU_CACHE);
-    Z_ChangeTag(faceback, PU_CACHE);
-
-    for (i=0;i<ST_NUMFACES;i++)
-       Z_ChangeTag(faces[i], PU_CACHE);
+void ST_loadData(void)
+{
+    lu_palette = W_GetNumForName (DEH_String("PLAYPAL"));
+    ST_loadGraphics();
+}
 
-    // Note: nobody ain't seen no unloading
-    //   of stminus yet. Dude.
-    
+static void ST_unloadCallback(char *lumpname, patch_t **variable)
+{
+    W_ReleaseLumpName(lumpname);
+    *variable = NULL;
+}
 
+void ST_unloadGraphics(void)
+{
+    ST_loadUnloadGraphics(ST_unloadCallback);
 }
 
 void ST_unloadData(void)
@@ -1465,7 +1410,7 @@ void ST_Stop (void)
 
 void ST_Init (void)
 {
-    veryfirsttime = 0;
     ST_loadData();
-    screens[4] = (byte *) Z_Malloc(ST_WIDTH*ST_HEIGHT, PU_STATIC, 0);
+    st_backing_screen = (byte *) Z_Malloc(ST_WIDTH * ST_HEIGHT, PU_STATIC, 0);
 }
+
index c68a10fe30d3c132ab9d13369f4f9cb0d34716db..8ed53e41c616c10b69e4c6d1447e04316092b853 100644 (file)
@@ -1,35 +1,33 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Status bar code.
 //     Does the face/direction indicator animatin.
 //     Does palette indicators as well (red pain/berserk, bright pickup)
 //
-//-----------------------------------------------------------------------------
 
 #ifndef __STSTUFF_H__
 #define __STSTUFF_H__
 
 #include "doomtype.h"
 #include "d_event.h"
+#include "m_cheat.h"
 
 // Size of statusbar.
 // Now sensitive for scaling.
-#define ST_HEIGHT      32*SCREEN_MUL
+#define ST_HEIGHT      32
 #define ST_WIDTH       SCREENWIDTH
 #define ST_Y           (SCREENHEIGHT - ST_HEIGHT)
 
@@ -74,13 +72,18 @@ typedef enum
 } st_chatstateenum_t;
 
 
-boolean ST_Responder(event_t* ev);
 
+extern byte *st_backing_screen;
+extern cheatseq_t cheat_mus;
+extern cheatseq_t cheat_god;
+extern cheatseq_t cheat_ammo;
+extern cheatseq_t cheat_ammonokey;
+extern cheatseq_t cheat_noclip;
+extern cheatseq_t cheat_commercial_noclip;
+extern cheatseq_t cheat_powerup[7];
+extern cheatseq_t cheat_choppers;
+extern cheatseq_t cheat_clev;
+extern cheatseq_t cheat_mypos;
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
diff --git a/frosted-doom/statdump.c b/frosted-doom/statdump.c
new file mode 100644 (file)
index 0000000..7afe3f3
--- /dev/null
@@ -0,0 +1,392 @@
+ /*
+
+ 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,
+};
+
+#if ORIGCODE
+
+/* Player colors. */
+static const char *player_colors[] =
+{
+    "Green", "Indigo", "Brown", "Red"
+};
+
+#endif
+
+// 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;
+
+#if ORIGCODE
+static GameMission_t discovered_gamemission = none;
+#endif
+
+#if ORIGCODE
+
+/* 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;
+        }
+    }
+}
+
+#endif
+
+#if ORIGCODE
+
+/* 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;
+}
+
+#endif
+
+#if ORIGCODE
+
+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);
+    }
+}
+
+#endif
+
+#if ORIGCODE
+
+/* 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");
+}
+
+#endif
+
+#if ORIGCODE
+
+/* 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");
+}
+
+#endif
+
+#if ORIGCODE
+
+/* 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);
+}
+
+#endif
+
+#if ORIGCODE
+
+/* 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");
+}
+
+#endif
+
+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)
+{
+#if ORIGCODE
+    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);
+        }
+    }
+#endif
+}
+
diff --git a/frosted-doom/statdump.h b/frosted-doom/statdump.h
new file mode 100644 (file)
index 0000000..48db2ad
--- /dev/null
@@ -0,0 +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 */
index 9c5aa8367f10faeedc3fff448e4e003b80621971..c221e9a04c12bfd9d91d4d7d49f831309317e503 100644 (file)
@@ -1,20 +1,16 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Lookup tables.
 //       maps tan(angle) to angle fast. Gotta search.
 //     
 //    
-//-----------------------------------------------------------------------------
-
-
-static const char
-rcsid[] = "$Id: tables.c,v 1.4 1997/02/03 16:47:57 b1 Exp $";
-
-
 
 #include "tables.h"
 
+// to get a global angle from cartesian coordinates, the coordinates are
+// flipped until they are in the first octant of the coordinate system, then
+// the y (<=x) is scaled and divided by x to get a tangent (slope) value
+// which is looked up in the tantoangle[] table.  The +1 size is to handle
+// the case when x==y without additional checking.
 
-
-
-int
-SlopeDiv
-( unsigned     num,
-  unsigned     den)
+int SlopeDiv(unsigned int num, unsigned int den)
 {
-    unsigned   ans;
+    unsigned ans;
     
     if (den < 512)
-       return SLOPERANGE;
-
-    ans = (num<<3)/(den>>8);
+    {
+        return SLOPERANGE;
+    }
+    else
+    {
+        ans = (num << 3) / (den >> 8);
 
-    return ans <= SLOPERANGE ? ans : SLOPERANGE;
+        if (ans <= SLOPERANGE)
+        {
+            return ans;
+        }
+        else
+        {
+            return SLOPERANGE;
+        }
+    }
 }
 
-
-
-
-int finetangent[4096] =
+const int finetangent[4096] =
 {
     -170910304,-56965752,-34178904,-24413316,-18988036,-15535599,-13145455,-11392683,
     -10052327,-8994149,-8137527,-7429880,-6835455,-6329090,-5892567,-5512368,
@@ -581,7 +578,7 @@ int finetangent[4096] =
 };
 
 
-int finesine[10240] =
+const int finesine[10240] =
 {
     25,75,125,175,226,276,326,376,
     427,477,527,578,628,678,728,779,
@@ -1865,9 +1862,9 @@ int finesine[10240] =
     65534,65535,65535,65535,65535,65535,65535,65535
 };
 
+const fixed_t *finecosine = &finesine[FINEANGLES/4];
 
-
-angle_t tantoangle[2049] =
+const angle_t tantoangle[2049] =
 {
     0,333772,667544,1001315,1335086,1668857,2002626,2336395,
     2670163,3003929,3337694,3671457,4005219,4338979,4672736,5006492,
@@ -2128,3 +2125,103 @@ angle_t tantoangle[2049] =
     536870912
 };
 
+// Now where did these came from?
+const byte gammatable[5][256] =
+{
+    {
+        1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
+        17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
+        33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
+        49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,
+        65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
+        81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,
+        97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,
+        113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
+        128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+        144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
+        160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
+        176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
+        192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
+        208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
+        224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
+        240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
+    },
+
+    {
+        2,4,5,7,8,10,11,12,14,15,16,18,19,20,21,23,
+        24,25,26,27,29,30,31,32,33,34,36,37,38,39,40,41,
+        42,44,45,46,47,48,49,50,51,52,54,55,56,57,58,59,
+        60,61,62,63,64,65,66,67,69,70,71,72,73,74,75,76,
+        77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,
+        93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,
+        109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,
+        125,126,127,128,129,129,130,131,132,133,134,135,136,137,138,139,
+        140,141,142,143,144,145,146,147,148,148,149,150,151,152,153,154,
+        155,156,157,158,159,160,161,162,163,163,164,165,166,167,168,169,
+        170,171,172,173,174,175,175,176,177,178,179,180,181,182,183,184,
+        185,186,186,187,188,189,190,191,192,193,194,195,196,196,197,198,
+        199,200,201,202,203,204,205,205,206,207,208,209,210,211,212,213,
+        214,214,215,216,217,218,219,220,221,222,222,223,224,225,226,227,
+        228,229,230,230,231,232,233,234,235,236,237,237,238,239,240,241,
+        242,243,244,245,245,246,247,248,249,250,251,252,252,253,254,255
+    },
+
+    {
+        4,7,9,11,13,15,17,19,21,22,24,26,27,29,30,32,
+        33,35,36,38,39,40,42,43,45,46,47,48,50,51,52,54,
+        55,56,57,59,60,61,62,63,65,66,67,68,69,70,72,73,
+        74,75,76,77,78,79,80,82,83,84,85,86,87,88,89,90,
+        91,92,93,94,95,96,97,98,100,101,102,103,104,105,106,107,
+        108,109,110,111,112,113,114,114,115,116,117,118,119,120,121,122,
+        123,124,125,126,127,128,129,130,131,132,133,133,134,135,136,137,
+        138,139,140,141,142,143,144,144,145,146,147,148,149,150,151,152,
+        153,153,154,155,156,157,158,159,160,160,161,162,163,164,165,166,
+        166,167,168,169,170,171,172,172,173,174,175,176,177,178,178,179,
+        180,181,182,183,183,184,185,186,187,188,188,189,190,191,192,193,
+        193,194,195,196,197,197,198,199,200,201,201,202,203,204,205,206,
+        206,207,208,209,210,210,211,212,213,213,214,215,216,217,217,218,
+        219,220,221,221,222,223,224,224,225,226,227,228,228,229,230,231,
+        231,232,233,234,235,235,236,237,238,238,239,240,241,241,242,243,
+        244,244,245,246,247,247,248,249,250,251,251,252,253,254,254,255
+    },
+
+    {
+        8,12,16,19,22,24,27,29,31,34,36,38,40,41,43,45,
+        47,49,50,52,53,55,57,58,60,61,63,64,65,67,68,70,
+        71,72,74,75,76,77,79,80,81,82,84,85,86,87,88,90,
+        91,92,93,94,95,96,98,99,100,101,102,103,104,105,106,107,
+        108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,
+        124,125,126,127,128,129,130,131,132,133,134,135,135,136,137,138,
+        139,140,141,142,143,143,144,145,146,147,148,149,150,150,151,152,
+        153,154,155,155,156,157,158,159,160,160,161,162,163,164,165,165,
+        166,167,168,169,169,170,171,172,173,173,174,175,176,176,177,178,
+        179,180,180,181,182,183,183,184,185,186,186,187,188,189,189,190,
+        191,192,192,193,194,195,195,196,197,197,198,199,200,200,201,202,
+        202,203,204,205,205,206,207,207,208,209,210,210,211,212,212,213,
+        214,214,215,216,216,217,218,219,219,220,221,221,222,223,223,224,
+        225,225,226,227,227,228,229,229,230,231,231,232,233,233,234,235,
+        235,236,237,237,238,238,239,240,240,241,242,242,243,244,244,245,
+        246,246,247,247,248,249,249,250,251,251,252,253,253,254,254,255
+    },
+
+
+    {
+        16,23,28,32,36,39,42,45,48,50,53,55,57,60,62,64,
+        66,68,69,71,73,75,76,78,80,81,83,84,86,87,89,90,
+        92,93,94,96,97,98,100,101,102,103,105,106,107,108,109,110,
+        112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,128,
+        128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+        143,144,145,146,147,148,149,150,150,151,152,153,154,155,155,156,
+        157,158,159,159,160,161,162,163,163,164,165,166,166,167,168,169,
+        169,170,171,172,172,173,174,175,175,176,177,177,178,179,180,180,
+        181,182,182,183,184,184,185,186,187,187,188,189,189,190,191,191,
+        192,193,193,194,195,195,196,196,197,198,198,199,200,200,201,202,
+        202,203,203,204,205,205,206,207,207,208,208,209,210,210,211,211,
+        212,213,213,214,214,215,216,216,217,217,218,219,219,220,220,221,
+        221,222,223,223,224,224,225,225,226,227,227,228,228,229,229,230,
+        230,231,232,232,233,233,234,234,235,235,236,236,237,237,238,239,
+        239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247,
+        247,248,248,249,249,250,250,251,251,252,252,253,254,254,255,255
+    }
+};
+
index 060fe5b359f5c994432d82f352e8176fcb78ff17..495fd53498fc0f5d063ee846b64d9104fc58bd85 100644 (file)
@@ -1,18 +1,17 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Lookup tables.
 //     int tantoangle[2049]    - ArcTan LUT,
 //       maps tan(angle) to angle fast. Gotta search.  
 //    
-//-----------------------------------------------------------------------------
 
 
 #ifndef __TABLES__
 #define __TABLES__
 
-
-
-#ifdef LINUX
-#include <math.h>
-#else
-#define PI                             3.141592657
-#endif
-
+#include "doomtype.h"
 
 #include "m_fixed.h"
        
 #define ANGLETOFINESHIFT       19              
 
 // Effective size is 10240.
-extern  fixed_t                finesine[5*FINEANGLES/4];
+extern const fixed_t finesine[5*FINEANGLES/4];
 
 // Re-use data, is just PI/2 pahse shift.
-extern  fixed_t*       finecosine;
+extern const fixed_t *finecosine;
 
 
 // Effective size is 4096.
-extern fixed_t         finetangent[FINEANGLES/2];
+extern const fixed_t finetangent[FINEANGLES/2];
+
+// Gamma correction tables.
+extern const byte gammatable[5][256];
 
 // Binary Angle Measument, BAM.
-#define ANG45                  0x20000000
-#define ANG90                  0x40000000
-#define ANG180         0x80000000
-#define ANG270         0xc0000000
 
+#define ANG45           0x20000000
+#define ANG90           0x40000000
+#define ANG180          0x80000000
+#define ANG270          0xc0000000
+#define ANG_MAX         0xffffffff
+
+#define ANG1            (ANG45 / 45)
+#define ANG60           (ANG180 / 3)
+
+// Heretic code uses this definition as though it represents one 
+// degree, but it is not!  This is actually ~1.40 degrees.
+
+#define ANG1_X          0x01000000
 
 #define SLOPERANGE             2048
 #define SLOPEBITS              11
@@ -81,20 +84,13 @@ typedef unsigned angle_t;
 // Effective size is 2049;
 // The +1 size is to handle the case when x==y
 //  without additional checking.
-extern angle_t         tantoangle[SLOPERANGE+1];
+extern const angle_t tantoangle[SLOPERANGE+1];
 
 
 // Utility function,
 //  called by R_PointToAngle.
-int
-SlopeDiv
-( unsigned     num,
-  unsigned     den);
+int SlopeDiv(unsigned int num, unsigned int den);
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
+
diff --git a/frosted-doom/v_patch.h b/frosted-doom/v_patch.h
new file mode 100644 (file)
index 0000000..687dca1
--- /dev/null
@@ -0,0 +1,50 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//      Refresh/rendering module, shared data struct definitions.
+//
+
+
+#ifndef V_PATCH_H
+#define V_PATCH_H
+
+// Patches.
+// A patch holds one or more columns.
+// Patches are used for sprites and all masked pictures,
+// and we compose textures from the TEXTURE1/2 lists
+// of patches.
+
+typedef struct 
+{ 
+    short              width;          // bounding box size 
+    short              height; 
+    short              leftoffset;     // pixels to the left of origin 
+    short              topoffset;      // pixels below the origin 
+    int                        columnofs[8];   // only [width] used
+    // the [0] is &columnofs[width] 
+} PACKEDATTR patch_t;
+
+// posts are runs of non masked source pixels
+typedef struct
+{
+    byte               topdelta;       // -1 is the last post in a column
+    byte               length;         // length data bytes follows
+} PACKEDATTR post_t;
+
+// column_t is a list of 0 or more post_t, (byte)-1 terminated
+typedef post_t column_t;
+
+#endif 
+
index 9b30e6483d8a864dc1a6af9582654745e9ebadb8..6db28aa5fc51a7b0c3d368b8aa5581d6d39711e1 100644 (file)
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Gamma correction LUT stuff.
 //     Functions to draw patches (by post) directly to screen.
 //     Functions to blit a block to the screen.
 //
-//-----------------------------------------------------------------------------
-
-
-static const char
-rcsid[] = "$Id: v_video.c,v 1.5 1997/02/03 22:45:13 b1 Exp $";
 
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
 
 #include "i_system.h"
-#include "r_local.h"
 
-#include "doomdef.h"
-#include "doomdata.h"
+#include "doomtype.h"
 
+#include "deh_str.h"
+#include "i_swap.h"
+#include "i_video.h"
 #include "m_bbox.h"
-#include "m_swap.h"
-
+#include "m_misc.h"
 #include "v_video.h"
+#include "w_wad.h"
+#include "z_zone.h"
 
+#include "config.h"
+#ifdef HAVE_LIBPNG
+#include <png.h>
+#endif
 
-// Each screen is [SCREENWIDTH*SCREENHEIGHT]; 
-byte*                          screens[5];     
-int                            dirtybox[4]; 
+// TODO: There are separate RANGECHECK defines for different games, but this
+// is common code. Fix this.
+#define RANGECHECK
 
+// Blending table used for fuzzpatch, etc.
+// Only used in Heretic/Hexen
 
+byte *tinttable = NULL;
+
+// villsa [STRIFE] Blending table used for Strife
+byte *xlatab = NULL;
+
+// The screen buffer that the v_video.c code draws to.
+
+static byte *dest_screen = NULL;
+
+int dirtybox[4]; 
+
+// haleyjd 08/28/10: clipping callback function for patches.
+// This is needed for Chocolate Strife, which clips patches to the screen.
+static vpatchclipfunc_t patchclip_callback = NULL;
 
-// Now where did these came from?
-byte gammatable[5][256] =
-{
-    {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
-     17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
-     33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
-     49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,
-     65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
-     81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,
-     97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,
-     113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
-     128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
-     144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
-     160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
-     176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
-     192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
-     208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
-     224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
-     240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255},
-
-    {2,4,5,7,8,10,11,12,14,15,16,18,19,20,21,23,24,25,26,27,29,30,31,
-     32,33,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,54,55,
-     56,57,58,59,60,61,62,63,64,65,66,67,69,70,71,72,73,74,75,76,77,
-     78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,
-     99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,
-     115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,129,
-     130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,
-     146,147,148,148,149,150,151,152,153,154,155,156,157,158,159,160,
-     161,162,163,163,164,165,166,167,168,169,170,171,172,173,174,175,
-     175,176,177,178,179,180,181,182,183,184,185,186,186,187,188,189,
-     190,191,192,193,194,195,196,196,197,198,199,200,201,202,203,204,
-     205,205,206,207,208,209,210,211,212,213,214,214,215,216,217,218,
-     219,220,221,222,222,223,224,225,226,227,228,229,230,230,231,232,
-     233,234,235,236,237,237,238,239,240,241,242,243,244,245,245,246,
-     247,248,249,250,251,252,252,253,254,255},
-
-    {4,7,9,11,13,15,17,19,21,22,24,26,27,29,30,32,33,35,36,38,39,40,42,
-     43,45,46,47,48,50,51,52,54,55,56,57,59,60,61,62,63,65,66,67,68,69,
-     70,72,73,74,75,76,77,78,79,80,82,83,84,85,86,87,88,89,90,91,92,93,
-     94,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,
-     113,114,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
-     129,130,131,132,133,133,134,135,136,137,138,139,140,141,142,143,144,
-     144,145,146,147,148,149,150,151,152,153,153,154,155,156,157,158,159,
-     160,160,161,162,163,164,165,166,166,167,168,169,170,171,172,172,173,
-     174,175,176,177,178,178,179,180,181,182,183,183,184,185,186,187,188,
-     188,189,190,191,192,193,193,194,195,196,197,197,198,199,200,201,201,
-     202,203,204,205,206,206,207,208,209,210,210,211,212,213,213,214,215,
-     216,217,217,218,219,220,221,221,222,223,224,224,225,226,227,228,228,
-     229,230,231,231,232,233,234,235,235,236,237,238,238,239,240,241,241,
-     242,243,244,244,245,246,247,247,248,249,250,251,251,252,253,254,254,
-     255},
-
-    {8,12,16,19,22,24,27,29,31,34,36,38,40,41,43,45,47,49,50,52,53,55,
-     57,58,60,61,63,64,65,67,68,70,71,72,74,75,76,77,79,80,81,82,84,85,
-     86,87,88,90,91,92,93,94,95,96,98,99,100,101,102,103,104,105,106,107,
-     108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,
-     125,126,127,128,129,130,131,132,133,134,135,135,136,137,138,139,140,
-     141,142,143,143,144,145,146,147,148,149,150,150,151,152,153,154,155,
-     155,156,157,158,159,160,160,161,162,163,164,165,165,166,167,168,169,
-     169,170,171,172,173,173,174,175,176,176,177,178,179,180,180,181,182,
-     183,183,184,185,186,186,187,188,189,189,190,191,192,192,193,194,195,
-     195,196,197,197,198,199,200,200,201,202,202,203,204,205,205,206,207,
-     207,208,209,210,210,211,212,212,213,214,214,215,216,216,217,218,219,
-     219,220,221,221,222,223,223,224,225,225,226,227,227,228,229,229,230,
-     231,231,232,233,233,234,235,235,236,237,237,238,238,239,240,240,241,
-     242,242,243,244,244,245,246,246,247,247,248,249,249,250,251,251,252,
-     253,253,254,254,255},
-
-    {16,23,28,32,36,39,42,45,48,50,53,55,57,60,62,64,66,68,69,71,73,75,76,
-     78,80,81,83,84,86,87,89,90,92,93,94,96,97,98,100,101,102,103,105,106,
-     107,108,109,110,112,113,114,115,116,117,118,119,120,121,122,123,124,
-     125,126,128,128,129,130,131,132,133,134,135,136,137,138,139,140,141,
-     142,143,143,144,145,146,147,148,149,150,150,151,152,153,154,155,155,
-     156,157,158,159,159,160,161,162,163,163,164,165,166,166,167,168,169,
-     169,170,171,172,172,173,174,175,175,176,177,177,178,179,180,180,181,
-     182,182,183,184,184,185,186,187,187,188,189,189,190,191,191,192,193,
-     193,194,195,195,196,196,197,198,198,199,200,200,201,202,202,203,203,
-     204,205,205,206,207,207,208,208,209,210,210,211,211,212,213,213,214,
-     214,215,216,216,217,217,218,219,219,220,220,221,221,222,223,223,224,
-     224,225,225,226,227,227,228,228,229,229,230,230,231,232,232,233,233,
-     234,234,235,235,236,236,237,237,238,239,239,240,240,241,241,242,242,
-     243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,
-     251,252,252,253,254,254,255,255}
-};
-
-
-
-int    usegamma;
-                        
 //
 // V_MarkRect 
 // 
-void
-V_MarkRect
-( int          x,
-  int          y,
-  int          width,
-  int          height ) 
+void V_MarkRect(int x, int y, int width, int height) 
 { 
-    M_AddToBox (dirtybox, x, y); 
-    M_AddToBox (dirtybox, x+width-1, y+height-1); 
+    // If we are temporarily using an alternate screen, do not 
+    // affect the update box.
+
+    if (dest_screen == I_VideoBuffer)
+    {
+        M_AddToBox (dirtybox, x, y); 
+        M_AddToBox (dirtybox, x + width-1, y + height-1); 
+    }
 } 
  
 
 //
 // V_CopyRect 
 // 
-void
-V_CopyRect
-( int          srcx,
-  int          srcy,
-  int          srcscrn,
-  int          width,
-  int          height,
-  int          destx,
-  int          desty,
-  int          destscrn ) 
+void V_CopyRect(int srcx, int srcy, byte *source,
+                int width, int height,
+                int destx, int desty)
 { 
-    byte*      src;
-    byte*      dest; 
-        
+    byte *src;
+    byte *dest; 
 #ifdef RANGECHECK 
-    if (srcx<0
-       ||srcx+width >SCREENWIDTH
-       || srcy<0
-       || srcy+height>SCREENHEIGHT 
-       ||destx<0||destx+width >SCREENWIDTH
-       || desty<0
-       || desty+height>SCREENHEIGHT 
-       || (unsigned)srcscrn>4
-       || (unsigned)destscrn>4)
-    {
-       I_Error ("Bad V_CopyRect");
+    if (srcx < 0
+     || srcx + width > SCREENWIDTH
+     || srcy < 0
+     || srcy + height > SCREENHEIGHT 
+     || destx < 0
+     || destx + width > SCREENWIDTH
+     || desty < 0
+     || desty + height > SCREENHEIGHT)
+    {
+        I_Error ("Bad V_CopyRect");
     }
 #endif 
-    V_MarkRect (destx, desty, width, height); 
-        
-    src = screens[srcscrn]+SCREENWIDTH*srcy+srcx; 
-    dest = screens[destscrn]+SCREENWIDTH*desty+destx; 
+
+    V_MarkRect(destx, desty, width, height); 
+    src = source + SCREENWIDTH * srcy + srcx; 
+    dest = dest_screen + SCREENWIDTH * desty + destx; 
 
     for ( ; height>0 ; height--) 
     { 
-       memcpy (dest, src, width); 
-       src += SCREENWIDTH; 
-       dest += SCREENWIDTH; 
+        memcpy(dest, src, width); 
+        src += SCREENWIDTH; 
+        dest += SCREENWIDTH; 
     } 
 } 
  
+//
+// V_SetPatchClipCallback
+//
+// haleyjd 08/28/10: Added for Strife support.
+// By calling this function, you can setup runtime error checking for patch 
+// clipping. Strife never caused errors by drawing patches partway off-screen.
+// Some versions of vanilla DOOM also behaved differently than the default
+// implementation, so this could possibly be extended to those as well for
+// accurate emulation.
+//
+void V_SetPatchClipCallback(vpatchclipfunc_t func)
+{
+    patchclip_callback = func;
+}
 
 //
 // V_DrawPatch
 // Masks a column based masked pic to the screen. 
 //
-void
-V_DrawPatch
-( int          x,
-  int          y,
-  int          scrn,
-  patch_t*     patch ) 
+
+void V_DrawPatch(int x, int y, patch_t *patch)
 { 
+    int count;
+    int col;
+    column_t *column;
+    byte *desttop;
+    byte *dest;
+    byte *source;
+    int w;
+
+    y -= SHORT(patch->topoffset);
+    x -= SHORT(patch->leftoffset);
+
+    // haleyjd 08/28/10: Strife needs silent error checking here.
+    if(patchclip_callback)
+    {
+        if(!patchclip_callback(patch, x, y))
+            return;
+    }
 
-    int                count;
-    int                col; 
-    column_t*  column; 
-    byte*      desttop;
-    byte*      dest;
-    byte*      source; 
-    int                w; 
-        
-    y -= SHORT(patch->topoffset); 
-    x -= SHORT(patch->leftoffset); 
-#ifdef RANGECHECK 
-    if (x<0
-       ||x+SHORT(patch->width) >SCREENWIDTH
-       || y<0
-       || y+SHORT(patch->height)>SCREENHEIGHT 
-       || (unsigned)scrn>4)
+#ifdef RANGECHECK
+    if (x < 0
+     || x + SHORT(patch->width) > SCREENWIDTH
+     || y < 0
+     || y + SHORT(patch->height) > SCREENHEIGHT)
     {
-      fprintf( stderr, "Patch at %d,%d exceeds LFB\n", x,y );
-      // No I_Error abort - what is up with TNT.WAD?
-      fprintf( stderr, "V_DrawPatch: bad patch (ignored)\n");
-      return;
+        I_Error("Bad V_DrawPatch x=%i y=%i patch.width=%i patch.height=%i topoffset=%i leftoffset=%i", x, y, patch->width, patch->height, patch->topoffset, patch->leftoffset);
     }
-#endif 
-    if (!scrn)
-       V_MarkRect (x, y, SHORT(patch->width), SHORT(patch->height)); 
+#endif
+
+    V_MarkRect(x, y, SHORT(patch->width), SHORT(patch->height));
+
+    col = 0;
+    desttop = dest_screen + y * SCREENWIDTH + x;
 
-    col = 0; 
-    desttop = screens[scrn]+y*SCREENWIDTH+x; 
-        
-    w = SHORT(patch->width); 
+    w = SHORT(patch->width);
 
     for ( ; col<w ; x++, col++, desttop++)
-    { 
-       column = (column_t *)((byte *)patch + LONG(patch->columnofs[col])); 
-       // step through the posts in a column 
-       while (column->topdelta != 0xff ) 
-       { 
-           source = (byte *)column + 3; 
-           dest = desttop + column->topdelta*SCREENWIDTH; 
-           count = column->length; 
-                        
-           while (count--) 
-           { 
-               *dest = *source++; 
-               dest += SCREENWIDTH; 
-           } 
-           column = (column_t *)(  (byte *)column + column->length 
-                                   + 4 ); 
-       } 
-    }                   
-} 
+    {
+        column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
+
+        // step through the posts in a column
+        while (column->topdelta != 0xff)
+        {
+            source = (byte *)column + 3;
+            dest = desttop + column->topdelta*SCREENWIDTH;
+            count = column->length;
+
+            while (count--)
+            {
+                *dest = *source++;
+                dest += SCREENWIDTH;
+            }
+            column = (column_t *)((byte *)column + column->length + 4);
+        }
+    }
+}
+
 //
-// V_DrawPatchFlipped 
+// V_DrawPatchFlipped
 // Masks a column based masked pic to the screen.
 // Flips horizontally, e.g. to mirror face.
 //
-void
-V_DrawPatchFlipped
-( int          x,
-  int          y,
-  int          scrn,
-  patch_t*     patch ) 
-{ 
 
-    int                count;
-    int                col; 
-    column_t*  column; 
-    byte*      desttop;
-    byte*      dest;
-    byte*      source; 
-    int                w; 
-        
+void V_DrawPatchFlipped(int x, int y, patch_t *patch)
+{
+    int count;
+    int col; 
+    column_t *column; 
+    byte *desttop;
+    byte *dest;
+    byte *source; 
+    int w; 
     y -= SHORT(patch->topoffset); 
     x -= SHORT(patch->leftoffset); 
+
+    // haleyjd 08/28/10: Strife needs silent error checking here.
+    if(patchclip_callback)
+    {
+        if(!patchclip_callback(patch, x, y))
+            return;
+    }
+
 #ifdef RANGECHECK 
-    if (x<0
-       ||x+SHORT(patch->width) >SCREENWIDTH
-       || y<0
-       || y+SHORT(patch->height)>SCREENHEIGHT 
-       || (unsigned)scrn>4)
+    if (x < 0
+     || x + SHORT(patch->width) > SCREENWIDTH
+     || y < 0
+     || y + SHORT(patch->height) > SCREENHEIGHT)
     {
-      fprintf( stderr, "Patch origin %d,%d exceeds LFB\n", x,y );
-      I_Error ("Bad V_DrawPatch in V_DrawPatchFlipped");
+        I_Error("Bad V_DrawPatchFlipped");
     }
-#endif 
-    if (!scrn)
-       V_MarkRect (x, y, SHORT(patch->width), SHORT(patch->height)); 
+#endif
 
-    col = 0; 
-    desttop = screens[scrn]+y*SCREENWIDTH+x; 
-        
-    w = SHORT(patch->width); 
+    V_MarkRect (x, y, SHORT(patch->width), SHORT(patch->height));
+
+    col = 0;
+    desttop = dest_screen + y * SCREENWIDTH + x;
+
+    w = SHORT(patch->width);
+
+    for ( ; col<w ; x++, col++, desttop++)
+    {
+        column = (column_t *)((byte *)patch + LONG(patch->columnofs[w-1-col]));
+
+        // step through the posts in a column
+        while (column->topdelta != 0xff )
+        {
+            source = (byte *)column + 3;
+            dest = desttop + column->topdelta*SCREENWIDTH;
+            count = column->length;
+
+            while (count--)
+            {
+                *dest = *source++;
+                dest += SCREENWIDTH;
+            }
+            column = (column_t *)((byte *)column + column->length + 4);
+        }
+    }
+}
 
-    for ( ; col<w ; x++, col++, desttop++) 
-    { 
-       column = (column_t *)((byte *)patch + LONG(patch->columnofs[w-1-col])); 
-       // step through the posts in a column 
-       while (column->topdelta != 0xff ) 
-       { 
-           source = (byte *)column + 3; 
-           dest = desttop + column->topdelta*SCREENWIDTH; 
-           count = column->length; 
-                        
-           while (count--) 
-           { 
-               *dest = *source++; 
-               dest += SCREENWIDTH; 
-           } 
-           column = (column_t *)(  (byte *)column + column->length 
-                                   + 4 ); 
-       } 
-    }                   
-} 
 
 
 //
 // V_DrawPatchDirect
 // Draws directly to the screen on the pc. 
 //
-void
-V_DrawPatchDirect
-( int          x,
-  int          y,
-  int          scrn,
-  patch_t*     patch ) 
+
+void V_DrawPatchDirect(int x, int y, patch_t *patch)
 {
-    V_DrawPatch (x,y,scrn, patch); 
-
-    /*
-    int                count;
-    int                col; 
-    column_t*  column; 
-    byte*      desttop;
-    byte*      dest;
-    byte*      source; 
-    int                w; 
-        
-    y -= SHORT(patch->topoffset); 
-    x -= SHORT(patch->leftoffset); 
+    V_DrawPatch(x, y, patch); 
+} 
 
-#ifdef RANGECHECK 
-    if (x<0
-       ||x+SHORT(patch->width) >SCREENWIDTH
-       || y<0
-       || y+SHORT(patch->height)>SCREENHEIGHT 
-       || (unsigned)scrn>4)
+//
+// V_DrawTLPatch
+//
+// Masks a column based translucent masked pic to the screen.
+//
+
+void V_DrawTLPatch(int x, int y, patch_t * patch)
+{
+    int count, col;
+    column_t *column;
+    byte *desttop, *dest, *source;
+    int w;
+
+    y -= SHORT(patch->topoffset);
+    x -= SHORT(patch->leftoffset);
+
+    if (x < 0
+     || x + SHORT(patch->width) > SCREENWIDTH 
+     || y < 0
+     || y + SHORT(patch->height) > SCREENHEIGHT)
     {
-       I_Error ("Bad V_DrawPatchDirect");
+        I_Error("Bad V_DrawTLPatch");
     }
-#endif 
-    // V_MarkRect (x, y, SHORT(patch->width), SHORT(patch->height)); 
-    desttop = destscreen + y*SCREENWIDTH/4 + (x>>2); 
-        
-    w = SHORT(patch->width); 
-    for ( col = 0 ; col<w ; col++) 
-    { 
-       outp (SC_INDEX+1,1<<(x&3)); 
-       column = (column_t *)((byte *)patch + LONG(patch->columnofs[col])); 
-       // step through the posts in a column 
-        
-       while (column->topdelta != 0xff ) 
-       { 
-           source = (byte *)column + 3; 
-           dest = desttop + column->topdelta*SCREENWIDTH/4; 
-           count = column->length; 
-           while (count--) 
-           { 
-               *dest = *source++; 
-               dest += SCREENWIDTH/4; 
-           } 
-           column = (column_t *)(  (byte *)column + column->length 
-                                   + 4 ); 
-       } 
-       if ( ((++x)&3) == 0 ) 
-           desttop++;  // go to next byte, not next plane 
-    }*/ 
-} 
 
+    col = 0;
+    desttop = dest_screen + y * SCREENWIDTH + x;
+
+    w = SHORT(patch->width);
+    for (; col < w; x++, col++, desttop++)
+    {
+        column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col]));
+
+        // step through the posts in a column
+
+        while (column->topdelta != 0xff)
+        {
+            source = (byte *) column + 3;
+            dest = desttop + column->topdelta * SCREENWIDTH;
+            count = column->length;
+
+            while (count--)
+            {
+                *dest = tinttable[((*dest) << 8) + *source++];
+                dest += SCREENWIDTH;
+            }
+            column = (column_t *) ((byte *) column + column->length + 4);
+        }
+    }
+}
+
+//
+// V_DrawXlaPatch
+//
+// villsa [STRIFE] Masks a column based translucent masked pic to the screen.
+//
+
+void V_DrawXlaPatch(int x, int y, patch_t * patch)
+{
+    int count, col;
+    column_t *column;
+    byte *desttop, *dest, *source;
+    int w;
+
+    y -= SHORT(patch->topoffset);
+    x -= SHORT(patch->leftoffset);
+
+    if(patchclip_callback)
+    {
+        if(!patchclip_callback(patch, x, y))
+            return;
+    }
+
+    col = 0;
+    desttop = dest_screen + y * SCREENWIDTH + x;
+
+    w = SHORT(patch->width);
+    for(; col < w; x++, col++, desttop++)
+    {
+        column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col]));
+
+        // step through the posts in a column
+
+        while(column->topdelta != 0xff)
+        {
+            source = (byte *) column + 3;
+            dest = desttop + column->topdelta * SCREENWIDTH;
+            count = column->length;
+
+            while(count--)
+            {
+                *dest = xlatab[*dest + ((*source) << 8)];
+                source++;
+                dest += SCREENWIDTH;
+            }
+            column = (column_t *) ((byte *) column + column->length + 4);
+        }
+    }
+}
+
+//
+// V_DrawAltTLPatch
+//
+// Masks a column based translucent masked pic to the screen.
+//
+
+void V_DrawAltTLPatch(int x, int y, patch_t * patch)
+{
+    int count, col;
+    column_t *column;
+    byte *desttop, *dest, *source;
+    int w;
+
+    y -= SHORT(patch->topoffset);
+    x -= SHORT(patch->leftoffset);
+
+    if (x < 0
+     || x + SHORT(patch->width) > SCREENWIDTH
+     || y < 0
+     || y + SHORT(patch->height) > SCREENHEIGHT)
+    {
+        I_Error("Bad V_DrawAltTLPatch");
+    }
+
+    col = 0;
+    desttop = dest_screen + y * SCREENWIDTH + x;
+
+    w = SHORT(patch->width);
+    for (; col < w; x++, col++, desttop++)
+    {
+        column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col]));
+
+        // step through the posts in a column
+
+        while (column->topdelta != 0xff)
+        {
+            source = (byte *) column + 3;
+            dest = desttop + column->topdelta * SCREENWIDTH;
+            count = column->length;
+
+            while (count--)
+            {
+                *dest = tinttable[((*dest) << 8) + *source++];
+                dest += SCREENWIDTH;
+            }
+            column = (column_t *) ((byte *) column + column->length + 4);
+        }
+    }
+}
+
+//
+// V_DrawShadowedPatch
+//
+// Masks a column based masked pic to the screen.
+//
+
+void V_DrawShadowedPatch(int x, int y, patch_t *patch)
+{
+    int count, col;
+    column_t *column;
+    byte *desttop, *dest, *source;
+    byte *desttop2, *dest2;
+    int w;
+
+    y -= SHORT(patch->topoffset);
+    x -= SHORT(patch->leftoffset);
+
+    if (x < 0
+     || x + SHORT(patch->width) > SCREENWIDTH
+     || y < 0
+     || y + SHORT(patch->height) > SCREENHEIGHT)
+    {
+        I_Error("Bad V_DrawShadowedPatch");
+    }
+
+    col = 0;
+    desttop = dest_screen + y * SCREENWIDTH + x;
+    desttop2 = dest_screen + (y + 2) * SCREENWIDTH + x + 2;
+
+    w = SHORT(patch->width);
+    for (; col < w; x++, col++, desttop++, desttop2++)
+    {
+        column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col]));
+
+        // step through the posts in a column
+
+        while (column->topdelta != 0xff)
+        {
+            source = (byte *) column + 3;
+            dest = desttop + column->topdelta * SCREENWIDTH;
+            dest2 = desttop2 + column->topdelta * SCREENWIDTH;
+            count = column->length;
+
+            while (count--)
+            {
+                *dest2 = tinttable[((*dest2) << 8)];
+                dest2 += SCREENWIDTH;
+                *dest = *source++;
+                dest += SCREENWIDTH;
+
+            }
+            column = (column_t *) ((byte *) column + column->length + 4);
+        }
+    }
+}
+
+//
+// Load tint table from TINTTAB lump.
+//
+
+void V_LoadTintTable(void)
+{
+    tinttable = W_CacheLumpName("TINTTAB", PU_STATIC);
+}
+
+//
+// V_LoadXlaTable
+//
+// villsa [STRIFE] Load xla table from XLATAB lump.
+//
+
+void V_LoadXlaTable(void)
+{
+    xlatab = W_CacheLumpName("XLATAB", PU_STATIC);
+}
 
 //
 // V_DrawBlock
 // Draw a linear block of pixels into the view buffer.
 //
-void
-V_DrawBlock
-( int          x,
-  int          y,
-  int          scrn,
-  int          width,
-  int          height,
-  byte*                src ) 
+
+void V_DrawBlock(int x, int y, int width, int height, byte *src) 
 { 
-    byte*      dest; 
-        
+    byte *dest; 
 #ifdef RANGECHECK 
-    if (x<0
-       ||x+width >SCREENWIDTH
-       || y<0
-       || y+height>SCREENHEIGHT 
-       || (unsigned)scrn>4 )
+    if (x < 0
+     || x + width >SCREENWIDTH
+     || y < 0
+     || y + height > SCREENHEIGHT)
     {
        I_Error ("Bad V_DrawBlock");
     }
@@ -425,7 +516,7 @@ V_DrawBlock
  
     V_MarkRect (x, y, width, height); 
  
-    dest = screens[scrn] + y*SCREENWIDTH+x; 
+    dest = dest_screen + y * SCREENWIDTH + x; 
 
     while (height--) 
     { 
@@ -434,60 +525,408 @@ V_DrawBlock
        dest += SCREENWIDTH; 
     } 
 } 
 
+void V_DrawFilledBox(int x, int y, int w, int h, int c)
+{
+    uint8_t *buf, *buf1;
+    int x1, y1;
 
-//
-// V_GetBlock
-// Gets a linear block of pixels from the view buffer.
-//
-void
-V_GetBlock
-( int          x,
-  int          y,
-  int          scrn,
-  int          width,
-  int          height,
-  byte*                dest ) 
-{ 
-    byte*      src; 
-        
-#ifdef RANGECHECK 
-    if (x<0
-       ||x+width >SCREENWIDTH
-       || y<0
-       || y+height>SCREENHEIGHT 
-       || (unsigned)scrn>4 )
+    buf = I_VideoBuffer + SCREENWIDTH * y + x;
+
+    for (y1 = 0; y1 < h; ++y1)
     {
-       I_Error ("Bad V_DrawBlock");
+        buf1 = buf;
+
+        for (x1 = 0; x1 < w; ++x1)
+        {
+            *buf1++ = c;
+        }
+
+        buf += SCREENWIDTH;
     }
-#endif 
-    src = screens[scrn] + y*SCREENWIDTH+x; 
+}
 
-    while (height--) 
-    { 
-       memcpy (dest, src, width); 
-       src += SCREENWIDTH; 
-       dest += width; 
-    } 
-} 
+void V_DrawHorizLine(int x, int y, int w, int c)
+{
+    uint8_t *buf;
+    int x1;
+
+    buf = I_VideoBuffer + SCREENWIDTH * y + x;
 
+    for (x1 = 0; x1 < w; ++x1)
+    {
+        *buf++ = c;
+    }
+}
+
+void V_DrawVertLine(int x, int y, int h, int c)
+{
+    uint8_t *buf;
+    int y1;
+
+    buf = I_VideoBuffer + SCREENWIDTH * y + x;
+
+    for (y1 = 0; y1 < h; ++y1)
+    {
+        *buf = c;
+        buf += SCREENWIDTH;
+    }
+}
 
+void V_DrawBox(int x, int y, int w, int h, int c)
+{
+    V_DrawHorizLine(x, y, w, c);
+    V_DrawHorizLine(x, y+h-1, w, c);
+    V_DrawVertLine(x, y, h, c);
+    V_DrawVertLine(x+w-1, y, h, c);
+}
 
+//
+// Draw a "raw" screen (lump containing raw data to blit directly
+// to the screen)
+//
+void V_DrawRawScreen(byte *raw)
+{
+    memcpy(dest_screen, raw, SCREENWIDTH * SCREENHEIGHT);
+}
 
 //
 // V_Init
 // 
 void V_Init (void) 
 { 
+    // no-op!
+    // There used to be separate screens that could be drawn to; these are
+    // now handled in the upper layers.
+}
+
+// Set the buffer that the code draws to.
+
+void V_UseBuffer(byte *buffer)
+{
+    dest_screen = buffer;
+}
+
+// Restore screen buffer to the i_video screen buffer.
+
+void V_RestoreBuffer(void)
+{
+    dest_screen = I_VideoBuffer;
+}
+
+//
+// SCREEN SHOTS
+//
+
+typedef struct
+{
+    char               manufacturer;
+    char               version;
+    char               encoding;
+    char               bits_per_pixel;
+
+    unsigned short     xmin;
+    unsigned short     ymin;
+    unsigned short     xmax;
+    unsigned short     ymax;
+    
+    unsigned short     hres;
+    unsigned short     vres;
+
+    unsigned char      palette[48];
+    
+    char               reserved;
+    char               color_planes;
+    unsigned short     bytes_per_line;
+    unsigned short     palette_type;
+    
+    char               filler[58];
+    unsigned char      data;           // unbounded
+} PACKEDATTR pcx_t;
+
+
+//
+// WritePCXfile
+//
+
+void WritePCXfile(char *filename, byte *data,
+                  int width, int height,
+                  byte *palette)
+{
     int                i;
-    byte*      base;
-               
-    // stick these in low dos memory on PCs
+    int                length;
+    pcx_t*     pcx;
+    byte*      pack;
+       
+    pcx = Z_Malloc (width*height*2+1000, PU_STATIC, NULL);
+
+    pcx->manufacturer = 0x0a;          // PCX id
+    pcx->version = 5;                  // 256 color
+    pcx->encoding = 1;                 // uncompressed
+    pcx->bits_per_pixel = 8;           // 256 color
+    pcx->xmin = 0;
+    pcx->ymin = 0;
+    pcx->xmax = SHORT(width-1);
+    pcx->ymax = SHORT(height-1);
+    pcx->hres = SHORT(width);
+    pcx->vres = SHORT(height);
+    memset (pcx->palette,0,sizeof(pcx->palette));
+    pcx->color_planes = 1;             // chunky image
+    pcx->bytes_per_line = SHORT(width);
+    pcx->palette_type = SHORT(2);      // not a grey scale
+    memset (pcx->filler,0,sizeof(pcx->filler));
+
+    // pack the image
+    pack = &pcx->data;
+       
+    for (i=0 ; i<width*height ; i++)
+    {
+       if ( (*data & 0xc0) != 0xc0)
+           *pack++ = *data++;
+       else
+       {
+           *pack++ = 0xc1;
+           *pack++ = *data++;
+       }
+    }
+    
+    // write the palette
+    *pack++ = 0x0c;    // palette ID byte
+    for (i=0 ; i<768 ; i++)
+       *pack++ = *palette++;
+    
+    // write output file
+    length = pack - (byte *)pcx;
+    M_WriteFile (filename, pcx, length);
+
+    Z_Free (pcx);
+}
 
-    base = I_AllocLow (SCREENWIDTH*SCREENHEIGHT*4);
+#ifdef HAVE_LIBPNG
+//
+// WritePNGfile
+//
+
+static void error_fn(png_structp p, png_const_charp s)
+{
+    printf("libpng error: %s\n", s);
+}
 
-    for (i=0 ; i<4 ; i++)
-       screens[i] = base + i*SCREENWIDTH*SCREENHEIGHT;
+static void warning_fn(png_structp p, png_const_charp s)
+{
+    printf("libpng warning: %s\n", s);
 }
+
+void WritePNGfile(char *filename, byte *data,
+                  int width, int height,
+                  byte *palette)
+{
+    png_structp ppng;
+    png_infop pinfo;
+    png_colorp pcolor;
+    FILE *handle;
+    int i;
+
+    handle = fopen(filename, "wb");
+    if (!handle)
+    {
+        return;
+    }
+
+    ppng = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
+                                   error_fn, warning_fn);
+    if (!ppng)
+    {
+        return;
+    }
+
+    pinfo = png_create_info_struct(ppng);
+    if (!pinfo)
+    {
+        png_destroy_write_struct(&ppng, NULL);
+        return;
+    }
+
+    png_init_io(ppng, handle);
+
+    png_set_IHDR(ppng, pinfo, width, height,
+                 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
+                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+    pcolor = malloc(sizeof(*pcolor) * 256);
+    if (!pcolor)
+    {
+        png_destroy_write_struct(&ppng, &pinfo);
+        return;
+    }
+
+    for (i = 0; i < 256; i++)
+    {
+        pcolor[i].red   = *(palette + 3 * i);
+        pcolor[i].green = *(palette + 3 * i + 1);
+        pcolor[i].blue  = *(palette + 3 * i + 2);
+    }
+
+    png_set_PLTE(ppng, pinfo, pcolor, 256);
+    free(pcolor);
+
+    png_write_info(ppng, pinfo);
+
+    for (i = 0; i < SCREENHEIGHT; i++)
+    {
+        png_write_row(ppng, data + i*SCREENWIDTH);
+    }
+
+    png_write_end(ppng, pinfo);
+    png_destroy_write_struct(&ppng, &pinfo);
+    fclose(handle);
+}
+#endif
+
+//
+// V_ScreenShot
+//
+
+void V_ScreenShot(char *format)
+{
+    int i;
+    char lbmname[16]; // haleyjd 20110213: BUG FIX - 12 is too small!
+    char *ext;
+    
+    // find a file name to save it to
+
+#ifdef HAVE_LIBPNG
+    extern int png_screenshots;
+    if (png_screenshots)
+    {
+        ext = "png";
+    }
+    else
+#endif
+    {
+        ext = "pcx";
+    }
+
+    for (i=0; i<=99; i++)
+    {
+        M_snprintf(lbmname, sizeof(lbmname), format, i, ext);
+
+        if (!M_FileExists(lbmname))
+        {
+            break;      // file doesn't exist
+        }
+    }
+
+    if (i == 100)
+    {
+        I_Error ("V_ScreenShot: Couldn't create a PCX");
+    }
+
+#ifdef HAVE_LIBPNG
+    if (png_screenshots)
+    {
+    WritePNGfile(lbmname, I_VideoBuffer,
+                 SCREENWIDTH, SCREENHEIGHT,
+                 W_CacheLumpName (DEH_String("PLAYPAL"), PU_CACHE));
+    }
+    else
+#endif
+    {
+    // save the pcx file
+    WritePCXfile(lbmname, I_VideoBuffer,
+                 SCREENWIDTH, SCREENHEIGHT,
+                 W_CacheLumpName (DEH_String("PLAYPAL"), PU_CACHE));
+    }
+}
+
+#define MOUSE_SPEED_BOX_WIDTH  120
+#define MOUSE_SPEED_BOX_HEIGHT 9
+
+void V_DrawMouseSpeedBox(int speed)
+{
+    extern int usemouse;
+    int bgcolor, bordercolor, red, black, white, yellow;
+    int box_x, box_y;
+    int original_speed;
+    int redline_x;
+    int linelen;
+
+    // Get palette indices for colors for widget. These depend on the
+    // palette of the game being played.
+
+    bgcolor = I_GetPaletteIndex(0x77, 0x77, 0x77);
+    bordercolor = I_GetPaletteIndex(0x55, 0x55, 0x55);
+    red = I_GetPaletteIndex(0xff, 0x00, 0x00);
+    black = I_GetPaletteIndex(0x00, 0x00, 0x00);
+    yellow = I_GetPaletteIndex(0xff, 0xff, 0x00);
+    white = I_GetPaletteIndex(0xff, 0xff, 0xff);
+
+    // If the mouse is turned off or acceleration is turned off, don't
+    // draw the box at all.
+
+    if (!usemouse || fabs(mouse_acceleration - 1) < 0.01)
+    {
+        return;
+    }
+
+    // Calculate box position
+
+    box_x = SCREENWIDTH - MOUSE_SPEED_BOX_WIDTH - 10;
+    box_y = 15;
+
+    V_DrawFilledBox(box_x, box_y,
+                    MOUSE_SPEED_BOX_WIDTH, MOUSE_SPEED_BOX_HEIGHT, bgcolor);
+    V_DrawBox(box_x, box_y,
+              MOUSE_SPEED_BOX_WIDTH, MOUSE_SPEED_BOX_HEIGHT, bordercolor);
+
+    // Calculate the position of the red line.  This is 1/3 of the way
+    // along the box.
+
+    redline_x = MOUSE_SPEED_BOX_WIDTH / 3;
+
+    // Undo acceleration and get back the original mouse speed
+
+    if (speed < mouse_threshold)
+    {
+        original_speed = speed;
+    }
+    else
+    {
+        original_speed = speed - mouse_threshold;
+        original_speed = (int) (original_speed / mouse_acceleration);
+        original_speed += mouse_threshold;
+    }
+
+    // Calculate line length
+
+    linelen = (original_speed * redline_x) / mouse_threshold;
+
+    // Draw horizontal "thermometer" 
+
+    if (linelen > MOUSE_SPEED_BOX_WIDTH - 1)
+    {
+        linelen = MOUSE_SPEED_BOX_WIDTH - 1;
+    }
+
+    V_DrawHorizLine(box_x + 1, box_y + 4, MOUSE_SPEED_BOX_WIDTH - 2, black);
+
+    if (linelen < redline_x)
+    {
+        V_DrawHorizLine(box_x + 1, box_y + MOUSE_SPEED_BOX_HEIGHT / 2,
+                      linelen, white);
+    }
+    else
+    {
+        V_DrawHorizLine(box_x + 1, box_y + MOUSE_SPEED_BOX_HEIGHT / 2,
+                        redline_x, white);
+        V_DrawHorizLine(box_x + redline_x, box_y + MOUSE_SPEED_BOX_HEIGHT / 2,
+                        linelen - redline_x, yellow);
+    }
+
+    // Draw red line
+
+    V_DrawVertLine(box_x + redline_x, box_y + 1,
+                 MOUSE_SPEED_BOX_HEIGHT - 2, red);
+}
+
index cc2aca56d7425861b9fa98d0584aa1b547b83f59..a970c71933a2dee53de1092f3da7b809ccd09655 100644 (file)
@@ -1,25 +1,22 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Gamma correction LUT.
 //     Functions to draw patches (by post) directly to screen.
 //     Functions to blit a block to the screen.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __V_VIDEO__
 
 #include "doomtype.h"
 
-#include "doomdef.h"
-
 // Needed because we are refering to patches.
-#include "r_data.h"
+#include "v_patch.h"
 
 //
 // VIDEO
 #define CENTERY                        (SCREENHEIGHT/2)
 
 
-// Screen 0 is the screen updated by I_Update screen.
-// Screen 1 is an extra buffer.
+extern int dirtybox[4];
 
+extern byte *tinttable;
 
+// haleyjd 08/28/10: implemented for Strife support
+// haleyjd 08/28/10: Patch clipping callback, implemented to support Choco
+// Strife.
+typedef boolean (*vpatchclipfunc_t)(patch_t *, int, int);
+void V_SetPatchClipCallback(vpatchclipfunc_t func);
 
-extern byte*           screens[5];
 
-extern  int    dirtybox[4];
+// Allocates buffer screens, call before R_Init.
+void V_Init (void);
 
-extern byte    gammatable[5][256];
-extern int     usegamma;
+// Draw a block from the specified source screen to the screen.
 
+void V_CopyRect(int srcx, int srcy, byte *source,
+                int width, int height,
+                int destx, int desty);
 
+void V_DrawPatch(int x, int y, patch_t *patch);
+void V_DrawPatchFlipped(int x, int y, patch_t *patch);
+void V_DrawTLPatch(int x, int y, patch_t *patch);
+void V_DrawAltTLPatch(int x, int y, patch_t * patch);
+void V_DrawShadowedPatch(int x, int y, patch_t *patch);
+void V_DrawXlaPatch(int x, int y, patch_t * patch);     // villsa [STRIFE]
+void V_DrawPatchDirect(int x, int y, patch_t *patch);
 
-// Allocates buffer screens, call before R_Init.
-void V_Init (void);
+// Draw a linear block of pixels into the view buffer.
 
+void V_DrawBlock(int x, int y, int width, int height, byte *src);
 
-void
-V_CopyRect
-( int          srcx,
-  int          srcy,
-  int          srcscrn,
-  int          width,
-  int          height,
-  int          destx,
-  int          desty,
-  int          destscrn );
-
-void
-V_DrawPatch
-( int          x,
-  int          y,
-  int          scrn,
-  patch_t*     patch);
-
-void
-V_DrawPatchDirect
-( int          x,
-  int          y,
-  int          scrn,
-  patch_t*     patch );
+void V_MarkRect(int x, int y, int width, int height);
 
+void V_DrawFilledBox(int x, int y, int w, int h, int c);
+void V_DrawHorizLine(int x, int y, int w, int c);
+void V_DrawVertLine(int x, int y, int h, int c);
+void V_DrawBox(int x, int y, int w, int h, int c);
 
-// Draw a linear block of pixels into the view buffer.
-void
-V_DrawBlock
-( int          x,
-  int          y,
-  int          scrn,
-  int          width,
-  int          height,
-  byte*                src );
-
-// Reads a linear block of pixels into the view buffer.
-void
-V_GetBlock
-( int          x,
-  int          y,
-  int          scrn,
-  int          width,
-  int          height,
-  byte*                dest );
-
-
-void
-V_MarkRect
-( int          x,
-  int          y,
-  int          width,
-  int          height );
+// Draw a raw screen lump
+
+void V_DrawRawScreen(byte *raw);
+
+// Temporarily switch to using a different buffer to draw graphics, etc.
+
+void V_UseBuffer(byte *buffer);
+
+// Return to using the normal screen buffer to draw graphics.
+
+void V_RestoreBuffer(void);
+
+// Save a screenshot of the current screen to a file, named in the 
+// format described in the string passed to the function, eg.
+// "DOOM%02i.pcx"
+
+void V_ScreenShot(char *format);
+
+// Load the lookup table for translucency calculations from the TINTTAB
+// lump.
+
+void V_LoadTintTable(void);
+
+// villsa [STRIFE]
+// Load the lookup table for translucency calculations from the XLATAB
+// lump.
+
+void V_LoadXlaTable(void);
+
+void V_DrawMouseSpeedBox(int speed);
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
+
diff --git a/frosted-doom/w_checksum.c b/frosted-doom/w_checksum.c
new file mode 100644 (file)
index 0000000..5933fdf
--- /dev/null
@@ -0,0 +1,87 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//       Generate a checksum of the WAD directory.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "m_misc.h"
+#include "sha1.h"
+#include "w_checksum.h"
+#include "w_wad.h"
+
+static wad_file_t **open_wadfiles = NULL;
+static int num_open_wadfiles = 0;
+
+static int GetFileNumber(wad_file_t *handle)
+{
+    int i;
+    int result;
+
+    for (i=0; i<num_open_wadfiles; ++i)
+    {
+        if (open_wadfiles[i] == handle)
+        {
+            return i;
+        }
+    }
+
+    // Not found in list.  This is a new file we haven't seen yet.
+    // Allocate another slot for this file.
+
+    open_wadfiles = realloc(open_wadfiles,
+                            sizeof(wad_file_t *) * (num_open_wadfiles + 1));
+    open_wadfiles[num_open_wadfiles] = handle;
+
+    result = num_open_wadfiles;
+    ++num_open_wadfiles;
+
+    return result;
+}
+
+static void ChecksumAddLump(sha1_context_t *sha1_context, lumpinfo_t *lump)
+{
+    char buf[9];
+
+    M_StringCopy(buf, lump->name, sizeof(buf));
+    SHA1_UpdateString(sha1_context, buf);
+    SHA1_UpdateInt32(sha1_context, GetFileNumber(lump->wad_file));
+    SHA1_UpdateInt32(sha1_context, lump->position);
+    SHA1_UpdateInt32(sha1_context, lump->size);
+}
+
+void W_Checksum(sha1_digest_t digest)
+{
+    sha1_context_t sha1_context;
+    unsigned int i;
+
+    SHA1_Init(&sha1_context);
+
+    num_open_wadfiles = 0;
+
+    // Go through each entry in the WAD directory, adding information
+    // about each entry to the SHA1 hash.
+
+    for (i=0; i<numlumps; ++i)
+    {
+        ChecksumAddLump(&sha1_context, &lumpinfo[i]);
+    }
+    
+    SHA1_Final(digest, &sha1_context);
+}
+
diff --git a/frosted-doom/w_checksum.h b/frosted-doom/w_checksum.h
new file mode 100644 (file)
index 0000000..e1ce5b8
--- /dev/null
@@ -0,0 +1,27 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//       Generate a checksum of the WAD directory.
+//
+
+#ifndef W_CHECKSUM_H
+#define W_CHECKSUM_H
+
+#include "doomtype.h"
+
+extern void W_Checksum(sha1_digest_t digest);
+
+#endif /* #ifndef W_CHECKSUM_H */
+
diff --git a/frosted-doom/w_file.c b/frosted-doom/w_file.c
new file mode 100644 (file)
index 0000000..891e095
--- /dev/null
@@ -0,0 +1,91 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//     WAD I/O functions.
+//
+
+#include <stdio.h>
+
+#include "config.h"
+
+#include "doomtype.h"
+#include "m_argv.h"
+
+#include "w_file.h"
+
+extern wad_file_class_t stdc_wad_file;
+
+#ifdef _WIN32
+extern wad_file_class_t win32_wad_file;
+#endif
+
+#ifdef HAVE_MMAP
+extern wad_file_class_t posix_wad_file;
+#endif 
+
+static wad_file_class_t *wad_file_classes[] = 
+{
+#ifdef _WIN32
+    &win32_wad_file,
+#endif
+#ifdef HAVE_MMAP
+    &posix_wad_file,
+#endif
+    &stdc_wad_file,
+};
+
+wad_file_t *W_OpenFile(char *path)
+{
+    wad_file_t *result;
+    int i;
+
+    //!
+    // Use the OS's virtual memory subsystem to map WAD files
+    // directly into memory.
+    //
+
+    if (!M_CheckParm("-mmap"))
+    {
+        return stdc_wad_file.OpenFile(path);
+    }
+
+    // Try all classes in order until we find one that works
+
+    result = NULL;
+
+    for (i = 0; i < arrlen(wad_file_classes); ++i)
+    {
+        result = wad_file_classes[i]->OpenFile(path);
+
+        if (result != NULL)
+        {
+            break;
+        }
+    }
+
+    return result;
+}
+
+void W_CloseFile(wad_file_t *wad)
+{
+    wad->file_class->CloseFile(wad);
+}
+
+size_t W_Read(wad_file_t *wad, unsigned int offset,
+              void *buffer, size_t buffer_len)
+{
+    return wad->file_class->Read(wad, offset, buffer, buffer_len);
+}
+
diff --git a/frosted-doom/w_file.h b/frosted-doom/w_file.h
new file mode 100644 (file)
index 0000000..f577814
--- /dev/null
@@ -0,0 +1,78 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//     WAD I/O functions.
+//
+
+
+#ifndef __W_FILE__
+#define __W_FILE__
+
+#include <stdio.h>
+#include "doomtype.h"
+
+typedef struct _wad_file_s wad_file_t;
+
+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;
+};
+
+// Open the specified file. Returns a pointer to a new wad_file_t 
+// handle for the WAD file, or NULL if it could not be opened.
+
+wad_file_t *W_OpenFile(char *path);
+
+// Close the specified WAD file.
+
+void W_CloseFile(wad_file_t *wad);
+
+// Read data from the specified file into the provided buffer.  The
+// data is read from the specified offset from the start of the file.
+// Returns the number of bytes read.
+
+size_t W_Read(wad_file_t *wad, unsigned int offset,
+              void *buffer, size_t buffer_len);
+
+#endif /* #ifndef __W_FILE__ */
diff --git a/frosted-doom/w_file_stdc.c b/frosted-doom/w_file_stdc.c
new file mode 100644 (file)
index 0000000..829e960
--- /dev/null
@@ -0,0 +1,96 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//     WAD I/O functions.
+//
+
+#include <stdio.h>
+
+#include "m_misc.h"
+#include "w_file.h"
+#include "z_zone.h"
+
+typedef struct
+{
+    wad_file_t wad;
+    FILE *fstream;
+} stdc_wad_file_t;
+
+extern wad_file_class_t stdc_wad_file;
+
+static wad_file_t *W_StdC_OpenFile(char *path)
+{
+    stdc_wad_file_t *result;
+    FILE *fstream;
+
+    fstream = fopen(path, "rb");
+
+    if (fstream == NULL)
+    {
+        return NULL;
+    }
+
+    // Create a new stdc_wad_file_t to hold the file handle.
+
+    result = Z_Malloc(sizeof(stdc_wad_file_t), PU_STATIC, 0);
+    result->wad.file_class = &stdc_wad_file;
+    result->wad.mapped = NULL;
+    result->wad.length = M_FileLength(fstream);
+    result->fstream = fstream;
+
+    return &result->wad;
+}
+
+static void W_StdC_CloseFile(wad_file_t *wad)
+{
+    stdc_wad_file_t *stdc_wad;
+
+    stdc_wad = (stdc_wad_file_t *) wad;
+
+    fclose(stdc_wad->fstream);
+    Z_Free(stdc_wad);
+}
+
+// Read data from the specified position in the file into the 
+// provided buffer.  Returns the number of bytes read.
+
+size_t W_StdC_Read(wad_file_t *wad, unsigned int offset,
+                   void *buffer, size_t buffer_len)
+{
+    stdc_wad_file_t *stdc_wad;
+    size_t result;
+
+    stdc_wad = (stdc_wad_file_t *) wad;
+
+    // Jump to the specified position in the file.
+
+    fseek(stdc_wad->fstream, offset, SEEK_SET);
+
+    // Read into the buffer.
+
+    result = fread(buffer, 1, buffer_len, stdc_wad->fstream);
+
+    return result;
+}
+
+
+wad_file_class_t stdc_wad_file = 
+{
+    W_StdC_OpenFile,
+    W_StdC_CloseFile,
+    W_StdC_Read,
+};
+
+
diff --git a/frosted-doom/w_file_stdc_unbuffered.c b/frosted-doom/w_file_stdc_unbuffered.c
new file mode 100644 (file)
index 0000000..e59e63b
--- /dev/null
@@ -0,0 +1,118 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//     WAD I/O functions.
+//
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "m_misc.h"
+#include "w_file.h"
+#include "z_zone.h"
+
+typedef struct
+{
+    wad_file_t wad;
+    int fd;
+} stdc_wad_file_t;
+
+extern wad_file_class_t stdc_wad_file;
+
+static unsigned int W_StdC_FileLength(int fd)
+{
+    long savedpos;
+    long length;
+
+    // save the current position in the file
+    savedpos = lseek(fd, 0, SEEK_CUR);
+    
+    // jump to the end and find the length
+    length = lseek(fd, 0, SEEK_END);
+
+    // go back to the old location
+    lseek(fd, savedpos, SEEK_SET);
+
+    return length;
+}
+
+static wad_file_t *W_StdC_OpenFile(char *path)
+{
+    stdc_wad_file_t *result;
+    int fd;
+
+    fd = open(path, O_RDONLY);
+
+    if (fd <= 0)
+    {
+        return NULL;
+    }
+
+    // Create a new stdc_wad_file_t to hold the file handle.
+
+    result = Z_Malloc(sizeof(stdc_wad_file_t), PU_STATIC, 0);
+    result->wad.file_class = &stdc_wad_file;
+    result->wad.mapped = NULL;
+    result->wad.length = W_StdC_FileLength(fd);
+    result->fd = fd;
+
+    return &result->wad;
+}
+
+static void W_StdC_CloseFile(wad_file_t *wad)
+{
+    stdc_wad_file_t *stdc_wad;
+
+    stdc_wad = (stdc_wad_file_t *) wad;
+
+    close(stdc_wad->fd);
+    Z_Free(stdc_wad);
+}
+
+// Read data from the specified position in the file into the 
+// provided buffer.  Returns the number of bytes read.
+
+size_t W_StdC_Read(wad_file_t *wad, unsigned int offset,
+                   void *buffer, size_t buffer_len)
+{
+    stdc_wad_file_t *stdc_wad;
+    size_t result;
+
+    stdc_wad = (stdc_wad_file_t *) wad;
+
+    // Jump to the specified position in the file.
+
+    lseek(stdc_wad->fd, offset, SEEK_SET);
+
+    // Read into the buffer.
+
+    result = read(stdc_wad->fd, buffer, buffer_len);
+
+    return result;
+}
+
+
+wad_file_class_t stdc_wad_file = 
+{
+    W_StdC_OpenFile,
+    W_StdC_CloseFile,
+    W_StdC_Read,
+};
+
+
diff --git a/frosted-doom/w_main.c b/frosted-doom/w_main.c
new file mode 100644 (file)
index 0000000..115f081
--- /dev/null
@@ -0,0 +1,198 @@
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// 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.
+//
+// DESCRIPTION:
+//     Common code to parse command line, identifying WAD files to load.
+//
+
+#include "doomfeatures.h"
+#include "d_iwad.h"
+#include "m_argv.h"
+#include "w_main.h"
+#include "w_merge.h"
+#include "w_wad.h"
+#include "z_zone.h"
+
+// Parse the command line, merging WAD files that are sppecified.
+// Returns true if at least one file was added.
+
+boolean W_ParseCommandLine(void)
+{
+    boolean modifiedgame = false;
+    int p;
+
+#ifdef FEATURE_WAD_MERGE
+
+    // Merged PWADs are loaded first, because they are supposed to be 
+    // modified IWADs.
+
+    //!
+    // @arg <files>
+    // @category mod
+    //
+    // Simulates the behavior of deutex's -merge option, merging a PWAD
+    // into the main IWAD.  Multiple files may be specified.
+    //
+
+    p = M_CheckParmWithArgs("-merge", 1);
+
+    if (p > 0)
+    {
+        for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
+        {
+            char *filename;
+
+            modifiedgame = true;
+
+            filename = D_TryFindWADByName(myargv[p]);
+
+            printf(" merging %s\n", filename);
+            W_MergeFile(filename);
+        }
+    }
+
+    // NWT-style merging:
+
+    // NWT's -merge option:
+
+    //!
+    // @arg <files>
+    // @category mod
+    //
+    // Simulates the behavior of NWT's -merge option.  Multiple files
+    // may be specified.
+
+    p = M_CheckParmWithArgs("-nwtmerge", 1);
+
+    if (p > 0)
+    {
+        for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
+        {
+            char *filename;
+
+            modifiedgame = true;
+
+            filename = D_TryFindWADByName(myargv[p]);
+
+            printf(" performing NWT-style merge of %s\n", filename);
+            W_NWTDashMerge(filename);
+        }
+    }
+    
+    // Add flats
+
+    //!
+    // @arg <files>
+    // @category mod
+    //
+    // Simulates the behavior of NWT's -af option, merging flats into
+    // the main IWAD directory.  Multiple files may be specified.
+    //
+
+    p = M_CheckParmWithArgs("-af", 1);
+
+    if (p > 0)
+    {
+        for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
+        {
+            char *filename;
+
+            modifiedgame = true;
+
+            filename = D_TryFindWADByName(myargv[p]);
+
+            printf(" merging flats from %s\n", filename);
+            W_NWTMergeFile(filename, W_NWT_MERGE_FLATS);
+        }
+    }
+
+    //!
+    // @arg <files>
+    // @category mod
+    //
+    // Simulates the behavior of NWT's -as option, merging sprites
+    // into the main IWAD directory.  Multiple files may be specified.
+    //
+
+    p = M_CheckParmWithArgs("-as", 1);
+
+    if (p > 0)
+    {
+        for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
+        {
+            char *filename;
+
+            modifiedgame = true;
+            filename = D_TryFindWADByName(myargv[p]);
+
+            printf(" merging sprites from %s\n", filename);
+            W_NWTMergeFile(filename, W_NWT_MERGE_SPRITES);
+        }
+    }
+
+    //!
+    // @arg <files>
+    // @category mod
+    //
+    // Equivalent to "-af <files> -as <files>".
+    //
+
+    p = M_CheckParmWithArgs("-aa", 1);
+
+    if (p > 0)
+    {
+        for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
+        {
+            char *filename;
+
+            modifiedgame = true;
+
+            filename = D_TryFindWADByName(myargv[p]);
+
+            printf(" merging sprites and flats from %s\n", filename);
+            W_NWTMergeFile(filename, W_NWT_MERGE_SPRITES | W_NWT_MERGE_FLATS);
+        }
+    }
+
+#endif
+
+    //!
+    // @arg <files>
+    // @vanilla
+    //
+    // Load the specified PWAD files.
+    //
+
+    p = M_CheckParmWithArgs ("-file", 1);
+    if (p)
+    {
+       // the parms after p are wadfile/lump names,
+       // until end of parms or another - preceded parm
+       modifiedgame = true;            // homebrew levels
+       while (++p != myargc && myargv[p][0] != '-')
+        {
+            char *filename;
+
+            filename = D_TryFindWADByName(myargv[p]);
+
+            printf(" adding %s\n", filename);
+           W_AddFile(filename);
+        }
+    }
+
+//    W_PrintDirectory();
+
+    return modifiedgame;
+}
+
diff --git a/frosted-doom/w_main.h b/frosted-doom/w_main.h
new file mode 100644 (file)
index 0000000..2e39efc
--- /dev/null
@@ -0,0 +1,24 @@
+//
+// 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.
+//
+// DESCRIPTION:
+//     Common code to parse command line, identifying WAD files to load.
+//
+
+#ifndef W_MAIN_H
+#define W_MAIN_H
+
+boolean W_ParseCommandLine(void);
+
+#endif /* #ifndef W_MAIN_H */
+
diff --git a/frosted-doom/w_merge.h b/frosted-doom/w_merge.h
new file mode 100644 (file)
index 0000000..c8ecc69
--- /dev/null
@@ -0,0 +1,44 @@
+//
+// 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.
+//
+// DESCRIPTION:
+// Handles merging of PWADs, similar to deutex's -merge option
+//
+// Ideally this should work exactly the same as in deutex, but trying to
+// read the deutex source code made my brain hurt.
+//
+
+#ifndef W_MERGE_H
+#define W_MERGE_H
+
+#define W_NWT_MERGE_SPRITES   0x1
+#define W_NWT_MERGE_FLATS     0x2
+
+// Add a new WAD and merge it into the main directory
+
+void W_MergeFile(char *filename);
+
+// NWT-style merging
+
+void W_NWTMergeFile(char *filename, int flags);
+
+// Acts the same as NWT's "-merge" option.
+
+void W_NWTDashMerge(char *filename);
+
+// Debug function that prints the WAD directory.
+
+void W_PrintDirectory(void);
+
+#endif /* #ifndef W_MERGE_H */
+
index 636e4fb5ed78cab83e9604780c0bead09f42cc1a..1248046397aef094eb18e1bed475e570a7f3e1ad 100644 (file)
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Handles WAD file header, directory, lump I/O.
 //
-//-----------------------------------------------------------------------------
 
 
-static const char
-rcsid[] = "$Id: w_wad.c,v 1.5 1997/02/03 16:47:57 b1 Exp $";
 
 
-#ifdef NORMALUNIX
 #include <ctype.h>
-#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <alloca.h>
-#define O_BINARY               0
-#endif
 
 #include "doomtype.h"
-#include "m_swap.h"
+
+#include "config.h"
+#include "d_iwad.h"
+#include "i_swap.h"
 #include "i_system.h"
+#include "i_video.h"
+#include "m_misc.h"
 #include "z_zone.h"
 
-#ifdef __GNUG__
-#pragma implementation "w_wad.h"
-#endif
 #include "w_wad.h"
 
+typedef struct
+{
+    // Should be "IWAD" or "PWAD".
+    char               identification[4];              
+    int                        numlumps;
+    int                        infotableofs;
+} PACKEDATTR wadinfo_t;
 
 
-
-
+typedef struct
+{
+    int                        filepos;
+    int                        size;
+    char               name[8];
+} PACKEDATTR filelump_t;
 
 //
 // GLOBALS
 //
 
 // Location of each lump on disk.
-lumpinfo_t*            lumpinfo;               
-int                    numlumps;
-
-void**                 lumpcache;
 
+lumpinfo_t *lumpinfo;          
+unsigned int numlumps = 0;
 
-#define strcmpi        strcasecmp
+// Hash table for fast lookups
 
-void d_strupr (char* s)
-{
-    while (*s) { *s = toupper(*s); s++; }
-}
+static lumpinfo_t **lumphash;
 
-int filelength (int handle) 
-{ 
-    struct stat        fileinfo;
-    
-    if (fstat (handle,&fileinfo) == -1)
-       I_Error ("Error fstating");
+// Hash function used for lump names.
 
-    return fileinfo.st_size;
-}
+unsigned int W_LumpNameHash(const char *s)
+{
+    // This is the djb2 string hash function, modded to work on strings
+    // that have a maximum length of 8.
 
+    unsigned int result = 5381;
+    unsigned int i;
 
-void
-ExtractFileBase
-( char*                path,
-  char*                dest )
-{
-    char*      src;
-    int                length;
-
-    src = path + strlen(path) - 1;
-    
-    // back up until a \ or the start
-    while (src != path
-          && *(src-1) != '\\'
-          && *(src-1) != '/')
+    for (i=0; i < 8 && s[i] != '\0'; ++i)
     {
-       src--;
+        result = ((result << 5) ^ result ) ^ toupper((int)s[i]);
     }
-    
-    // copy up to eight characters
-    memset (dest,0,8);
-    length = 0;
-    
-    while (*src && *src != '.')
-    {
-       if (++length == 9)
-           I_Error ("Filename base of %s >8 chars",path);
 
-       *dest++ = toupper((int)*src++);
-    }
+    return result;
 }
 
+// Increase the size of the lumpinfo[] array to the specified size.
+static void ExtendLumpInfo(int newnumlumps)
+{
+    lumpinfo_t *newlumpinfo;
+    unsigned int i;
 
+    newlumpinfo = calloc(newnumlumps, sizeof(lumpinfo_t));
+
+    if (newlumpinfo == NULL)
+    {
+       I_Error ("Couldn't realloc lumpinfo");
+    }
 
+    // Copy over lumpinfo_t structures from the old array. If any of
+    // these lumps have been cached, we need to update the user
+    // pointers to the new location.
+    for (i = 0; i < numlumps && i < newnumlumps; ++i)
+    {
+        memcpy(&newlumpinfo[i], &lumpinfo[i], sizeof(lumpinfo_t));
+
+        if (newlumpinfo[i].cache != NULL)
+        {
+            Z_ChangeUser(newlumpinfo[i].cache, &newlumpinfo[i].cache);
+        }
+
+        // We shouldn't be generating a hash table until after all WADs have
+        // been loaded, but just in case...
+        if (lumpinfo[i].next != NULL)
+        {
+            int nextlumpnum = lumpinfo[i].next - lumpinfo;
+            newlumpinfo[i].next = &newlumpinfo[nextlumpnum];
+        }
+    }
 
+    // All done.
+    free(lumpinfo);
+    lumpinfo = newlumpinfo;
+    numlumps = newnumlumps;
+}
 
 //
 // LUMP BASED ROUTINES.
@@ -129,214 +135,105 @@ ExtractFileBase
 //  with multiple lumps.
 // Other files are single lumps with the base filename
 //  for the lump name.
-//
-// If filename starts with a tilde, the file is handled
-//  specially to allow map reloads.
-// But: the reload feature is a fragile hack...
-
-int                    reloadlump;
-char*                  reloadname;
-
 
-void W_AddFile (char *filename)
+wad_file_t *W_AddFile (char *filename)
 {
-    wadinfo_t          header;
-    lumpinfo_t*                lump_p;
-    unsigned           i;
-    int                        handle;
-    int                        length;
-    int                        startlump;
-    filelump_t*                fileinfo;
-    filelump_t         singleinfo;
-    int                        storehandle;
-    
+    wadinfo_t header;
+    lumpinfo_t *lump_p;
+    unsigned int i;
+    wad_file_t *wad_file;
+    int length;
+    int startlump;
+    filelump_t *fileinfo;
+    filelump_t *filerover;
+    int newnumlumps;
+
     // open the file and add to directory
 
-    // handle reload indicator.
-    if (filename[0] == '~')
-    {
-       filename++;
-       reloadname = filename;
-       reloadlump = numlumps;
-    }
-               
-    if ( (handle = open (filename,O_RDONLY | O_BINARY)) == -1)
-    {
-       printf (" couldn't open %s\n",filename);
-       return;
-    }
+    wad_file = W_OpenFile(filename);
 
-    printf (" adding %s\n",filename);
-    startlump = numlumps;
-       
-    if (strcmpi (filename+strlen(filename)-3 , "wad" ) )
+    if (wad_file == NULL)
     {
-       // single lump file
-       fileinfo = &singleinfo;
-       singleinfo.filepos = 0;
-       singleinfo.size = LONG(filelength(handle));
-       ExtractFileBase (filename, singleinfo.name);
-       numlumps++;
-    }
-    else 
-    {
-       // WAD file
-       read (handle, &header, sizeof(header));
-       if (strncmp(header.identification,"IWAD",4))
-       {
-           // Homebrew levels?
-           if (strncmp(header.identification,"PWAD",4))
-           {
-               I_Error ("Wad file %s doesn't have IWAD "
-                        "or PWAD id\n", filename);
-           }
-           
-           // ???modifiedgame = true;          
-       }
-       header.numlumps = LONG(header.numlumps);
-       header.infotableofs = LONG(header.infotableofs);
-       length = header.numlumps*sizeof(filelump_t);
-       //XXX fileinfo = alloca (length);
-       fileinfo = malloc (length);
-       lseek (handle, header.infotableofs, SEEK_SET);
-       read (handle, fileinfo, length);
-       numlumps += header.numlumps;
+               printf (" couldn't open %s\n", filename);
+               return NULL;
     }
 
-    
-    // Fill in lumpinfo
-    lumpinfo = realloc (lumpinfo, numlumps*sizeof(lumpinfo_t));
+    newnumlumps = numlumps;
 
-    if (!lumpinfo)
-       I_Error ("Couldn't realloc lumpinfo");
-
-    lump_p = &lumpinfo[startlump];
-       
-    storehandle = reloadname ? -1 : handle;
-       
-    for (i=startlump ; i<numlumps ; i++,lump_p++, fileinfo++)
+    if (strcasecmp(filename+strlen(filename)-3 , "wad" ) )
     {
-       lump_p->handle = storehandle;
-       lump_p->position = LONG(fileinfo->filepos);
-       lump_p->size = LONG(fileinfo->size);
-       strncpy (lump_p->name, fileinfo->name, 8);
-    }
+       // single lump file
 
-    //XXX: Alloca replacement
-    free(fileinfo);
-       
-    if (reloadname)
-       close (handle);
-}
+        // fraggle: Swap the filepos and size here.  The WAD directory
+        // parsing code expects a little-endian directory, so will swap
+        // them back.  Effectively we're constructing a "fake WAD directory"
+        // here, as it would appear on disk.
 
+               fileinfo = Z_Malloc(sizeof(filelump_t), PU_STATIC, 0);
+               fileinfo->filepos = LONG(0);
+               fileinfo->size = LONG(wad_file->length);
 
+        // Name the lump after the base of the filename (without the
+        // extension).
 
-
-//
-// W_Reload
-// Flushes any of the reloadable lumps in memory
-//  and reloads the directory.
-//
-void W_Reload (void)
-{
-    wadinfo_t          header;
-    int                        lumpcount;
-    lumpinfo_t*                lump_p;
-    unsigned           i;
-    int                        handle;
-    int                        length;
-    filelump_t*                fileinfo;
-       
-    if (!reloadname)
-       return;
-               
-    if ( (handle = open (reloadname,O_RDONLY | O_BINARY)) == -1)
-       I_Error ("W_Reload: couldn't open %s",reloadname);
-
-    read (handle, &header, sizeof(header));
-    lumpcount = LONG(header.numlumps);
-    header.infotableofs = LONG(header.infotableofs);
-    length = lumpcount*sizeof(filelump_t);
-    //XXX fileinfo = alloca (length);
-    fileinfo = malloc (length);
-    if (!fileinfo)
-        return;
-    lseek (handle, header.infotableofs, SEEK_SET);
-    read (handle, fileinfo, length);
-    
-    // Fill in lumpinfo
-    lump_p = &lumpinfo[reloadlump];
-       
-    for (i=reloadlump ;
-        i<reloadlump+lumpcount ;
-        i++,lump_p++, fileinfo++)
+               M_ExtractFileBase (filename, fileinfo->name);
+               newnumlumps++;
+    }
+    else 
     {
-       if (lumpcache[i])
-           Z_Free (lumpcache[i]);
-
-       lump_p->position = LONG(fileinfo->filepos);
-       lump_p->size = LONG(fileinfo->size);
+       // WAD file
+        W_Read(wad_file, 0, &header, sizeof(header));
+
+               if (strncmp(header.identification,"IWAD",4))
+               {
+                       // Homebrew levels?
+                       if (strncmp(header.identification,"PWAD",4))
+                       {
+                       I_Error ("Wad file %s doesn't have IWAD "
+                                "or PWAD id\n", filename);
+                       }
+
+                       // ???modifiedgame = true;
+               }
+
+               header.numlumps = LONG(header.numlumps);
+               header.infotableofs = LONG(header.infotableofs);
+               length = header.numlumps*sizeof(filelump_t);
+               fileinfo = Z_Malloc(length, PU_STATIC, 0);
+
+        W_Read(wad_file, header.infotableofs, fileinfo, length);
+        newnumlumps += header.numlumps;
     }
 
-    free(fileinfo);
-    close (handle);
-}
-
-
+    // Increase size of numlumps array to accomodate the new file.
+    startlump = numlumps;
+    ExtendLumpInfo(newnumlumps);
 
-//
-// W_InitMultipleFiles
-// Pass a null terminated list of files to use.
-// All files are optional, but at least one file
-//  must be found.
-// Files with a .wad extension are idlink files
-//  with multiple lumps.
-// Other files are single lumps with the base filename
-//  for the lump name.
-// Lump names can appear multiple times.
-// The name searcher looks backwards, so a later file
-//  does override all earlier ones.
-//
-void W_InitMultipleFiles (char** filenames)
-{      
-    int                size;
-    
-    // open all the files, load headers, and count lumps
-    numlumps = 0;
-
-    // will be realloced as lumps are added
-    lumpinfo = malloc(1);      
-
-    for ( ; *filenames ; filenames++)
-       W_AddFile (*filenames);
-
-    if (!numlumps)
-       I_Error ("W_InitFiles: no files found");
-    
-    // set up caching
-    size = numlumps * sizeof(*lumpcache);
-    lumpcache = malloc (size);
-    
-    if (!lumpcache)
-       I_Error ("Couldn't allocate lumpcache");
-
-    memset (lumpcache,0, size);
-}
+    lump_p = &lumpinfo[startlump];
 
+    filerover = fileinfo;
 
+    for (i=startlump; i<numlumps; ++i)
+    {
+               lump_p->wad_file = wad_file;
+               lump_p->position = LONG(filerover->filepos);
+               lump_p->size = LONG(filerover->size);
+                       lump_p->cache = NULL;
+               strncpy(lump_p->name, filerover->name, 8);
+
+                       ++lump_p;
+                       ++filerover;
+    }
 
+    Z_Free(fileinfo);
 
-//
-// W_InitFile
-// Just initialize from a single file.
-//
-void W_InitFile (char* filename)
-{
-    char*      names[2];
+    if (lumphash != NULL)
+    {
+        Z_Free(lumphash);
+        lumphash = NULL;
+    }
 
-    names[0] = filename;
-    names[1] = NULL;
-    W_InitMultipleFiles (names);
+    return wad_file;
 }
 
 
@@ -358,42 +255,44 @@ int W_NumLumps (void)
 
 int W_CheckNumForName (char* name)
 {
-    union {
-       char    s[9];
-       int     x[2];
-       
-    } name8;
-    
-    int                v1;
-    int                v2;
-    lumpinfo_t*        lump_p;
-
-    // make the name into two integers for easy compares
-    strncpy (name8.s,name,8);
-
-    // in case the name was a fill 8 chars
-    name8.s[8] = 0;
-
-    // case insensitive
-    d_strupr (name8.s);
+    lumpinfo_t *lump_p;
+    int i;
 
-    v1 = name8.x[0];
-    v2 = name8.x[1];
+    // Do we have a hash table yet?
 
-
-    // scan backwards so patch lump files take precedence
-    lump_p = lumpinfo + numlumps;
-
-    while (lump_p-- != lumpinfo)
+    if (lumphash != NULL)
     {
-       if ( *(int *)lump_p->name == v1
-            && *(int *)&lump_p->name[4] == v2)
-       {
-           return lump_p - lumpinfo;
-       }
+        int hash;
+        
+        // We do! Excellent.
+
+        hash = W_LumpNameHash(name) % numlumps;
+        
+        for (lump_p = lumphash[hash]; lump_p != NULL; lump_p = lump_p->next)
+        {
+            if (!strncasecmp(lump_p->name, name, 8))
+            {
+                return lump_p - lumpinfo;
+            }
+        }
+    } 
+    else
+    {
+        // We don't have a hash table generate yet. Linear search :-(
+        // 
+        // scan backwards so patch lump files take precedence
+
+        for (i=numlumps-1; i >= 0; --i)
+        {
+            if (!strncasecmp(lumpinfo[i].name, name, 8))
+            {
+                return i;
+            }
+        }
     }
 
     // TFB. Not found.
+
     return -1;
 }
 
@@ -409,10 +308,12 @@ int W_GetNumForName (char* name)
     int        i;
 
     i = W_CheckNumForName (name);
-    
-    if (i == -1)
-      I_Error ("W_GetNumForName: %s not found!", name);
-      
+
+    if (i < 0)
+    {
+        I_Error ("W_GetNumForName: %s not found!", name);
+    }
     return i;
 }
 
@@ -421,10 +322,12 @@ int W_GetNumForName (char* name)
 // W_LumpLength
 // Returns the buffer size needed to load the given lump.
 //
-int W_LumpLength (int lump)
+int W_LumpLength (unsigned int lump)
 {
     if (lump >= numlumps)
-       I_Error ("W_LumpLength: %i >= numlumps",lump);
+    {
+       I_Error ("W_LumpLength: %i >= numlumps", lump);
+    }
 
     return lumpinfo[lump].size;
 }
@@ -436,42 +339,29 @@ int W_LumpLength (int lump)
 // Loads the lump into the given buffer,
 //  which must be >= W_LumpLength().
 //
-void
-W_ReadLump
-( int          lump,
-  void*                dest )
+void W_ReadLump(unsigned int lump, void *dest)
 {
-    int                c;
-    lumpinfo_t*        l;
-    int                handle;
+    int c;
+    lumpinfo_t *l;
        
     if (lump >= numlumps)
-       I_Error ("W_ReadLump: %i >= numlumps",lump);
+    {
+       I_Error ("W_ReadLump: %i >= numlumps", lump);
+    }
 
     l = lumpinfo+lump;
        
-    // ??? I_BeginRead ();
+    I_BeginRead ();
        
-    if (l->handle == -1)
-    {
-       // reloadable file, so use open / read / close
-       if ( (handle = open (reloadname,O_RDONLY | O_BINARY)) == -1)
-           I_Error ("W_ReadLump: couldn't open %s",reloadname);
-    }
-    else
-       handle = l->handle;
-               
-    lseek (handle, l->position, SEEK_SET);
-    c = read (handle, dest, l->size);
+    c = W_Read(l->wad_file, l->position, dest, l->size);
 
     if (c < l->size)
+    {
        I_Error ("W_ReadLump: only read %i of %i on lump %i",
-                c,l->size,lump);       
+                c, l->size, lump);     
+    }
 
-    if (l->handle == -1)
-       close (handle);
-               
-    // ??? I_EndRead ();
+    I_EndRead ();
 }
 
 
@@ -480,31 +370,55 @@ W_ReadLump
 //
 // W_CacheLumpNum
 //
-void*
-W_CacheLumpNum
-( int          lump,
-  int          tag )
+// Load a lump into memory and return a pointer to a buffer containing
+// the lump data.
+//
+// 'tag' is the type of zone memory buffer to allocate for the lump
+// (usually PU_STATIC or PU_CACHE).  If the lump is loaded as 
+// PU_STATIC, it should be released back using W_ReleaseLumpNum
+// when no longer needed (do not use Z_ChangeTag).
+//
+
+void *W_CacheLumpNum(int lumpnum, int tag)
 {
-    byte*      ptr;
+    byte *result;
+    lumpinfo_t *lump;
 
-    if ((unsigned)lump >= numlumps)
-       I_Error ("W_CacheLumpNum: %i >= numlumps",lump);
-               
-    if (!lumpcache[lump])
+    if ((unsigned)lumpnum >= numlumps)
     {
-       // read the lump in
-       
-       //printf ("cache miss on lump %i\n",lump);
-       ptr = Z_Malloc (W_LumpLength (lump), tag, &lumpcache[lump]);
-       W_ReadLump (lump, lumpcache[lump]);
+       I_Error ("W_CacheLumpNum: %i >= numlumps", lumpnum);
+    }
+
+    lump = &lumpinfo[lumpnum];
+
+    // Get the pointer to return.  If the lump is in a memory-mapped
+    // file, we can just return a pointer to within the memory-mapped
+    // region.  If the lump is in an ordinary file, we may already
+    // have it cached; otherwise, load it into memory.
+
+    if (lump->wad_file->mapped != NULL)
+    {
+        // Memory mapped file, return from the mmapped region.
+
+        result = lump->wad_file->mapped + lump->position;
+    }
+    else if (lump->cache != NULL)
+    {
+        // Already cached, so just switch the zone tag.
+
+        result = lump->cache;
+        Z_ChangeTag(lump->cache, tag);
     }
     else
     {
-       //printf ("cache hit on lump %i\n",lump);
-       Z_ChangeTag (lumpcache[lump],tag);
+        // Not yet loaded, so load it now
+
+        lump->cache = Z_Malloc(W_LumpLength(lumpnum), tag, &lump->cache);
+       W_ReadLump (lumpnum, lump->cache);
+        result = lump->cache;
     }
        
-    return lumpcache[lump];
+    return result;
 }
 
 
@@ -512,14 +426,48 @@ W_CacheLumpNum
 //
 // W_CacheLumpName
 //
-void*
-W_CacheLumpName
-( char*                name,
-  int          tag )
+void *W_CacheLumpName(char *name, int tag)
 {
-    return W_CacheLumpNum (W_GetNumForName(name), tag);
+    return W_CacheLumpNum(W_GetNumForName(name), tag);
 }
 
+// 
+// Release a lump back to the cache, so that it can be reused later 
+// without having to read from disk again, or alternatively, discarded
+// if we run out of memory.
+//
+// Back in Vanilla Doom, this was just done using Z_ChangeTag 
+// directly, but now that we have WAD mmap, things are a bit more
+// complicated ...
+//
+
+void W_ReleaseLumpNum(int lumpnum)
+{
+    lumpinfo_t *lump;
+
+    if ((unsigned)lumpnum >= numlumps)
+    {
+       I_Error ("W_ReleaseLumpNum: %i >= numlumps", lumpnum);
+    }
+
+    lump = &lumpinfo[lumpnum];
+
+    if (lump->wad_file->mapped != NULL)
+    {
+        // Memory-mapped file, so nothing needs to be done here.
+    }
+    else
+    {
+        Z_ChangeTag(lump->cache, PU_CACHE);
+    }
+}
+
+void W_ReleaseLumpName(char *name)
+{
+    W_ReleaseLumpNum(W_GetNumForName(name));
+}
+
+#if 0
 
 //
 // W_Profile
@@ -540,7 +488,7 @@ void W_Profile (void)
        
     for (i=0 ; i<numlumps ; i++)
     {  
-       ptr = lumpcache[i];
+       ptr = lumpinfo[i].cache;
        if (!ptr)
        {
            ch = ' ';
@@ -557,7 +505,7 @@ void W_Profile (void)
        info[i][profilecount] = ch;
     }
     profilecount++;
-       
+#if ORIGCODE
     f = fopen ("waddump.txt","w");
     name[8] = 0;
 
@@ -580,6 +528,85 @@ void W_Profile (void)
        fprintf (f,"\n");
     }
     fclose (f);
+#endif
 }
 
 
+#endif
+
+// Generate a hash table for fast lookups
+
+void W_GenerateHashTable(void)
+{
+    unsigned int i;
+
+    // Free the old hash table, if there is one
+
+    if (lumphash != NULL)
+    {
+        Z_Free(lumphash);
+    }
+
+    // Generate hash table
+    if (numlumps > 0)
+    {
+        lumphash = Z_Malloc(sizeof(lumpinfo_t *) * numlumps, PU_STATIC, NULL);
+        memset(lumphash, 0, sizeof(lumpinfo_t *) * numlumps);
+
+        for (i=0; i<numlumps; ++i)
+        {
+            unsigned int hash;
+
+            hash = W_LumpNameHash(lumpinfo[i].name) % numlumps;
+
+            // Hook into the hash table
+
+            lumpinfo[i].next = lumphash[hash];
+            lumphash[hash] = &lumpinfo[i];
+        }
+    }
+
+    // All done!
+}
+
+// Lump names that are unique to particular game types. This lets us check
+// the user is not trying to play with the wrong executable, eg.
+// chocolate-doom -iwad hexen.wad.
+static const struct
+{
+    GameMission_t mission;
+    char *lumpname;
+} unique_lumps[] = {
+    { doom,    "POSSA1" },
+    { heretic, "IMPXA1" },
+    { hexen,   "ETTNA1" },
+    { strife,  "AGRDA1" },
+};
+
+void W_CheckCorrectIWAD(GameMission_t mission)
+{
+    int i;
+    int lumpnum;
+
+    for (i = 0; i < arrlen(unique_lumps); ++i)
+    {
+        if (mission != unique_lumps[i].mission)
+        {
+            lumpnum = W_CheckNumForName(unique_lumps[i].lumpname);
+
+            if (lumpnum >= 0)
+            {
+                I_Error("\nYou are trying to use a %s IWAD file with "
+                        "the %s%s binary.\nThis isn't going to work.\n"
+                        "You probably want to use the %s%s binary.",
+                        D_SuggestGameName(unique_lumps[i].mission,
+                                          indetermined),
+                        PROGRAM_PREFIX,
+                        D_GameMissionString(mission),
+                        PROGRAM_PREFIX,
+                        D_GameMissionString(unique_lumps[i].mission));
+            }
+        }
+    }
+}
+
index db1faaa6a15256fc01ab16a9006bf0b170a5fe24..718957499086d5552ebab5e8f51ced9d39c5231a 100644 (file)
@@ -1,89 +1,78 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     WAD I/O functions.
 //
-//-----------------------------------------------------------------------------
 
 
 #ifndef __W_WAD__
 #define __W_WAD__
 
+#include <stdio.h>
 
-#ifdef __GNUG__
-#pragma interface
-#endif
+#include "doomtype.h"
+#include "d_mode.h"
+
+#include "w_file.h"
 
 
 //
 // TYPES
 //
-typedef struct
-{
-    // Should be "IWAD" or "PWAD".
-    char               identification[4];              
-    int                        numlumps;
-    int                        infotableofs;
-    
-} wadinfo_t;
-
-
-typedef struct
-{
-    int                        filepos;
-    int                        size;
-    char               name[8];
-    
-} filelump_t;
 
 //
 // WADFILE I/O related stuff.
 //
-typedef struct
+
+typedef struct lumpinfo_s lumpinfo_t;
+
+struct lumpinfo_s
 {
     char       name[8];
-    int                handle;
+    wad_file_t *wad_file;
     int                position;
     int                size;
-} lumpinfo_t;
+    void       *cache;
+
+    // Used for hash table lookups
+
+    lumpinfo_t *next;
+};
 
 
-extern void**          lumpcache;
-extern lumpinfo_t*     lumpinfo;
-extern int             numlumps;
+extern lumpinfo_t *lumpinfo;
+extern unsigned int numlumps;
 
-void    W_InitMultipleFiles (char** filenames);
-void    W_Reload (void);
+wad_file_t *W_AddFile (char *filename);
 
 int    W_CheckNumForName (char* name);
 int    W_GetNumForName (char* name);
 
-int    W_LumpLength (int lump);
-void    W_ReadLump (int lump, void *dest);
+int    W_LumpLength (unsigned int lump);
+void    W_ReadLump (unsigned int lump, void *dest);
 
 void*  W_CacheLumpNum (int lump, int tag);
 void*  W_CacheLumpName (char* name, int tag);
 
+void    W_GenerateHashTable(void);
 
+extern unsigned int W_LumpNameHash(const char *s);
 
+void    W_ReleaseLumpNum(int lump);
+void    W_ReleaseLumpName(char *name);
+
+void W_CheckCorrectIWAD(GameMission_t mission);
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 98be302a1c98c06fd711c6a9b0dd8b48bb5af9b5..ddb9a66c1d23ab480cec0f8f36fa512eb17d3740 100644 (file)
@@ -1,36 +1,31 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Intermission screens.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: wi_stuff.c,v 1.7 1997/02/03 22:45:13 b1 Exp $";
 
 #include <stdio.h>
 
 #include "z_zone.h"
 
+#include "m_misc.h"
 #include "m_random.h"
-#include "m_swap.h"
 
+#include "deh_main.h"
+#include "i_swap.h"
 #include "i_system.h"
 
 #include "w_wad.h"
@@ -223,48 +218,54 @@ static point_t lnodes[NUMEPISODES][NUMMAPS] =
 // Using patches saves a lot of space,
 //  as they replace 320x200 full screen frames.
 //
+
+#define ANIM(type, period, nanims, x, y, nexttic)            \
+   { (type), (period), (nanims), { (x), (y) }, (nexttic),    \
+     0, { NULL, NULL, NULL }, 0, 0, 0, 0 }
+
+
 static anim_t epsd0animinfo[] =
 {
-    { ANIM_ALWAYS, TICRATE/3, 3, { 224, 104 } },
-    { ANIM_ALWAYS, TICRATE/3, 3, { 184, 160 } },
-    { ANIM_ALWAYS, TICRATE/3, 3, { 112, 136 } },
-    { ANIM_ALWAYS, TICRATE/3, 3, { 72, 112 } },
-    { ANIM_ALWAYS, TICRATE/3, 3, { 88, 96 } },
-    { ANIM_ALWAYS, TICRATE/3, 3, { 64, 48 } },
-    { ANIM_ALWAYS, TICRATE/3, 3, { 192, 40 } },
-    { ANIM_ALWAYS, TICRATE/3, 3, { 136, 16 } },
-    { ANIM_ALWAYS, TICRATE/3, 3, { 80, 16 } },
-    { ANIM_ALWAYS, TICRATE/3, 3, { 64, 24 } }
+    ANIM(ANIM_ALWAYS, TICRATE/3, 3, 224, 104, 0),
+    ANIM(ANIM_ALWAYS, TICRATE/3, 3, 184, 160, 0),
+    ANIM(ANIM_ALWAYS, TICRATE/3, 3, 112, 136, 0),
+    ANIM(ANIM_ALWAYS, TICRATE/3, 3, 72, 112, 0),
+    ANIM(ANIM_ALWAYS, TICRATE/3, 3, 88, 96, 0),
+    ANIM(ANIM_ALWAYS, TICRATE/3, 3, 64, 48, 0),
+    ANIM(ANIM_ALWAYS, TICRATE/3, 3, 192, 40, 0),
+    ANIM(ANIM_ALWAYS, TICRATE/3, 3, 136, 16, 0),
+    ANIM(ANIM_ALWAYS, TICRATE/3, 3, 80, 16, 0),
+    ANIM(ANIM_ALWAYS, TICRATE/3, 3, 64, 24, 0),
 };
 
 static anim_t epsd1animinfo[] =
 {
-    { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 1 },
-    { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 2 },
-    { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 3 },
-    { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 4 },
-    { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 5 },
-    { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 6 },
-    { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 7 },
-    { ANIM_LEVEL, TICRATE/3, 3, { 192, 144 }, 8 },
-    { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 8 }
+    ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 1),
+    ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 2),
+    ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 3),
+    ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 4),
+    ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 5),
+    ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 6),
+    ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 7),
+    ANIM(ANIM_LEVEL, TICRATE/3, 3, 192, 144, 8),
+    ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 8),
 };
 
 static anim_t epsd2animinfo[] =
 {
-    { ANIM_ALWAYS, TICRATE/3, 3, { 104, 168 } },
-    { ANIM_ALWAYS, TICRATE/3, 3, { 40, 136 } },
-    { ANIM_ALWAYS, TICRATE/3, 3, { 160, 96 } },
-    { ANIM_ALWAYS, TICRATE/3, 3, { 104, 80 } },
-    { ANIM_ALWAYS, TICRATE/3, 3, { 120, 32 } },
-    { ANIM_ALWAYS, TICRATE/4, 3, { 40, 0 } }
+    ANIM(ANIM_ALWAYS, TICRATE/3, 3, 104, 168, 0),
+    ANIM(ANIM_ALWAYS, TICRATE/3, 3, 40, 136, 0),
+    ANIM(ANIM_ALWAYS, TICRATE/3, 3, 160, 96, 0),
+    ANIM(ANIM_ALWAYS, TICRATE/3, 3, 104, 80, 0),
+    ANIM(ANIM_ALWAYS, TICRATE/3, 3, 120, 32, 0),
+    ANIM(ANIM_ALWAYS, TICRATE/4, 3, 40, 0, 0),
 };
 
 static int NUMANIMS[NUMEPISODES] =
 {
-    sizeof(epsd0animinfo)/sizeof(anim_t),
-    sizeof(epsd1animinfo)/sizeof(anim_t),
-    sizeof(epsd2animinfo)/sizeof(anim_t)
+    arrlen(epsd0animinfo),
+    arrlen(epsd1animinfo),
+    arrlen(epsd2animinfo),
 };
 
 static anim_t *anims[NUMEPISODES] =
@@ -282,8 +283,6 @@ static anim_t *anims[NUMEPISODES] =
 //
 // Locally used stuff.
 //
-#define FB 0
-
 
 // States for single-player
 #define SP_KILLS               0
@@ -338,14 +337,11 @@ static int                NUMCMAPS;
 //     GRAPHICS
 //
 
-// background (map of levels).
-static patch_t*                bg;
-
 // You Are Here graphic
-static patch_t*                yah[2]
+static patch_t*                yah[3] = { NULL, NULL, NULL }
 
 // splat
-static patch_t*                splat;
+static patch_t*                splat[2] = { NULL, NULL };
 
 // %, : graphics
 static patch_t*                percent;
@@ -373,7 +369,7 @@ static patch_t*             items;
 static patch_t*                frags;
 
 // Time sucks.
-static patch_t*                time;
+static patch_t*                timepatch;
 static patch_t*                par;
 static patch_t*                sucks;
 
@@ -395,18 +391,17 @@ static patch_t*           bp[MAXPLAYERS];
  // Name graphics of each level (centered)
 static patch_t**       lnames;
 
+// Buffer storing the backdrop
+static patch_t *background;
+
 //
 // CODE
 //
 
 // slam background
-// UNUSED static unsigned char *background=0;
-
-
 void WI_slamBackground(void)
 {
-    memcpy(screens[0], screens[1], SCREENWIDTH * SCREENHEIGHT);
-    V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
+    V_DrawPatch(0, 0, background);
 }
 
 // The ticker is used to detect keys
@@ -422,15 +417,33 @@ void WI_drawLF(void)
 {
     int y = WI_TITLEY;
 
-    // draw <LevelName> 
-    V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->last]->width))/2,
-               y, FB, lnames[wbs->last]);
+    if (gamemode != commercial || wbs->last < NUMCMAPS)
+    {
+        // draw <LevelName> 
+        V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->last]->width))/2,
+                    y, lnames[wbs->last]);
 
-    // draw "Finished!"
-    y += (5*SHORT(lnames[wbs->last]->height))/4;
-    
-    V_DrawPatch((SCREENWIDTH - SHORT(finished->width))/2,
-               y, FB, finished);
+        // draw "Finished!"
+        y += (5*SHORT(lnames[wbs->last]->height))/4;
+
+        V_DrawPatch((SCREENWIDTH - SHORT(finished->width)) / 2, y, finished);
+    }
+    else if (wbs->last == NUMCMAPS)
+    {
+        // MAP33 - nothing is displayed!
+    }
+    else if (wbs->last > NUMCMAPS)
+    {
+        // > MAP33.  Doom bombs out here with a Bad V_DrawPatch error.
+        // I'm pretty sure that doom2.exe is just reading into random
+        // bits of memory at this point, but let's try to be accurate
+        // anyway.  This deliberately triggers a V_DrawPatch error.
+
+        patch_t tmp = { SCREENWIDTH, SCREENHEIGHT, 1, 1, 
+                        { 0, 0, 0, 0, 0, 0, 0, 0 } };
+
+        V_DrawPatch(0, y, &tmp);
+    }
 }
 
 
@@ -442,13 +455,15 @@ void WI_drawEL(void)
 
     // draw "Entering"
     V_DrawPatch((SCREENWIDTH - SHORT(entering->width))/2,
-               y, FB, entering);
+               y,
+                entering);
 
     // draw level
     y += (5*SHORT(lnames[wbs->next]->height))/4;
 
     V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->next]->width))/2,
-               y, FB, lnames[wbs->next]);
+               y, 
+                lnames[wbs->next]);
 
 }
 
@@ -484,12 +499,13 @@ WI_drawOnLnode
        {
            i++;
        }
-    } while (!fits && i!=2);
+    } while (!fits && i!=2 && c[i] != NULL);
 
     if (fits && i<2)
     {
-       V_DrawPatch(lnodes[wbs->epsd][n].x, lnodes[wbs->epsd][n].y,
-                   FB, c[i]);
+       V_DrawPatch(lnodes[wbs->epsd][n].x,
+                    lnodes[wbs->epsd][n].y,
+                   c[i]);
     }
     else
     {
@@ -585,7 +601,7 @@ void WI_drawAnimatedBack(void)
     int                        i;
     anim_t*            a;
 
-    if (commercial)
+    if (gamemode == commercial)
        return;
 
     if (wbs->epsd > 2)
@@ -596,7 +612,7 @@ void WI_drawAnimatedBack(void)
        a = &anims[wbs->epsd][i];
 
        if (a->ctr >= 0)
-           V_DrawPatch(a->loc.x, a->loc.y, FB, a->p[a->ctr]);
+           V_DrawPatch(a->loc.x, a->loc.y, a->p[a->ctr]);
     }
 
 }
@@ -653,13 +669,13 @@ WI_drawNum
     while (digits--)
     {
        x -= fontwidth;
-       V_DrawPatch(x, y, FB, num[ n % 10 ]);
+       V_DrawPatch(x, y, num[ n % 10 ]);
        n /= 10;
     }
 
     // draw a minus sign if necessary
     if (neg)
-       V_DrawPatch(x-=8, y, FB, wiminus);
+       V_DrawPatch(x-=8, y, wiminus);
 
     return x;
 
@@ -674,7 +690,7 @@ WI_drawPercent
     if (p < 0)
        return;
 
-    V_DrawPatch(x, y, FB, percent);
+    V_DrawPatch(x, y, percent);
     WI_drawNum(x, y, p, -1);
 }
 
@@ -709,14 +725,14 @@ WI_drawTime
 
            // draw
            if (div==60 || t / div)
-               V_DrawPatch(x, y, FB, colon);
+               V_DrawPatch(x, y, colon);
            
        } while (t / div);
     }
     else
     {
        // "sucks"
-       V_DrawPatch(x - SHORT(sucks->width), y, FB, sucks); 
+       V_DrawPatch(x - SHORT(sucks->width), y, sucks); 
     }
 }
 
@@ -740,7 +756,11 @@ void WI_updateNoState(void) {
 
     if (!--cnt)
     {
-       WI_End();
+        // Don't call WI_End yet.  G_WorldDone doesnt immediately 
+        // change gamestate, so WI_Drawer is still going to get
+        // run until that happens.  If we do that after WI_End
+        // (which unloads all the graphics), we're in trouble.
+       //WI_End();
        G_WorldDone();
     }
 
@@ -791,11 +811,11 @@ void WI_drawShowNextLoc(void)
 
        // draw a splat on taken cities.
        for (i=0 ; i<=last ; i++)
-           WI_drawOnLnode(i, &splat);
+           WI_drawOnLnode(i, splat);
 
        // splat the secret level?
        if (wbs->didsecret)
-           WI_drawOnLnode(8, &splat);
+           WI_drawOnLnode(8, splat);
 
        // draw flashing ptr
        if (snl_pointeron)
@@ -986,10 +1006,6 @@ void WI_drawDeathmatchStats(void)
     int                x;
     int                y;
     int                w;
-    
-    //int              lh;     // line height
-
-    //lh = WI_SPACINGY;
 
     WI_slamBackground();
     
@@ -1000,11 +1016,10 @@ void WI_drawDeathmatchStats(void)
     // draw stat titles (top line)
     V_DrawPatch(DM_TOTALSX-SHORT(total->width)/2,
                DM_MATRIXY-WI_SPACINGY+10,
-               FB,
                total);
     
-    V_DrawPatch(DM_KILLERSX, DM_KILLERSY, FB, killers);
-    V_DrawPatch(DM_VICTIMSX, DM_VICTIMSY, FB, victims);
+    V_DrawPatch(DM_KILLERSX, DM_KILLERSY, killers);
+    V_DrawPatch(DM_VICTIMSX, DM_VICTIMSY, victims);
 
     // draw P?
     x = DM_MATRIXX + DM_SPACINGX;
@@ -1016,33 +1031,29 @@ void WI_drawDeathmatchStats(void)
        {
            V_DrawPatch(x-SHORT(p[i]->width)/2,
                        DM_MATRIXY - WI_SPACINGY,
-                       FB,
                        p[i]);
            
            V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2,
                        y,
-                       FB,
                        p[i]);
 
            if (i == me)
            {
                V_DrawPatch(x-SHORT(p[i]->width)/2,
                            DM_MATRIXY - WI_SPACINGY,
-                           FB,
                            bstar);
 
                V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2,
                            y,
-                           FB,
                            star);
            }
        }
        else
        {
            // V_DrawPatch(x-SHORT(bp[i]->width)/2,
-           //   DM_MATRIXY - WI_SPACINGY, FB, bp[i]);
+           //   DM_MATRIXY - WI_SPACINGY, bp[i]);
            // V_DrawPatch(DM_MATRIXX-SHORT(bp[i]->width)/2,
-           //   y, FB, bp[i]);
+           //   y, bp[i]);
        }
        x += DM_SPACINGX;
        y += WI_SPACINGY;
@@ -1274,17 +1285,17 @@ void WI_drawNetgameStats(void)
 
     // draw stat titles (top line)
     V_DrawPatch(NG_STATSX+NG_SPACINGX-SHORT(kills->width),
-               NG_STATSY, FB, kills);
+               NG_STATSY, kills);
 
     V_DrawPatch(NG_STATSX+2*NG_SPACINGX-SHORT(items->width),
-               NG_STATSY, FB, items);
+               NG_STATSY, items);
 
     V_DrawPatch(NG_STATSX+3*NG_SPACINGX-SHORT(secret->width),
-               NG_STATSY, FB, secret);
+               NG_STATSY, secret);
     
     if (dofrags)
        V_DrawPatch(NG_STATSX+4*NG_SPACINGX-SHORT(frags->width),
-                   NG_STATSY, FB, frags);
+                   NG_STATSY, frags);
 
     // draw stats
     y = NG_STATSY + SHORT(kills->height);
@@ -1295,10 +1306,10 @@ void WI_drawNetgameStats(void)
            continue;
 
        x = NG_STATSX;
-       V_DrawPatch(x-SHORT(p[i]->width), y, FB, p[i]);
+       V_DrawPatch(x-SHORT(p[i]->width), y, p[i]);
 
        if (i == me)
-           V_DrawPatch(x-SHORT(p[i]->width), y, FB, star);
+           V_DrawPatch(x-SHORT(p[i]->width), y, star);
 
        x += NG_SPACINGX;
        WI_drawPercent(x-pwidth, y+10, cnt_kills[i]);   x += NG_SPACINGX;
@@ -1447,21 +1458,21 @@ void WI_drawStats(void)
     
     WI_drawLF();
 
-    V_DrawPatch(SP_STATSX, SP_STATSY, FB, kills);
+    V_DrawPatch(SP_STATSX, SP_STATSY, kills);
     WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY, cnt_kills[0]);
 
-    V_DrawPatch(SP_STATSX, SP_STATSY+lh, FB, items);
+    V_DrawPatch(SP_STATSX, SP_STATSY+lh, items);
     WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+lh, cnt_items[0]);
 
-    V_DrawPatch(SP_STATSX, SP_STATSY+2*lh, FB, sp_secret);
+    V_DrawPatch(SP_STATSX, SP_STATSY+2*lh, sp_secret);
     WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]);
 
-    V_DrawPatch(SP_TIMEX, SP_TIMEY, FB, time);
+    V_DrawPatch(SP_TIMEX, SP_TIMEY, timepatch);
     WI_drawTime(SCREENWIDTH/2 - SP_TIMEX, SP_TIMEY, cnt_time);
 
     if (wbs->epsd < 3)
     {
-       V_DrawPatch(SCREENWIDTH/2 + SP_TIMEX, SP_TIMEY, FB, par);
+       V_DrawPatch(SCREENWIDTH/2 + SP_TIMEX, SP_TIMEY, par);
        WI_drawTime(SCREENWIDTH - SP_TIMEX, SP_TIMEY, cnt_par);
     }
 
@@ -1535,70 +1546,42 @@ void WI_Ticker(void)
 
 }
 
-void WI_loadData(void)
-{
-    int                i;
-    int                j;
-    char       name[9];
-    anim_t*    a;
-
-    if (gamemode == commercial)
-       strcpy(name, "INTERPIC");
-    else 
-       sprintf(name, "WIMAP%d", wbs->epsd);
-    
-    if ( gamemode == retail )
-    {
-      if (wbs->epsd == 3)
-       strcpy(name,"INTERPIC");
-    }
+typedef void (*load_callback_t)(char *lumpname, patch_t **variable);
 
-    // background
-    bg = W_CacheLumpName(name, PU_CACHE);    
-    V_DrawPatch(0, 0, 1, bg);
+// Common load/unload function.  Iterates over all the graphics
+// lumps to be loaded/unloaded into memory.
 
-
-    // UNUSED unsigned char *pic = screens[1];
-    // if (gamemode == commercial)
-    // {
-    // darken the background image
-    // while (pic != screens[1] + SCREENHEIGHT*SCREENWIDTH)
-    // {
-    //   *pic = colormaps[256*25 + *pic];
-    //   pic++;
-    // }
-    //}
+static void WI_loadUnloadData(load_callback_t callback)
+{
+    int i, j;
+    char name[9];
+    anim_t *a;
 
     if (gamemode == commercial)
     {
-       NUMCMAPS = 32;                                                          
-       lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMCMAPS,
-                                      PU_STATIC, 0);
        for (i=0 ; i<NUMCMAPS ; i++)
-       {                                                               
-           sprintf(name, "CWILV%2.2d", i);
-           lnames[i] = W_CacheLumpName(name, PU_STATIC);
-       }                                       
+       {
+           DEH_snprintf(name, 9, "CWILV%2.2d", i);
+            callback(name, &lnames[i]);
+       }
     }
     else
     {
-       lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMMAPS,
-                                      PU_STATIC, 0);
        for (i=0 ; i<NUMMAPS ; i++)
        {
-           sprintf(name, "WILV%d%d", wbs->epsd, i);
-           lnames[i] = W_CacheLumpName(name, PU_STATIC);
+           DEH_snprintf(name, 9, "WILV%d%d", wbs->epsd, i);
+            callback(name, &lnames[i]);
        }
 
        // you are here
-       yah[0] = W_CacheLumpName("WIURH0", PU_STATIC);
+        callback(DEH_String("WIURH0"), &yah[0]);
 
        // you are here (alt.)
-       yah[1] = W_CacheLumpName("WIURH1", PU_STATIC);
+        callback(DEH_String("WIURH1"), &yah[1]);
 
        // splat
-       splat = W_CacheLumpName("WISPLAT", PU_STATIC); 
-       
+        callback(DEH_String("WISPLAT"), &splat[0]);
+
        if (wbs->epsd < 3)
        {
            for (j=0;j<NUMANIMS[wbs->epsd];j++)
@@ -1607,16 +1590,16 @@ void WI_loadData(void)
                for (i=0;i<a->nanims;i++)
                {
                    // MONDO HACK!
-                   if (wbs->epsd != 1 || j != 8) 
+                   if (wbs->epsd != 1 || j != 8)
                    {
                        // animations
-                       sprintf(name, "WIA%d%.2d%.2d", wbs->epsd, j, i);  
-                       a->p[i] = W_CacheLumpName(name, PU_STATIC);
+                       DEH_snprintf(name, 9, "WIA%d%.2d%.2d", wbs->epsd, j, i);
+                        callback(name, &a->p[i]);
                    }
                    else
                    {
                        // HACK ALERT!
-                       a->p[i] = anims[1][4].p[i]; 
+                       a->p[i] = anims[1][4].p[i];
                    }
                }
            }
@@ -1624,149 +1607,146 @@ void WI_loadData(void)
     }
 
     // More hacks on minus sign.
-    wiminus = W_CacheLumpName("WIMINUS", PU_STATIC); 
+    callback(DEH_String("WIMINUS"), &wiminus);
 
     for (i=0;i<10;i++)
     {
         // numbers 0-9
-       sprintf(name, "WINUM%d", i);     
-       num[i] = W_CacheLumpName(name, PU_STATIC);
+       DEH_snprintf(name, 9, "WINUM%d", i);
+        callback(name, &num[i]);
     }
 
     // percent sign
-    percent = W_CacheLumpName("WIPCNT", PU_STATIC);
+    callback(DEH_String("WIPCNT"), &percent);
 
     // "finished"
-    finished = W_CacheLumpName("WIF", PU_STATIC);
+    callback(DEH_String("WIF"), &finished);
 
     // "entering"
-    entering = W_CacheLumpName("WIENTER", PU_STATIC);
+    callback(DEH_String("WIENTER"), &entering);
 
     // "kills"
-    kills = W_CacheLumpName("WIOSTK", PU_STATIC);   
+    callback(DEH_String("WIOSTK"), &kills);
 
     // "scrt"
-    secret = W_CacheLumpName("WIOSTS", PU_STATIC);
+    callback(DEH_String("WIOSTS"), &secret);
 
      // "secret"
-    sp_secret = W_CacheLumpName("WISCRT2", PU_STATIC);
+    callback(DEH_String("WISCRT2"), &sp_secret);
 
-    // Yuck. 
-    if (french)
+    // french wad uses WIOBJ (?)
+    if (W_CheckNumForName(DEH_String("WIOBJ")) >= 0)
     {
-       // "items"
-       if (netgame && !deathmatch)
-           items = W_CacheLumpName("WIOBJ", PU_STATIC);    
-       else
-           items = W_CacheLumpName("WIOSTI", PU_STATIC);
-    } else
-       items = W_CacheLumpName("WIOSTI", PU_STATIC);
+       // "items"
+       if (netgame && !deathmatch)
+            callback(DEH_String("WIOBJ"), &items);
+       else
+            callback(DEH_String("WIOSTI"), &items);
+    } else {
+        callback(DEH_String("WIOSTI"), &items);
+    }
 
     // "frgs"
-    frags = W_CacheLumpName("WIFRGS", PU_STATIC);    
+    callback(DEH_String("WIFRGS"), &frags);
 
     // ":"
-    colon = W_CacheLumpName("WICOLON", PU_STATIC); 
+    callback(DEH_String("WICOLON"), &colon);
 
     // "time"
-    time = W_CacheLumpName("WITIME", PU_STATIC);   
+    callback(DEH_String("WITIME"), &timepatch);
 
     // "sucks"
-    sucks = W_CacheLumpName("WISUCKS", PU_STATIC);  
+    callback(DEH_String("WISUCKS"), &sucks);
 
     // "par"
-    par = W_CacheLumpName("WIPAR", PU_STATIC);   
+    callback(DEH_String("WIPAR"), &par);
 
     // "killers" (vertical)
-    killers = W_CacheLumpName("WIKILRS", PU_STATIC);
+    callback(DEH_String("WIKILRS"), &killers);
 
     // "victims" (horiz)
-    victims = W_CacheLumpName("WIVCTMS", PU_STATIC);
+    callback(DEH_String("WIVCTMS"), &victims);
 
     // "total"
-    total = W_CacheLumpName("WIMSTT", PU_STATIC);   
-
-    // your face
-    star = W_CacheLumpName("STFST01", PU_STATIC);
-
-    // dead face
-    bstar = W_CacheLumpName("STFDEAD0", PU_STATIC);    
+    callback(DEH_String("WIMSTT"), &total);
 
     for (i=0 ; i<MAXPLAYERS ; i++)
     {
        // "1,2,3,4"
-       sprintf(name, "STPB%d", i);      
-       p[i] = W_CacheLumpName(name, PU_STATIC);
+       DEH_snprintf(name, 9, "STPB%d", i);
+        callback(name, &p[i]);
 
        // "1,2,3,4"
-       sprintf(name, "WIBP%d", i+1);     
-       bp[i] = W_CacheLumpName(name, PU_STATIC);
+       DEH_snprintf(name, 9, "WIBP%d", i+1);
+        callback(name, &bp[i]);
     }
 
+    // Background image
+
+    if (gamemode == commercial)
+    {
+        M_StringCopy(name, DEH_String("INTERPIC"), sizeof(name));
+    }
+    else if (gamemode == retail && wbs->epsd == 3)
+    {
+        M_StringCopy(name, DEH_String("INTERPIC"), sizeof(name));
+    }
+    else
+    {
+       DEH_snprintf(name, sizeof(name), "WIMAP%d", wbs->epsd);
+    }
+
+    // Draw backdrop and save to a temporary buffer
+
+    callback(name, &background);
 }
 
-void WI_unloadData(void)
+static void WI_loadCallback(char *name, patch_t **variable)
 {
-    int                i;
-    int                j;
-
-    Z_ChangeTag(wiminus, PU_CACHE);
+    *variable = W_CacheLumpName(name, PU_STATIC);
+}
 
-    for (i=0 ; i<10 ; i++)
-       Z_ChangeTag(num[i], PU_CACHE);
-    
+void WI_loadData(void)
+{
     if (gamemode == commercial)
     {
-       for (i=0 ; i<NUMCMAPS ; i++)
-           Z_ChangeTag(lnames[i], PU_CACHE);
+       NUMCMAPS = 32;
+       lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMCMAPS,
+                                      PU_STATIC, NULL);
     }
     else
     {
-       Z_ChangeTag(yah[0], PU_CACHE);
-       Z_ChangeTag(yah[1], PU_CACHE);
+       lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMMAPS,
+                                      PU_STATIC, NULL);
+    }
 
-       Z_ChangeTag(splat, PU_CACHE);
+    WI_loadUnloadData(WI_loadCallback);
 
-       for (i=0 ; i<NUMMAPS ; i++)
-           Z_ChangeTag(lnames[i], PU_CACHE);
-       
-       if (wbs->epsd < 3)
-       {
-           for (j=0;j<NUMANIMS[wbs->epsd];j++)
-           {
-               if (wbs->epsd != 1 || j != 8)
-                   for (i=0;i<anims[wbs->epsd][j].nanims;i++)
-                       Z_ChangeTag(anims[wbs->epsd][j].p[i], PU_CACHE);
-           }
-       }
-    }
-    
-    Z_Free(lnames);
-
-    Z_ChangeTag(percent, PU_CACHE);
-    Z_ChangeTag(colon, PU_CACHE);
-    Z_ChangeTag(finished, PU_CACHE);
-    Z_ChangeTag(entering, PU_CACHE);
-    Z_ChangeTag(kills, PU_CACHE);
-    Z_ChangeTag(secret, PU_CACHE);
-    Z_ChangeTag(sp_secret, PU_CACHE);
-    Z_ChangeTag(items, PU_CACHE);
-    Z_ChangeTag(frags, PU_CACHE);
-    Z_ChangeTag(time, PU_CACHE);
-    Z_ChangeTag(sucks, PU_CACHE);
-    Z_ChangeTag(par, PU_CACHE);
-
-    Z_ChangeTag(victims, PU_CACHE);
-    Z_ChangeTag(killers, PU_CACHE);
-    Z_ChangeTag(total, PU_CACHE);
-    //  Z_ChangeTag(star, PU_CACHE);
-    //  Z_ChangeTag(bstar, PU_CACHE);
-    
-    for (i=0 ; i<MAXPLAYERS ; i++)
-       Z_ChangeTag(p[i], PU_CACHE);
+    // These two graphics are special cased because we're sharing
+    // them with the status bar code
 
-    for (i=0 ; i<MAXPLAYERS ; i++)
-       Z_ChangeTag(bp[i], PU_CACHE);
+    // your face
+    star = W_CacheLumpName(DEH_String("STFST01"), PU_STATIC);
+
+    // dead face
+    bstar = W_CacheLumpName(DEH_String("STFDEAD0"), PU_STATIC);
+}
+
+static void WI_unloadCallback(char *name, patch_t **variable)
+{
+    W_ReleaseLumpName(name);
+    *variable = NULL;
+}
+
+void WI_unloadData(void)
+{
+    WI_loadUnloadData(WI_unloadCallback);
+
+    // We do not free these lumps as they are shared with the status
+    // bar code.
+   
+    // W_ReleaseLumpName("STFST01");
+    // W_ReleaseLumpName("STFDEAD0");
 }
 
 void WI_Drawer (void)
@@ -1837,7 +1817,6 @@ void WI_initVariables(wbstartstruct_t* wbstartstruct)
 
 void WI_Start(wbstartstruct_t* wbstartstruct)
 {
-
     WI_initVariables(wbstartstruct);
     WI_loadData();
 
index db9d5370cc5f0e0a475db739e81b865e6af2fa11..296571f73a82995c1e40039ac2e70b11c151e8ef 100644 (file)
@@ -1,23 +1,20 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //  Intermission.
 //
-//-----------------------------------------------------------------------------
 
 #ifndef __WI_STUFF__
 #define __WI_STUFF__
@@ -32,8 +29,7 @@ typedef enum
 {
     NoState = -1,
     StatCount,
-    ShowNextLoc
-
+    ShowNextLoc,
 } stateenum_t;
 
 // Called by main loop, animate the intermission.
@@ -46,9 +42,7 @@ void WI_Drawer (void);
 // Setup for an intermission screen.
 void WI_Start(wbstartstruct_t*  wbstartstruct);
 
+// Shut down the intermission screen
+void WI_End(void);
+
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
index 434548545f96cf56907b0f94443cd42cc50edfb0..16da22b90a9036efe27b785aac55dc13ad1ff30f 100644 (file)
@@ -1,32 +1,25 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //     Zone Memory Allocation. Neat.
 //
-//-----------------------------------------------------------------------------
 
-static const char
-rcsid[] = "$Id: z_zone.c,v 1.4 1997/02/03 16:47:58 b1 Exp $";
 
 #include "z_zone.h"
 #include "i_system.h"
-#include "doomdef.h"
+#include "doomtype.h"
 
 
 //
@@ -40,8 +33,19 @@ rcsid[] = "$Id: z_zone.c,v 1.4 1997/02/03 16:47:58 b1 Exp $";
 //  because it will get overwritten automatically if needed.
 // 
  
+#define MEM_ALIGN sizeof(void *)
 #define ZONEID 0x1d4a11
 
+typedef struct memblock_s
+{
+    int                        size;   // including the header and possibly tiny fragments
+    void**             user;
+    int                        tag;    // PU_FREE if this is free
+    int                        id;     // should be ZONEID
+    struct memblock_s* next;
+    struct memblock_s* prev;
+} memblock_t;
+
 
 typedef struct
 {
@@ -79,8 +83,8 @@ void Z_ClearZone (memzone_t* zone)
        
     block->prev = block->next = &zone->blocklist;
     
-    // NULL indicates a free block.
-    block->user = NULL;        
+    // a free block.
+    block->tag = PU_FREE;
 
     block->size = zone->size - sizeof(memzone_t);
 }
@@ -109,8 +113,8 @@ void Z_Init (void)
        
     block->prev = block->next = &mainzone->blocklist;
 
-    // NULL indicates a free block.
-    block->user = NULL;
+    // free block
+    block->tag = PU_FREE;
     
     block->size = mainzone->size - sizeof(memzone_t);
 }
@@ -129,45 +133,42 @@ void Z_Free (void* ptr)
     if (block->id != ZONEID)
        I_Error ("Z_Free: freed a pointer without ZONEID");
                
-    if (block->user > (void **)0x100)
+    if (block->tag != PU_FREE && block->user != NULL)
     {
-       // smaller values are not pointers
-       // Note: OS-dependend?
-       
-       // clear the user's mark
-       *block->user = 0;
+       // clear the user's mark
+           *block->user = 0;
     }
 
     // mark as free
-    block->user = NULL;        
-    block->tag = 0;
+    block->tag = PU_FREE;
+    block->user = NULL;
     block->id = 0;
        
     other = block->prev;
 
-    if (!other->user)
+    if (other->tag == PU_FREE)
     {
-       // merge with previous free block
-       other->size += block->size;
-       other->next = block->next;
-       other->next->prev = other;
+        // merge with previous free block
+        other->size += block->size;
+        other->next = block->next;
+        other->next->prev = other;
 
-       if (block == mainzone->rover)
-           mainzone->rover = other;
+        if (block == mainzone->rover)
+            mainzone->rover = other;
 
-       block = other;
+        block = other;
     }
        
     other = block->next;
-    if (!other->user)
+    if (other->tag == PU_FREE)
     {
-       // merge the next free block onto the end
-       block->size += other->size;
-       block->next = other->next;
-       block->next->prev = block;
+        // merge the next free block onto the end
+        block->size += other->size;
+        block->next = other->next;
+        block->next->prev = block;
 
-       if (other == mainzone->rover)
-           mainzone->rover = block;
+        if (other == mainzone->rover)
+            mainzone->rover = block;
     }
 }
 
@@ -191,8 +192,9 @@ Z_Malloc
     memblock_t* rover;
     memblock_t* newblock;
     memblock_t*        base;
+    void *result;
 
-    size = (size + 3) & ~3;
+    size = (size + MEM_ALIGN - 1) & ~(MEM_ALIGN - 1);
     
     // scan through the block list,
     // looking for the first free block
@@ -206,42 +208,45 @@ Z_Malloc
     //  back up over them
     base = mainzone->rover;
     
-    if (!base->prev->user)
-       base = base->prev;
+    if (base->prev->tag == PU_FREE)
+        base = base->prev;
        
     rover = base;
     start = base->prev;
        
     do
     {
-       if (rover == start)
-       {
-           // scanned all the way around the list
-           I_Error ("Z_Malloc: failed on allocation of %i bytes", size);
-       }
+        if (rover == start)
+        {
+            // scanned all the way around the list
+            I_Error ("Z_Malloc: failed on allocation of %i bytes", size);
+        }
        
-       if (rover->user)
-       {
-           if (rover->tag < PU_PURGELEVEL)
-           {
-               // hit a block that can't be purged,
-               //  so move base past it
-               base = rover = rover->next;
-           }
-           else
-           {
-               // free the rover block (adding the size to base)
-
-               // the rover can be the base block
-               base = base->prev;
-               Z_Free ((byte *)rover+sizeof(memblock_t));
-               base = base->next;
-               rover = base->next;
-           }
-       }
-       else
-           rover = rover->next;
-    } while (base->user || base->size < size);
+        if (rover->tag != PU_FREE)
+        {
+            if (rover->tag < PU_PURGELEVEL)
+            {
+                // hit a block that can't be purged,
+                // so move base past it
+                base = rover = rover->next;
+            }
+            else
+            {
+                // free the rover block (adding the size to base)
+
+                // the rover can be the base block
+                base = base->prev;
+                Z_Free ((byte *)rover+sizeof(memblock_t));
+                base = base->next;
+                rover = base->next;
+            }
+        }
+        else
+        {
+            rover = rover->next;
+        }
+
+    } while (base->tag != PU_FREE || base->size < size);
 
     
     // found a block big enough
@@ -249,43 +254,39 @@ Z_Malloc
     
     if (extra >  MINFRAGMENT)
     {
-       // there will be a free fragment after the allocated block
-       newblock = (memblock_t *) ((byte *)base + size );
-       newblock->size = extra;
+        // there will be a free fragment after the allocated block
+        newblock = (memblock_t *) ((byte *)base + size );
+        newblock->size = extra;
        
-       // NULL indicates free block.
-       newblock->user = NULL;  
-       newblock->tag = 0;
-       newblock->prev = base;
-       newblock->next = base->next;
-       newblock->next->prev = newblock;
-
-       base->next = newblock;
-       base->size = size;
+        newblock->tag = PU_FREE;
+        newblock->user = NULL; 
+        newblock->prev = base;
+        newblock->next = base->next;
+        newblock->next->prev = newblock;
+
+        base->next = newblock;
+        base->size = size;
     }
        
-    if (user)
-    {
-       // mark as an in use block
-       base->user = user;                      
-       *(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
-    }
-    else
-    {
-       if (tag >= PU_PURGELEVEL)
+       if (user == NULL && tag >= PU_PURGELEVEL)
            I_Error ("Z_Malloc: an owner is required for purgable blocks");
 
-       // mark as in use, but unowned  
-       base->user = (void *)2;         
-    }
+    base->user = user;
     base->tag = tag;
 
+    result  = (void *) ((byte *)base + sizeof(memblock_t));
+
+    if (base->user)
+    {
+        *base->user = result;
+    }
+
     // next allocation will start looking here
     mainzone->rover = base->next;      
        
     base->id = ZONEID;
     
-    return (void *) ((byte *)base + sizeof(memblock_t));
+    return result;
 }
 
 
@@ -309,7 +310,7 @@ Z_FreeTags
        next = block->next;
 
        // free block?
-       if (!block->user)
+       if (block->tag == PU_FREE)
            continue;
        
        if (block->tag >= lowtag && block->tag <= hightag)
@@ -354,7 +355,7 @@ Z_DumpHeap
        if ( block->next->prev != block)
            printf ("ERROR: next block doesn't have proper back link\n");
 
-       if (!block->user && !block->next->user)
+       if (block->tag == PU_FREE && block->next->tag == PU_FREE)
            printf ("ERROR: two consecutive free blocks\n");
     }
 }
@@ -386,7 +387,7 @@ void Z_FileDumpHeap (FILE* f)
        if ( block->next->prev != block)
            fprintf (f,"ERROR: next block doesn't have proper back link\n");
 
-       if (!block->user && !block->next->user)
+       if (block->tag == PU_FREE && block->next->tag == PU_FREE)
            fprintf (f,"ERROR: two consecutive free blocks\n");
     }
 }
@@ -414,7 +415,7 @@ void Z_CheckHeap (void)
        if ( block->next->prev != block)
            I_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
 
-       if (!block->user && !block->next->user)
+       if (block->tag == PU_FREE && block->next->tag == PU_FREE)
            I_Error ("Z_CheckHeap: two consecutive free blocks\n");
     }
 }
@@ -425,24 +426,38 @@ void Z_CheckHeap (void)
 //
 // Z_ChangeTag
 //
-void
-Z_ChangeTag2
-( void*                ptr,
-  int          tag )
+void Z_ChangeTag2(void *ptr, int tag, char *file, int line)
 {
     memblock_t*        block;
        
-    block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
+    block = (memblock_t *) ((byte *)ptr - sizeof(memblock_t));
 
     if (block->id != ZONEID)
-       I_Error ("Z_ChangeTag: freed a pointer without ZONEID");
+        I_Error("%s:%i: Z_ChangeTag: block without a ZONEID!",
+                file, line);
 
-    if (tag >= PU_PURGELEVEL && (unsigned)block->user < 0x100)
-       I_Error ("Z_ChangeTag: an owner is required for purgable blocks");
+    if (tag >= PU_PURGELEVEL && block->user == NULL)
+        I_Error("%s:%i: Z_ChangeTag: an owner is required "
+                "for purgable blocks", file, line);
 
     block->tag = tag;
 }
 
+void Z_ChangeUser(void *ptr, void **user)
+{
+    memblock_t*        block;
+
+    block = (memblock_t *) ((byte *)ptr - sizeof(memblock_t));
+
+    if (block->id != ZONEID)
+    {
+        I_Error("Z_ChangeUser: Tried to change user for invalid block!");
+    }
+
+    block->user = user;
+    *user = ptr;
+}
+
 
 
 //
@@ -456,12 +471,18 @@ int Z_FreeMemory (void)
     free = 0;
     
     for (block = mainzone->blocklist.next ;
-        block != &mainzone->blocklist;
-        block = block->next)
+         block != &mainzone->blocklist;
+         block = block->next)
     {
-       if (!block->user || block->tag >= PU_PURGELEVEL)
-           free += block->size;
+        if (block->tag == PU_FREE || block->tag >= PU_PURGELEVEL)
+            free += block->size;
     }
+
     return free;
 }
 
+unsigned int Z_ZoneSize(void)
+{
+    return mainzone->size;
+}
+
index cf153d0e4e92079d30ee8e45b63f4413ea9f22df..526f30d30a3cbae6e87e04549eebe93be8c6b5d8 100644 (file)
@@ -1,18 +1,16 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
 //
-// $Id:$
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2014 Simon Howard
 //
-// Copyright (C) 1993-1996 by id Software, Inc.
+// 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 source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 //
 // DESCRIPTION:
 //      Zone Memory Allocation, perhaps NeXT ObjectiveC inspired.
@@ -20,7 +18,6 @@
 //      to John Carmack, might have been useful for
 //      Quake.
 //
-//---------------------------------------------------------------------
 
 
 
 //
 // ZONE MEMORY
 // PU - purge tags.
-// Tags < 100 are not overwritten until freed.
-#define PU_STATIC              1       // static entire execution time
-#define PU_SOUND               2       // static while playing
-#define PU_MUSIC               3       // static while playing
-#define PU_DAVE                4       // anything else Dave wants static
-#define PU_LEVEL               50      // static until level exited
-#define PU_LEVSPEC             51      // a special thinker in a level
-// Tags >= 100 are purgable whenever needed.
-#define PU_PURGELEVEL  100
-#define PU_CACHE               101
 
+enum
+{
+    PU_STATIC = 1,                  // static entire execution time
+    PU_SOUND,                       // static while playing
+    PU_MUSIC,                       // static while playing
+    PU_FREE,                        // a free block
+    PU_LEVEL,                       // static until level exited
+    PU_LEVSPEC,                     // a special thinker in a level
+    
+    // Tags >= PU_PURGELEVEL are purgable whenever needed.
+
+    PU_PURGELEVEL,
+    PU_CACHE,
+
+    // Total number of different tag types
+
+    PU_NUM_TAGS
+};
+        
 
 void   Z_Init (void);
 void*  Z_Malloc (int size, int tag, void *ptr);
@@ -51,36 +57,17 @@ void    Z_FreeTags (int lowtag, int hightag);
 void    Z_DumpHeap (int lowtag, int hightag);
 void    Z_FileDumpHeap (FILE *f);
 void    Z_CheckHeap (void);
-void    Z_ChangeTag2 (void *ptr, int tag);
+void    Z_ChangeTag2 (void *ptr, int tag, char *file, int line);
+void    Z_ChangeUser(void *ptr, void **user);
 int     Z_FreeMemory (void);
-
-
-typedef struct memblock_s
-{
-    int                        size;   // including the header and possibly tiny fragments
-    void**             user;   // NULL if a free block
-    int                        tag;    // purgelevel
-    int                        id;     // should be ZONEID
-    struct memblock_s* next;
-    struct memblock_s* prev;
-} memblock_t;
+unsigned int Z_ZoneSize(void);
 
 //
 // This is used to get the local FILE:LINE info from CPP
 // prior to really call the function in question.
 //
-#define Z_ChangeTag(p,t) \
-{ \
-      if (( (memblock_t *)( (byte *)(p) - sizeof(memblock_t)))->id!=0x1d4a11) \
-         I_Error("Z_CT at "__FILE__":%i",__LINE__); \
-         Z_ChangeTag2(p,t); \
-};
-
+#define Z_ChangeTag(p,t)                                       \
+    Z_ChangeTag2((p), (t), __FILE__, __LINE__)
 
 
 #endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------