+++ /dev/null
-/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//
+++ /dev/null
-/info/cvsroot/id/id_doom
+++ /dev/null
-/info/cvsroot/
+++ /dev/null
-
-
-
- * 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
- **************************************************************
-
+++ /dev/null
-
-
- 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.
-
-
-
-
+++ /dev/null
-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
+++ /dev/null
-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)
-
-
-
--------------------------------------------------------------------
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
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)
+
#############################################################
#
#############################################################
+++ /dev/null
-
-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
-
+++ /dev/null
-
-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
+++ /dev/null
-
-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.
-
+++ /dev/null
-
-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)?
+++ /dev/null
-
-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.
-
+++ /dev/null
-
-- 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?
-// 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.
#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
{ { -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[] = {
{ { 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))
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;
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.
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);
}
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++)
{
if (m_paninc.x || m_paninc.y)
{
followplayer = 0;
- f_oldloc.x = MAXINT;
+ f_oldloc.x = INT_MAX;
}
m_x += m_paninc.x;
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;
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();
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);
}
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)
//
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;
{
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;
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);
}
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;
tmp.y = fl->a.y + (dy*(-fl->a.x))/dx;
tmp.x = 0;
}
+ else
+ {
+ tmp.x = 0;
+ tmp.y = 0;
+ }
if (outside == outcode1)
{
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
|| 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;
}
{
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;
}
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);
}
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;
}
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]);
}
}
-// 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))
void AM_Stop (void);
+extern cheatseq_t cheat_amap;
+
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
+++ /dev/null
-/* 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 */
--- /dev/null
+/* 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"
-// 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__
#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:$
-//
-//-----------------------------------------------------------------------------
--- /dev/null
+//
+// 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;
+}
+
+
-// 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__
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.
//
} 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:$
-//
-//-----------------------------------------------------------------------------
+
+++ /dev/null
-// 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:$
-//
-//-----------------------------------------------------------------------------
-
-
-// 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"
-// 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__
#include "doomdef.h"
-#ifdef __GNUG__
-#pragma interface
-#endif
// Weapon info: sprite frames, ammunition use.
extern weaponinfo_t weaponinfo[NUMWEAPONS];
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
--- /dev/null
+//
+// 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?";
+}
+
--- /dev/null
+//
+// 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
+
--- /dev/null
+//
+// 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;
+}
--- /dev/null
+//
+// 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
+
-// 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"
#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"
#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"
//
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
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;
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);
//
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);
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
// 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;
// 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));
}
{
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);
} 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 ();
+ }
}
}
//
void D_PageDrawer (void)
{
- V_DrawPatch (0,0, 0, W_CacheLumpName(pagename, PU_CACHE));
+ V_DrawPatch (0, 0, W_CacheLumpName(pagename, PU_CACHE));
}
// 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;
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;
{
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
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");
+ }
}
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;
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)
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
}
+
-// 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);
//
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
+
--- /dev/null
+//
+// 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";
+ }
+}
+
--- /dev/null
+//
+// 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__ */
+
-// 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;
}
}
// 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");
+ }
}
}
+
+++ /dev/null
-// 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:$
-//
-//-----------------------------------------------------------------------------
-
-// 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__
// as commands per game tick.
#include "d_ticcmd.h"
-#ifdef __GNUG__
-#pragma interface
-#endif
+#include "net_defs.h"
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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__
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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
typedef union
{
- actionf_p1 acp1;
actionf_v acv;
+ actionf_p1 acp1;
actionf_p2 acp2;
} actionf_t;
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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:$
-//
-//-----------------------------------------------------------------------------
--- /dev/null
+//
+// 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 */
+
--- /dev/null
+//
+// 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 */
+
--- /dev/null
+//
+// 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 */
+
--- /dev/null
+/*
+ * 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_ */
-// 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__
{
short x;
short y;
-} mapvertex_t;
+} PACKEDATTR mapvertex_t;
// A SideDef, defining the visual appearance of a wall,
char midtexture[8];
// Front sector, towards viewer.
short sector;
-} mapsidedef_t;
+} PACKEDATTR mapsidedef_t;
short tag;
// sidenum[1] will be -1 if one sided
short sidenum[2];
-} maplinedef_t;
+} PACKEDATTR maplinedef_t;
//
short lightlevel;
short special;
short tag;
-} mapsector_t;
+} PACKEDATTR mapsector_t;
// SubSector, as generated by BSP.
typedef struct
short numsegs;
// Index of first one, segs are stored sequentially.
short firstseg;
-} mapsubsector_t;
+} PACKEDATTR mapsubsector_t;
// LineSeg, generated by splitting LineDefs
short linedef;
short side;
short offset;
-} mapseg_t;
+} PACKEDATTR mapseg_t;
// else it's a node of another subtree.
unsigned short children[2];
-} mapnode_t;
+} PACKEDATTR mapnode_t;
short angle;
short type;
short options;
-} mapthing_t;
+} PACKEDATTR mapthing_t;
#endif // __DOOMDATA__
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-
-// 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.
-// 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,
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.
//
// 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.
} 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:$
-//
-//-----------------------------------------------------------------------------
--- /dev/null
+//
+// 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 */
+
+
--- /dev/null
+//
+// 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__
+
-// 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;
-// 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.
// 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"
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;
// -------------------------------------------
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.
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.
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;
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;
-extern int gametic;
-
-
// Bookkeeping on players - state.
extern player_t players[MAXPLAYERS];
extern wbstartstruct_t wminfo;
-// LUT of ammunition limits for each kind.
-// This doubles with BackPack powerup item.
-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;
extern gamestate_t wipegamestate;
extern int mouseSensitivity;
-//?
-// debug flag to cancel adaptiveness
-extern boolean singletics;
extern int bodyqueslot;
// 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:$
-//
-//-----------------------------------------------------------------------------
-// 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
+
-// 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!",
"THIS IS NO MESSAGE!\nPage intentionally left blank."
};
+#endif
-// 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:$
-//
-//-----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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 *
+ *---------------------------------------------------------------------*/
-// 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;
//
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;
}
boolean F_Responder (event_t *event)
{
- if (finalestage == 2)
+ if (finalestage == F_STAGE_CAST)
return F_CastResponder (event);
return false;
//
void F_Ticker (void)
{
- int i;
+ size_t i;
// check for skipping
if ( (gamemode == commercial)
// advance animation
finalecount++;
- if (finalestage == 2)
+ if (finalestage == F_STAGE_CAST)
{
F_CastTicker ();
return;
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);
byte* dest;
int x,y,w;
- int count;
+ signed int count;
char* ch;
int c;
int cx;
// 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++)
{
cy = 10;
ch = finaletext;
- count = (finalecount - 10)/TEXTSPEED;
+ count = ((signed int) finalecount - 10) / TEXTSPEED;
if (count < 0)
count = 0;
for ( ; count ; count-- )
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;
}
//
// F_StartCast
//
-extern gamestate_t wipegamestate;
-
-
void F_StartCast (void)
{
wipegamestate = -1; // force a screen wipe
caststate = &states[mobjinfo[castorder[castnum].type].seestate];
casttics = caststate->tics;
castdeath = false;
- finalestage = 2;
+ finalestage = F_STAGE_CAST;
castframes = 0;
castonmelee = 0;
castattacking = false;
}
w = SHORT (hu_font[c]->width);
- V_DrawPatch(cx, 180, 0, hu_font[c]);
+ V_DrawPatch(cx, 180, hu_font[c]);
cx+=w;
}
//
// F_CastDrawer
//
-void V_DrawPatchFlipped (int x, int y, int scrn, patch_t *patch);
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];
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);
}
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 )
//
void F_BunnyScroll (void)
{
- int scrolled;
+ signed int scrolled;
int x;
patch_t* p1;
patch_t* p2;
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)
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;
}
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;
- }
- }
-
}
-// 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__
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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"
int ticks )
{
Z_Free(y);
+ Z_Free(wipe_scr_start);
+ Z_Free(wipe_scr_end);
return 0;
}
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;
}
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;
}
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);
}
}
return !go;
-
}
+
-// 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__
int ticks );
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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"
#include "hu_stuff.h"
#include "st_stuff.h"
#include "am_map.h"
+#include "statdump.h"
// Needs access to LFB.
#include "v_video.h"
#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;
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
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;
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++)
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
// 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;
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;
// 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();
|| 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)
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;
// 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
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));
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.
{
// 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
}
return false;
}
-
+
if (gamestate == GS_LEVEL)
{
#if 0
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:
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:
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:
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
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;
}
}
}
+
+ // Have we just finished displaying an intermission screen?
+
+ if (oldgamestate == GS_INTERMISSION && gamestate != GS_INTERMISSION)
+ {
+ WI_End();
+ }
+
+ oldgamestate = gamestate;
// do main actions
switch (gamestate)
case GS_DEMOSCREEN:
D_PageTicker ();
- break;
+ break;
}
}
// 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);
-
-}
+}
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];
fixed_t x;
fixed_t y;
subsector_t* ss;
- unsigned an;
mobj_t* mo;
int i;
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
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) )
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++)
gamestate = GS_INTERMISSION;
viewactive = false;
automapactive = false;
+
+ StatCopy(&wminfo);
- if (statcopy)
- memcpy (statcopy, &wminfo, sizeof(wminfo));
-
WI_Start (&wminfo);
}
void G_LoadGame (char* name)
{
- strcpy (savename, name);
+ M_StringCopy(savename, name, sizeof(savename));
gameaction = ga_loadgame;
}
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 ();
}
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 ();
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 )
{
}
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
}
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
//
-// 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;
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++;
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;
// 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;
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;
fastparm = false;
nomonsters = false;
consoleplayer = 0;
- D_AdvanceDemo ();
+
+ if (singledemo)
+ I_Quit ();
+ else
+ D_AdvanceDemo ();
+
return true;
}
-// 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__
#include "doomdef.h"
#include "d_event.h"
-
+#include "d_ticcmd.h"
//
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:$
-//
-//-----------------------------------------------------------------------------
+
--- /dev/null
+//
+// 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;
+}
+
--- /dev/null
+//
+// 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__ */
+
-// 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"
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 <= '_')
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
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]);
}
}
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
}
}
- //lastautomapactive = automapactive;
if (l->needsupdate) l->needsupdate--;
}
( hu_itext_t* it,
unsigned char ch )
{
+ ch = toupper(ch);
if (ch >= ' ' && ch <= '_')
HUlib_addCharToTextLine(&it->l, (char) ch);
-// 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
void HUlib_eraseIText(hu_itext_t* it);
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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"
// 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))
-char* chat_macros[] =
+char *chat_macros[10] =
{
HUSTR_CHATMACRO0,
HUSTR_CHATMACRO1,
HUSTR_PLRRED
};
-
char chat_char; // remove later.
static player_t* plr;
patch_t* hu_font[HU_FONTSIZE];
static int message_counter;
extern int showMessages;
-extern boolean automapactive;
static boolean headsupactive = false;
"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,
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,
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,
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)
{
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);
}
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++));
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)
{
|| 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;
{
if (((head + 1) & (QUEUESIZE-1)) == tail)
{
- plr->message = HUSTR_MSGU;
+ plr->message = DEH_String(HUSTR_MSGU);
}
else
{
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;
if (ev->data1 == KEY_RSHIFT)
{
- shiftdown = ev->type == ev_keydown;
return false;
}
else if (ev->data1 == KEY_RALT || ev->data1 == KEY_LALT)
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);
{
for (i=0; i<MAXPLAYERS ; i++)
{
- if (ev->data1 == destination_keys[i])
+ if (ev->data2 == key_multi_msgplayer[i])
{
if (playeringame[i] && i!=consoleplayer)
{
{
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);
}
}
}
}
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");
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;
-// 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__
#define HU_BROADCAST 5
-#define HU_MSGREFRESH KEY_ENTER
#define HU_MSGX 0
#define HU_MSGY 0
#define HU_MSGWIDTH 64 // in characters
char HU_dequeueChatChar(void);
void HU_Erase(void);
+extern char *chat_macros[10];
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
+
--- /dev/null
+//
+// 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
+}
+
--- /dev/null
+//
+// 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
--- /dev/null
+//
+// 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
+}
+
--- /dev/null
+//
+// 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
+
--- /dev/null
+//
+// 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]);
+ }
+}
+
--- /dev/null
+//
+// 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__ */
+
-// 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;
-}
+}
+
+++ /dev/null
-// 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);
-}
-
+++ /dev/null
-// 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:$
-//
-//-----------------------------------------------------------------------------
--- /dev/null
+//
+// 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);
+}
+
--- /dev/null
+//
+// 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,
+};
+
--- /dev/null
+//
+// 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,
+};
+
+
--- /dev/null
+//
+// 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__ */
+
--- /dev/null
+//
+// 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,
+};
+
--- /dev/null
+//
+// 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,
+};
+
-// 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");
-}
-// 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:$
-//
-//-----------------------------------------------------------------------------
+
--- /dev/null
+//
+// 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
+
-// 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;
+}
+
-// 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);
// 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
// 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:$
-//
-//-----------------------------------------------------------------------------
+
--- /dev/null
+//
+// 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);
+}
+
--- /dev/null
+//
+// 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
+
-// 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
+}
-// 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:$
-//
-//-----------------------------------------------------------------------------
+++ /dev/null
-// 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--);
- */
-}
-
-
+++ /dev/null
-// 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--);
- */
-}
-
-
//
// 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>
#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;
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;
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?
}
//
#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;
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++];
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)
+{
+}
--- /dev/null
+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,
+
+};
-// 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"
"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
};
-// 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__
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,
extern mobjinfo_t mobjinfo[NUMMOBJTYPES];
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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;
// 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;
+ }
+}
-// 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
//
// 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:$
-//
-//-----------------------------------------------------------------------------
-// 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"
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
-// 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"
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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.
( 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
( 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);
}
-// 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
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
--- /dev/null
+//
+// 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;
+}
+
--- /dev/null
+//
+// 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
--- /dev/null
+//
+// 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.
+}
+
--- /dev/null
+//
+// 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__ */
+
-// 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"
( fixed_t a,
fixed_t b )
{
- return ((long long) a * (long long) b) >> FRACBITS;
+ return ((int64_t) a * (int64_t) b) >> FRACBITS;
}
// 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;
-}
-// 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
//
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:$
-//
-//-----------------------------------------------------------------------------
-// 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"
#include "g_game.h"
#include "m_argv.h"
-#include "m_swap.h"
+#include "m_controls.h"
+#include "p_saveg.h"
#include "s_sound.h"
#include "m_menu.h"
-
extern patch_t* hu_font[HU_FONTSIZE];
extern boolean message_dontfuckwithme;
//
// 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,
char endstring[160];
+//static boolean opldev;
//
// MENU TYPEDEFS
// 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;
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);
{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'}
};
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 =
//
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;
}
}
{
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);
{
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));
}
{
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 ();
}
{
if (netgame)
{
- M_StartMessage(LOADNET,NULL,false);
+ M_StartMessage(DEH_String(LOADNET),NULL,false);
return;
}
{
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);
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]);
}
{
if (!usergame)
{
- M_StartMessage(SAVEDEAD,NULL,false);
+ M_StartMessage(DEH_String(SAVEDEAD),NULL,false);
return;
}
//
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);
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);
}
//
// 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);
{
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);
}
//
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;
}
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));
}
//
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)
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)
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);
}
//
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));
}
//
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);
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);
{
if (choice == nightmare)
{
- M_StartMessage(NIGHTMARE,M_VerifyNightmare,true);
+ M_StartMessage(DEH_String(NIGHTMARE),M_VerifyNightmare,true);
return;
}
if ( (gamemode == shareware)
&& choice)
{
- M_StartMessage(SWSTRING,NULL,false);
+ M_StartMessage(DEH_String(SWSTRING),NULL,false);
M_SetupNextMenu(&ReadDef1);
return;
}
//
// 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);
}
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;
}
//
// M_EndGame
//
-void M_EndGameResponse(int ch)
+void M_EndGameResponse(int key)
{
- if (ch != 'y')
+ if (key != key_menu_confirm)
return;
currentMenu->lastOn = itemOn;
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);
}
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)
-void M_QuitResponse(int ch)
+void M_QuitResponse(int key)
{
- if (ch != 'y')
+ if (key != key_menu_confirm)
return;
if (!netgame)
{
}
+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);
}
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);
}
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));
}
( 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
( 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));
}
}
-
void M_StopMessage(void)
{
menuactive = messageLastMenuActive;
//
int M_StringWidth(char* string)
{
- int i;
+ size_t i;
int w = 0;
int c;
//
int M_StringHeight(char* string)
{
- int i;
+ size_t i;
int h;
int height = SHORT(hu_font[0]->height);
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
boolean M_Responder (event_t* ev)
{
int ch;
+ int key;
int i;
static int joywait = 0;
static int mousewait = 0;
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
{
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;
}
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)
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]) <
// 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);
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)
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)
{
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)
{
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)
{
}
}
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)
{
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;
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
{
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;
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));
}
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;
}
-// 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__
+extern int detailLevel;
+extern int screenblocks;
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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;
//
// 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);
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
-// 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:$
-//
-//-----------------------------------------------------------------------------
+
-// 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 ,
{
rndindex = prndindex = 0;
}
-
-
-
-
-// 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__
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
+++ /dev/null
-// 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
-
-
+++ /dev/null
-// 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:$
-//
-//-----------------------------------------------------------------------------
--- /dev/null
+//
+// 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;
+ }
+}
+
+
--- /dev/null
+//
+// 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 */
+
--- /dev/null
+//
+// 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 */
--- /dev/null
+//
+// 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 */
+
+
--- /dev/null
+//
+// 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 */
--- /dev/null
+//
+// 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 */
+
--- /dev/null
+//
+// 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 */
+
--- /dev/null
+//
+// 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 */
+
--- /dev/null
+//
+// 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 */
+
--- /dev/null
+//
+// 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 */
+
--- /dev/null
+//
+// 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 */
+
--- /dev/null
+//
+// 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 */
+
-// 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"
case silentCrushAndRaise:
break;
default:
- S_StartSound((mobj_t *)&ceiling->sector->soundorg,
- sfx_stnmov);
+ S_StartSound(&ceiling->sector->soundorg, sfx_stnmov);
// ?
break;
}
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;
{
case silentCrushAndRaise: break;
default:
- S_StartSound((mobj_t *)&ceiling->sector->soundorg,
- sfx_stnmov);
+ S_StartSound(&ceiling->sector->soundorg, sfx_stnmov);
}
}
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:
-// 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"
{
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:
{
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:
{
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:
{
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;
}
}
{
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;
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;
}
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;
}
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;
}
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:
mobj_t* thing )
{
player_t* player;
- //int secnum;
sector_t* sec;
vldoor_t* door;
int side;
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;
}
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;
}
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;
}
// if the sector has an active thinker, use it
sec = sides[ line->sidenum[side^1]] .sector;
- //secnum = sec-sectors;
if (sec->specialdata)
{
{
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;
}
{
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;
}
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;
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;
}
//
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;
}
-// 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"
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;
&& 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;
}
tdir<=DI_SOUTHEAST;
tdir++ )
{
- if (tdir!=turnaround)
+ if (tdir != (int) turnaround)
{
actor->movedir =tdir;
tdir != (DI_EAST-1);
tdir-- )
{
- if (tdir!=turnaround)
+ if (tdir != (int) turnaround)
{
- actor->movedir =tdir;
+ actor->movedir = tdir;
if ( P_TryWalk(actor) )
return;
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;
}
junk.tag = 666;
- EV_DoDoor(&junk,open);
+ EV_DoDoor(&junk, vld_open);
}
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;
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]);
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]);
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]);
//
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
}
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)
{
case 6:
junk.tag = 666;
- EV_DoDoor (&junk, blazeOpen);
+ EV_DoDoor (&junk, vld_blazeOpen);
return;
break;
mobj_t* braintargets[32];
int numbraintargets;
-int braintargeton;
+int braintargeton = 0;
void A_BrainAwake (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);
-// 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"
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)
{
}
P_RemoveThinker(&floor->thinker);
- S_StartSound((mobj_t *)&floor->sector->soundorg,
- sfx_pstop);
+ S_StartSound(&floor->sector->soundorg, sfx_pstop);
}
}
case raiseToTexture:
{
- int minsize = MAXINT;
+ int minsize = INT_MAX;
side_t* side;
floor->direction = 1;
floormove_t* floor;
- fixed_t stairsize;
- fixed_t speed;
+ fixed_t stairsize = 0;
+ fixed_t speed = 0;
secnum = -1;
rtn = 0;
-// 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.
#include "dstrings.h"
#include "sounds.h"
+#include "deh_main.h"
+#include "deh_misc.h"
#include "doomstat.h"
#include "m_random.h"
#include "s_sound.h"
-#ifdef __GNUG__
-#pragma implementation "p_inter.h"
-#endif
#include "p_inter.h"
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] )
{
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);
{
// 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;
// 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;
case SPR_YKEY:
if (!player->cards[it_yellowcard])
- player->message = GOTYELWCARD;
+ player->message = DEH_String(GOTYELWCARD);
P_GiveCard (player, it_yellowcard);
if (!netgame)
break;
case SPR_RKEY:
if (!player->cards[it_redcard])
- player->message = GOTREDCARD;
+ player->message = DEH_String(GOTREDCARD);
P_GiveCard (player, it_redcard);
if (!netgame)
break;
case SPR_BSKU:
if (!player->cards[it_blueskull])
- player->message = GOTBLUESKUL;
+ player->message = DEH_String(GOTBLUESKUL);
P_GiveCard (player, it_blueskull);
if (!netgame)
break;
case SPR_YSKU:
if (!player->cards[it_yellowskull])
- player->message = GOTYELWSKUL;
+ player->message = DEH_String(GOTYELWSKUL);
P_GiveCard (player, it_yellowskull);
if (!netgame)
break;
case SPR_RSKU:
if (!player->cards[it_redskull])
- player->message = GOTREDSKULL;
+ player->message = DEH_String(GOTREDSKULL);
P_GiveCard (player, it_redskull);
if (!netgame)
break;
case SPR_STIM:
if (!P_GiveBody (player, 10))
return;
- player->message = GOTSTIM;
+ player->message = DEH_String(GOTSTIM);
break;
case SPR_MEDI:
return;
if (player->health < 25)
- player->message = GOTMEDINEED;
+ player->message = DEH_String(GOTMEDINEED);
else
- player->message = GOTMEDIKIT;
+ player->message = DEH_String(GOTMEDIKIT);
break;
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;
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;
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:
}
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;
// 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
-// 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);
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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"
-// 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__
//
// P_MOBJ
//
-#define ONFLOORZ MININT
-#define ONCEILINGZ MAXINT
+#define ONFLOORZ INT_MIN
+#define ONCEILINGZ INT_MAX
// Time interval for item respawning.
#define ITEMQUESIZE 128
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);
} 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;
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);
#endif // __P_LOCAL__
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-
-
-// 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"
// 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;
// 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;
// MOVEMENT ITERATOR FUNCTIONS
//
+static void SpechitOverrun(line_t *ld);
//
// PIT_CheckLine
// 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;
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) ) )
{
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.
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)
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;
{
fixed_t x2;
fixed_t y2;
+
+ t1 = P_SubstNullMobj(t1);
angle >>= ANGLETOFINESHIFT;
shootthing = t1;
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;
+ }
+}
+
-// 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>
#include "m_bbox.h"
#include "doomdef.h"
+#include "doomstat.h"
#include "p_local.h"
( fixed_t* tmbox,
line_t* ld )
{
- int p1;
- int p2;
+ int p1 = 0;
+ int p2 = 0;
switch (ld->slopetype)
{
boolean earlyout;
int ptflags;
+static void InterceptsOverrun(int num_intercepts, intercept_t *intercept);
+
//
// PIT_AddLineIntercepts.
// Looks for lines in the given block
intercept_p->frac = frac;
intercept_p->isaline = true;
intercept_p->d.line = ld;
+ InterceptsOverrun(intercept_p - intercepts, intercept_p);
intercept_p++;
return true; // continue
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
while (count--)
{
- dist = MAXINT;
+ dist = INT_MAX;
for (scan = intercepts ; scan<intercept_p ; scan++)
{
if (scan->frac < dist)
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);
+}
//
-// 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"
// 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;
}
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) )
{
mobj->movecount++;
- if (mobj->movecount < 12*35)
+ if (mobj->movecount < 12*TICRATE)
return;
if ( leveltime&31 )
return;
// wait at least 30 seconds
- if (leveltime - itemrespawntime[iquetail] < 30*35)
+ if (leveltime - itemrespawntime[iquetail] < 30*TICRATE)
return;
mthing = &itemrespawnque[iquetail];
int i;
+ if (mthing->type == 0)
+ {
+ return;
+ }
+
// not playing?
if (!playeringame[mthing->type-1])
return;
}
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)
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
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)
-// 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__
-#ifdef __GNUG__
-#pragma interface
-#endif
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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"
|| plat->type == raiseToNearestAndChange)
{
if (!(leveltime&7))
- S_StartSound((mobj_t *)&plat->sector->soundorg,
- sfx_stnmov);
+ S_StartSound(&plat->sector->soundorg, sfx_stnmov);
}
{
plat->count = plat->wait;
plat->status = down;
- S_StartSound((mobj_t *)&plat->sector->soundorg,
- sfx_pstart);
+ S_StartSound(&plat->sector->soundorg, sfx_pstart);
}
else
{
{
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)
{
{
plat->count = plat->wait;
plat->status = waiting;
- S_StartSound((mobj_t *)&plat->sector->soundorg,sfx_pstop);
+ S_StartSound(&plat->sector->soundorg,sfx_pstop);
}
break;
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;
// 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:
plat->wait = 0;
plat->status = up;
- S_StartSound((mobj_t *)&sec->soundorg,sfx_stnmov);
+ S_StartSound(&sec->soundorg,sfx_stnmov);
break;
case downWaitUpStay:
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:
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:
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);
-// 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"
#define WEAPONTOP 32*FRACUNIT
-// plasma cells for a bfg attack
-#define BFGCELLS 40
-
//
// P_SetPsprite
// 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
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;
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;
+ }
+}
//
( 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);
}
( 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);
}
( player_t* player,
pspdef_t* psp )
{
- player->ammo[weaponinfo[player->readyweapon].ammo]--;
+ DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1);
P_SetPsprite (player,
ps_flash,
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,
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,
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,
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,
-// 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__
// and the Frame Sequence table.
#include "info.h"
-#ifdef __GNUG__
-#pragma interface
-#endif
//
} pspdef_t;
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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 = §ors[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 = §ors[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 = §ors[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 = §ors[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 = §ors[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 = §ors[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 = §ors[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
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]);
}
}
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 ];
- }
- }
}
}
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)
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;
}
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;
}
// 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;
}
} 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;
}
}
// add a terminating marker
- *save_p++ = tc_end;
+ saveg_write8(tc_end);
}
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;
mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
P_AddThinker (&mobj->thinker);
break;
-
+
default:
I_Error ("Unknown tclass %i in savegame",tclass);
}
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
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);
}
// 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 = §ors[(int)ceiling->sector];
+ saveg_read_ceiling_t(ceiling);
ceiling->sector->specialdata = ceiling;
if (ceiling->thinker.function.acp1)
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 = §ors[(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 = §ors[(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 = §ors[(int)plat->sector];
+ saveg_read_plat_t(plat);
plat->sector->specialdata = plat;
if (plat->thinker.function.acp1)
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 = §ors[(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 = §ors[(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 = §ors[(int)glow->sector];
+ saveg_read_glow_t(glow);
glow->thinker.function.acp1 = (actionf_p1)T_Glow;
P_AddThinker (&glow->thinker);
break;
-// 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.
void P_ArchiveSpecials (void);
void P_UnArchiveSpecials (void);
-extern byte* save_p;
+extern FILE *save_stream;
+extern boolean savegame_error;
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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"
int numsides;
side_t* sides;
+static int totallines;
// BLOCKMAP
// Created from axis aligned bounding box
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;
}
// 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
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);
{
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);
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);
}
ss->firstline = SHORT(ms->firstseg);
}
- Z_Free (data);
+ W_ReleaseLumpNum(lump);
}
ss->thinglist = NULL;
}
- Z_Free (data);
+ W_ReleaseLumpNum(lump);
}
}
}
- Z_Free (data);
+ W_ReleaseLumpNum(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);
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
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);
}
else
ld->backsector = 0;
}
-
- Z_Free (data);
+
+ W_ReleaseLumpNum(lump);
}
sd->midtexture = R_TextureNumForName(msd->midtexture);
sd->sector = §ors[SHORT(msd->sector)];
}
-
- Z_Free (data);
+
+ W_ReleaseLumpNum(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);
}
line_t** linebuffer;
int i;
int j;
- int total;
line_t* li;
sector_t* sector;
subsector_t* ss;
// 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;
}
+// 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
// 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
{
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;
-// 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.
void P_Init (void);
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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"
continue;
line->validcount = validcount;
-
+
v1 = line->v1;
v2 = line->v2;
s1 = P_DivlineSide (v1->x,v1->y, &strace);
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) )
-// 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"
//
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;
{true, "WFALL4", "WFALL1", 8},
{true, "DBRAIN4", "DBRAIN1", 8},
- {-1, "", "", 0}
+ {-1, "", "", 0},
};
anim_t anims[MAXANIMS];
{
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;
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++;
// 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
//
int i;
line_t* check;
sector_t* other;
- fixed_t height = MAXINT;
+ fixed_t height = INT_MAX;
for (i=0 ;i < sec->linecount ; i++)
{
// 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;
case 16:
// Close Door 30
- EV_DoDoor(line,close30ThenOpen);
+ EV_DoDoor(line,vld_close30ThenOpen);
line->special = 0;
break;
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;
case 110:
// Blazing Door Close (faster than TURBO!)
- EV_DoDoor (line,blazeClose);
+ EV_DoDoor (line,vld_blazeClose);
line->special = 0;
break;
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:
case 86:
// Open Door
- EV_DoDoor(line,open);
+ EV_DoDoor(line,vld_open);
break;
case 87:
case 90:
// Raise Door
- EV_DoDoor(line,normal);
+ EV_DoDoor(line,vld_normal);
break;
case 91:
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:
case 46:
// OPEN DOOR
- EV_DoDoor(line,open);
+ EV_DoDoor(line,vld_open);
P_ChangeSwitchTexture(line,1);
break;
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
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 = §ors[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);
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);
floor->direction = -1;
floor->sector = s1;
floor->speed = FLOORSPEED / 2;
- floor->floordestheight = s3->floorheight;
+ floor->floordestheight = s3_floorheight;
break;
}
}
{
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++)
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++;
-// 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:
// according to adjacent sectors, respective
// utility functions, etc.
//
-//-----------------------------------------------------------------------------
#ifndef __P_SPEC__
bwhere_e where;
int btexture;
int btimer;
- mobj_t* soundorg;
+ degenmobj_t *soundorg;
} button_t;
//
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;
mobj_t* thing );
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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"
episode = 1;
- if (gamemode == registered)
+ if (gamemode == registered || gamemode == retail)
episode = 2;
else
if ( gamemode == commercial )
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));
}
}
}
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;
}
}
case 29:
// Raise Door
- if (EV_DoDoor(line,normal))
+ if (EV_DoDoor(line,vld_normal))
P_ChangeSwitchTexture(line,0);
break;
case 50:
// Close Door
- if (EV_DoDoor(line,close))
+ if (EV_DoDoor(line,vld_close))
P_ChangeSwitchTexture(line,0);
break;
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;
// BlzOpenDoor RED
case 137:
// BlzOpenDoor YELLOW
- if (EV_DoLockedDoor (line,blazeOpen,thing))
+ if (EV_DoLockedDoor (line,vld_blazeOpen,thing))
P_ChangeSwitchTexture(line,0);
break;
// BUTTONS
case 42:
// Close Door
- if (EV_DoDoor(line,close))
+ if (EV_DoDoor(line,vld_close))
P_ChangeSwitchTexture(line,1);
break;
case 61:
// Open Door
- if (EV_DoDoor(line,open))
+ if (EV_DoDoor(line,vld_open))
P_ChangeSwitchTexture(line,1);
break;
case 63:
// Raise Door
- if (EV_DoDoor(line,normal))
+ if (EV_DoDoor(line,vld_normal))
P_ChangeSwitchTexture(line,1);
break;
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;
// BlzOpenDoor RED
case 136:
// BlzOpenDoor YELLOW
- if (EV_DoLockedDoor (line,blazeOpen,thing))
+ if (EV_DoLockedDoor (line,vld_blazeOpen,thing))
P_ChangeSwitchTexture(line,1);
break;
-// 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"
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);
-// 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"
-// 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,
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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"
-// 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"
-// 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;
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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"
short patch;
short stepdir;
short colormap;
-} mappatch_t;
+} PACKEDATTR mappatch_t;
//
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,
// 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;
// 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;
+};
int numtextures;
texture_t** textures;
+texture_t** textures_hashtable;
int* texturewidthmask;
int count;
int position;
byte* source;
- //byte* dest;
- //
- //dest = (byte *)cache + 3;
-
+
while (patch->topdelta != 0xff)
{
source = (byte *)patch + 3;
{
texture_t* texture;
byte* patchcount; // patchcount[texture->width]
- byte* patchcount_alloc;
texpatch_t* patch;
patch_t* realpatch;
int x;
// 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++)
}
}
- free(patchcount_alloc);
+ Z_Free(patchcount);
}
}
+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];
+ }
+}
//
char* name_p;
int* patchlookup;
- int* patchlookup_alloc;
int totalwidth;
int nummappatches;
// 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
{
}
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++)
{
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];
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)
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();
}
{
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;
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++)
{
//
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);
}
void R_InitData (void)
{
R_InitTextures ();
- printf ("\nInitTextures");
+ printf (".");
R_InitFlats ();
- printf ("\nInitFlats");
+ printf (".");
R_InitSpriteLumps ();
- printf ("\nInitSprites");
+ printf (".");
R_InitColormaps ();
- printf ("\nInitColormaps");
}
//
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;
}
void R_PrecacheLevel (void)
{
char* flatpresent;
- char* flatpresent_alloc;
char* texturepresent;
- char* texturepresent_alloc;
char* spritepresent;
- char* spritepresent_alloc;
int i;
int j;
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++)
}
}
- 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++)
}
}
- 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)
}
}
- free(spritepresent_alloc);
+ Z_Free(spritepresent);
}
-// 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__
#include "r_defs.h"
#include "r_state.h"
-#ifdef __GNUG__
-#pragma interface
-#endif
// Retrieve column data for span blitting.
byte*
int R_CheckTextureNumForName (char *name);
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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
-// 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;
-// 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.
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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"
//
byte translations[3][256];
-
+// Backing buffer containing the bezel drawn around the screen and
+// surrounding background.
+
+static byte *background_buffer = NULL;
//
byte* dest2;
fixed_t frac;
fixed_t fracstep;
+ int x;
count = dc_yh - dc_yl;
// 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;
if (count < 0)
return;
-
#ifdef RANGECHECK
if ((unsigned)dc_x >= SCREENWIDTH
|| dc_yl < 0 || dc_yh >= SCREENHEIGHT)
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;
// 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--);
}
+
//
#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;
// 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--);
{
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++)
// 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--);
+}
//
// 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--);
}
//
// Preclaculate all row offsets.
for (i=0 ; i<height ; i++)
- ylookup[i] = screens[0] + (i+viewwindowy)*SCREENWIDTH;
+ ylookup[i] = I_VideoBuffer + (i+viewwindowy)*SCREENWIDTH;
}
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++)
{
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();
}
// 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);
+ }
}
// 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;
-// 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;
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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__
#include "r_draw.h"
#endif // __R_LOCAL__
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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 $";
#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"
// 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];
fixed_t dy;
fixed_t temp;
fixed_t dist;
+ fixed_t frac;
dx = abs(x - viewx);
dy = abs(y - viewy);
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] );
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;
else
{
colfunc = basecolfunc = R_DrawColumnLow;
- fuzzcolfunc = R_DrawFuzzColumn;
- transcolfunc = R_DrawTranslatedColumn;
+ fuzzcolfunc = R_DrawFuzzColumnLow;
+ transcolfunc = R_DrawTranslatedColumnLow;
spanfunc = R_DrawSpanLow;
}
//
// 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;
}
-// 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__
#include "r_data.h"
-#ifdef __GNUG__
-#pragma interface
-#endif
//
extern fixed_t viewcos;
extern fixed_t viewsin;
-extern int viewwidth;
-extern int viewheight;
extern int viewwindowx;
extern int viewwindowy;
// 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.
void R_SetViewSize (int blocks, int detail);
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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"
#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);
}
int x;
int stop;
int angle;
+ int lumpnum;
#ifdef RANGECHECK
if (ds_p - drawsegs > MAXDRAWSEGS)
}
// 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;
pl->bottom[x]);
}
- Z_ChangeTag (ds_source, PU_CACHE);
+ W_ReleaseLumpNum(lumpnum);
}
}
-// 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__
#include "r_data.h"
-#ifdef __GNUG__
-#pragma interface
-#endif
// Visplane related.
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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"
for (dc_x = x1 ; dc_x <= x2 ; dc_x++)
{
// calculate lighting
- if (maskedtexturecol[dc_x] != MAXSHORT)
+ if (maskedtexturecol[dc_x] != SHRT_MAX)
{
if (!fixedcolormap)
{
(byte *)R_GetColumn(texnum,maskedtexturecol[dc_x]) -3);
R_DrawMaskedColumn (col);
- maskedtexturecol[dc_x] = MAXSHORT;
+ maskedtexturecol[dc_x] = SHRT_MAX;
}
spryscale += rw_scalestep;
}
int top;
int bottom;
- //texturecolumn = 0; // shut up compiler warning
-
for ( ; rw_x < rw_stopx ; rw_x++)
{
// mark floor / ceiling areas
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)
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
{
else if (backsector->floorheight > viewz)
{
ds_p->silhouette = SIL_BOTTOM;
- ds_p->bsilheight = MAXINT;
+ ds_p->bsilheight = INT_MAX;
// ds_p->sprbottomclip = negonearray;
}
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;
}
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++;
}
-// 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
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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.
#include "r_data.h"
-#ifdef __GNUG__
-#pragma implementation "r_sky.h"
-#endif
#include "r_sky.h"
//
-// 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"
void R_InitSkyMap (void);
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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__
-#ifdef __GNUG__
-#pragma interface
-#endif
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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"
char** check;
int i;
int l;
- int intname;
int frame;
int rotation;
int start;
// count the number of sprite names
check = namelist;
while (*check != NULL)
- check++;
+ check++;
numsprites = check-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';
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:
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;
}
}
}
else if (vis->mobjflags & MF_TRANSLATION)
{
- colfunc = R_DrawTranslatedColumn;
+ colfunc = transcolfunc;
dc_translation = translationtables - 256 +
( (vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT-8) );
}
// 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
// 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
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)
//
// 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;
-// 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
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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_t* sfxinfo;
+ 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;
}
}
{
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();
// 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;
-}
-
-
-
-
-// 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);
// 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
// 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);
//
// 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:$
-//
-//-----------------------------------------------------------------------------
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+//
+// 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__ */
+
-// 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"
// 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")
};
// 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),
};
-// 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[];
} sfxenum_t;
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-
-// 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"
void STlib_init(void)
{
- sttminus = (patch_t *) W_CacheLumpName("STTMINUS", PU_STATIC);
+ sttminus = (patch_t *) W_CacheLumpName(DEH_String("STTMINUS"), PU_STATIC);
}
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)
// 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);
}
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);
}
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)
{
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;
}
}
{
b->x = x;
b->y = y;
- b->oldval = 0;
+ b->oldval = false;
b->val = val;
b->on = on;
b->p = i;
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);
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;
}
-// 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
//
int y;
// last icon value
- int oldval;
+ boolean oldval;
// pointer to current icon status
boolean* val;
boolean refresh );
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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>
#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"
// 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;
// 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;
// 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);
//
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);
}
}
// 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)
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;
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;
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);
}
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);
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;
if (gamemode == commercial)
{
- epsd = 0;
+ epsd = 1;
map = (buf[0] - '0')*10 + buf[1] - '0';
}
else
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)))
&& ((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;
}
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;
}
-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;
// 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)
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);
}
+
-// 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)
} 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:$
-//
-//-----------------------------------------------------------------------------
--- /dev/null
+ /*
+
+ 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
+}
+
--- /dev/null
+ /*
+
+ 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 */
-// 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,
};
-int finesine[10240] =
+const int finesine[10240] =
{
25,75,125,175,226,276,326,376,
427,477,527,578,628,678,728,779,
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,
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
+ }
+};
+
-// 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
// 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:$
-//
-//-----------------------------------------------------------------------------
+
--- /dev/null
+//
+// 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
+
-// 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");
}
V_MarkRect (x, y, width, height);
- dest = screens[scrn] + y*SCREENWIDTH+x;
+ dest = dest_screen + y * SCREENWIDTH + x;
while (height--)
{
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);
+}
+
-// 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:$
-//
-//-----------------------------------------------------------------------------
+
--- /dev/null
+//
+// 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);
+}
+
--- /dev/null
+//
+// 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 */
+
--- /dev/null
+//
+// 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);
+}
+
--- /dev/null
+//
+// 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__ */
--- /dev/null
+//
+// 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,
+};
+
+
--- /dev/null
+//
+// 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,
+};
+
+
--- /dev/null
+//
+// 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;
+}
+
--- /dev/null
+//
+// 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 */
+
--- /dev/null
+//
+// 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 */
+
-// 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.
// 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;
}
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;
}
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;
}
// 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;
}
// 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 ();
}
//
// 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;
}
//
// 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
for (i=0 ; i<numlumps ; i++)
{
- ptr = lumpcache[i];
+ ptr = lumpinfo[i].cache;
if (!ptr)
{
ch = ' ';
info[i][profilecount] = ch;
}
profilecount++;
-
+#if ORIGCODE
f = fopen ("waddump.txt","w");
name[8] = 0;
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));
+ }
+ }
+ }
+}
+
-// 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:$
-//
-//-----------------------------------------------------------------------------
-// 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"
// 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] =
//
// Locally used stuff.
//
-#define FB 0
-
// States for single-player
#define SP_KILLS 0
// 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;
static patch_t* frags;
// Time sucks.
-static patch_t* time;
+static patch_t* timepatch;
static patch_t* par;
static patch_t* sucks;
// 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
{
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);
+ }
}
// 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]);
}
{
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
{
int i;
anim_t* a;
- if (commercial)
+ if (gamemode == commercial)
return;
if (wbs->epsd > 2)
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]);
}
}
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;
if (p < 0)
return;
- V_DrawPatch(x, y, FB, percent);
+ V_DrawPatch(x, y, percent);
WI_drawNum(x, y, p, -1);
}
// 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);
}
}
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();
}
// 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)
int x;
int y;
int w;
-
- //int lh; // line height
-
- //lh = WI_SPACINGY;
WI_slamBackground();
// 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;
{
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;
// 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);
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;
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);
}
}
-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++)
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];
}
}
}
}
// 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)
void WI_Start(wbstartstruct_t* wbstartstruct)
{
-
WI_initVariables(wbstartstruct);
WI_loadData();
-// 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__
{
NoState = -1,
StatCount,
- ShowNextLoc
-
+ ShowNextLoc,
} stateenum_t;
// Called by main loop, animate the intermission.
// Setup for an intermission screen.
void WI_Start(wbstartstruct_t* wbstartstruct);
+// Shut down the intermission screen
+void WI_End(void);
+
#endif
-//-----------------------------------------------------------------------------
-//
-// $Log:$
-//
-//-----------------------------------------------------------------------------
-// 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"
//
// 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
{
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);
}
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);
}
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;
}
}
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
// 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
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;
}
next = block->next;
// free block?
- if (!block->user)
+ if (block->tag == PU_FREE)
continue;
if (block->tag >= lowtag && block->tag <= hightag)
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");
}
}
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");
}
}
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");
}
}
//
// 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;
+}
+
//
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;
+}
+
-// 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.
// 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);
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:$
-//
-//-----------------------------------------------------------------------------