diff --git a/frosted-doom/CVS/Entries b/frosted-doom/CVS/Entries deleted file mode 100644 index f1f4112..0000000 --- a/frosted-doom/CVS/Entries +++ /dev/null @@ -1,109 +0,0 @@ -/ChangeLog/1.14/Mon Feb 3 22:45:08 1997// -/DOOMLIC.TXT/1.3/Sun Jan 26 07:44:56 1997// -/FILES/1.1/Sun Jan 19 17:22:41 1997// -/FILES2/1.1/Sun Jan 19 17:22:42 1997// -/Makefile/1.6/Mon Feb 3 22:45:08 1997// -/am_data.h/1.2/Tue Jan 21 18:59:56 1997// -/am_map.c/1.4/Mon Feb 3 21:24:33 1997// -/am_map.h/1.2/Tue Jan 21 18:59:56 1997// -/d_englsh.h/1.1/Mon Feb 3 21:48:03 1997// -/d_event.h/1.2/Mon Feb 3 22:01:47 1997// -/d_french.h/1.3/Mon Feb 3 21:48:03 1997// -/d_main.c/1.8/Mon Feb 3 22:45:09 1997// -/d_net.c/1.3/Mon Feb 3 22:01:47 1997// -/d_textur.h/1.1/Mon Feb 3 16:47:51 1997// -/doomdata.h/1.5/Mon Feb 3 22:45:09 1997// -/doomdef.h/1.9/Mon Feb 3 22:45:09 1997// -/doomtype.h/1.2/Mon Feb 3 22:45:09 1997// -/dstrings.h/1.4/Mon Feb 3 21:48:03 1997// -/dutils.c/1.5/Mon Feb 3 17:11:23 1997// -/dutils.h/1.4/Mon Feb 3 17:11:23 1997// -/f_finale.c/1.5/Mon Feb 3 21:26:34 1997// -/f_finale.h/1.1/Mon Feb 3 21:26:34 1997// -/f_wipe.c/1.2/Mon Feb 3 22:45:09 1997// -/f_wipe.h/1.1/Mon Feb 3 17:11:23 1997// -/fpfunc.S/1.1/Sun Jan 19 17:22:43 1997// -/g_game.c/1.8/Mon Feb 3 22:45:09 1997// -/g_game.h/1.1/Mon Feb 3 21:34:47 1997// -/hu_lib.c/1.3/Sun Jan 26 07:44:58 1997// -/hu_lib.h/1.4/Mon Feb 3 16:47:52 1997// -/hu_stuff.c/1.4/Mon Feb 3 16:47:52 1997// -/hu_stuff.h/1.3/Sun Jan 26 07:44:58 1997// -/i_dga.c/1.3/Sun Jan 26 07:44:58 1997// -/i_ibm.c/1.3/Sun Jan 26 07:44:58 1997// -/i_main.c/1.4/Mon Feb 3 22:45:10 1997// -/i_pcnet.c/1.3/Sun Jan 26 07:44:59 1997// -/i_sound.c/1.3/Sun Jan 26 07:44:59 1997// -/i_sound.h/1.3/Sun Jan 26 07:44:59 1997// -/i_svga.c/1.3/Sun Jan 26 07:44:59 1997// -/i_unix.c/1.5/Mon Feb 3 22:45:10 1997// -/i_x.c/1.6/Mon Feb 3 22:45:10 1997// -/info.c/1.3/Sun Jan 26 07:45:00 1997// -/info.h/1.3/Sun Jan 26 07:45:00 1997// -/irix.c/1.3/Sun Jan 26 07:45:00 1997// -/irix.h/1.3/Sun Jan 26 07:45:01 1997// -/linux.c/1.3/Sun Jan 26 07:45:01 1997// -/m_argv.c/1.1/Mon Feb 3 22:45:10 1997// -/m_argv.h/1.1/Mon Feb 3 22:45:10 1997// -/m_bbox.c/1.1/Mon Feb 3 22:45:10 1997// -/m_bbox.h/1.1/Mon Feb 3 22:45:10 1997// -/m_cheat.c/1.1/Mon Feb 3 21:24:34 1997// -/m_cheat.h/1.1/Mon Feb 3 21:24:34 1997// -/m_menu.c/1.7/Mon Feb 3 22:45:10 1997// -/m_menu.h/1.1/Mon Feb 3 22:01:49 1997// -/m_misc.c/1.6/Mon Feb 3 22:45:10 1997// -/m_misc.h/1.1/Mon Feb 3 22:45:11 1997// -/m_random.c/1.1/Mon Feb 3 22:45:11 1997// -/m_random.h/1.1/Mon Feb 3 22:45:11 1997// -/p_ceilng.c/1.4/Mon Feb 3 16:47:53 1997// -/p_doors.c/1.4/Mon Feb 3 16:47:53 1997// -/p_enemy.c/1.5/Mon Feb 3 22:45:11 1997// -/p_floor.c/1.4/Mon Feb 3 16:47:54 1997// -/p_inter.c/1.4/Mon Feb 3 22:45:11 1997// -/p_lights.c/1.5/Mon Feb 3 22:45:11 1997// -/p_local.h/1.3/Tue Jan 28 22:08:27 1997// -/p_map.c/1.5/Mon Feb 3 22:45:11 1997// -/p_maputl.c/1.5/Mon Feb 3 22:45:11 1997// -/p_mobj.c/1.5/Mon Feb 3 22:45:12 1997// -/p_plats.c/1.5/Mon Feb 3 22:45:12 1997// -/p_pspr.c/1.5/Mon Feb 3 22:45:12 1997// -/p_setup.c/1.5/Mon Feb 3 22:45:12 1997// -/p_sight.c/1.3/Tue Jan 28 22:08:28 1997// -/p_spec.c/1.6/Mon Feb 3 22:45:12 1997// -/p_spec.h/1.3/Tue Jan 28 22:08:29 1997// -/p_switch.c/1.3/Tue Jan 28 22:08:29 1997// -/p_telept.c/1.3/Tue Jan 28 22:08:29 1997// -/p_tick.c/1.4/Mon Feb 3 16:47:55 1997// -/p_user.c/1.3/Tue Jan 28 22:08:29 1997// -/r_bsp.c/1.4/Mon Feb 3 22:45:12 1997// -/r_data.c/1.4/Mon Feb 3 16:47:55 1997// -/r_draw.c/1.4/Mon Feb 3 16:47:55 1997// -/r_local.h/1.4/Mon Feb 3 21:26:34 1997// -/r_main.c/1.5/Mon Feb 3 22:45:12 1997// -/r_plane.c/1.4/Mon Feb 3 16:47:55 1997// -/r_segs.c/1.3/Wed Jan 29 20:10:19 1997// -/r_things.c/1.5/Mon Feb 3 16:47:56 1997// -/s_sound.c/1.6/Mon Feb 3 22:45:12 1997// -/sounds.c/1.3/Wed Jan 29 22:40:44 1997// -/sounds.h/1.3/Wed Jan 29 22:40:44 1997// -/soundsrv.c/1.3/Wed Jan 29 22:40:44 1997// -/soundsrv.h/1.3/Wed Jan 29 22:40:44 1997// -/soundst.h/1.3/Wed Jan 29 22:40:45 1997// -/st_lib.c/1.4/Mon Feb 3 16:47:56 1997// -/st_lib.h/1.4/Mon Feb 3 16:47:56 1997// -/st_stuff.c/1.6/Mon Feb 3 22:45:13 1997// -/st_stuff.h/1.3/Thu Jan 30 19:54:22 1997// -/sun.c/1.3/Thu Jan 30 19:54:22 1997// -/tables.c/1.4/Mon Feb 3 16:47:57 1997// -/tables.h/1.1/Mon Feb 3 16:47:57 1997// -/tmap.S/1.1/Sun Jan 19 17:22:51 1997// -/v_video.c/1.5/Mon Feb 3 22:45:13 1997// -/v_video.h/1.2/Mon Feb 3 17:11:59 1997// -/w_wad.c/1.5/Mon Feb 3 16:47:57 1997// -/wadread.c/1.3/Thu Jan 30 19:54:23 1997// -/wadread.h/1.3/Thu Jan 30 19:54:23 1997// -/wi_data.h/1.3/Thu Jan 30 19:54:23 1997// -/wi_stuff.c/1.7/Mon Feb 3 22:45:13 1997// -/wi_stuff.h/1.4/Mon Feb 3 16:47:58 1997// -/z_zone.c/1.4/Mon Feb 3 16:47:58 1997// -/z_zone.h/1.1/Mon Feb 3 16:47:58 1997// diff --git a/frosted-doom/CVS/Repository b/frosted-doom/CVS/Repository deleted file mode 100644 index fa03d7f..0000000 --- a/frosted-doom/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -/info/cvsroot/id/id_doom diff --git a/frosted-doom/CVS/Root b/frosted-doom/CVS/Root deleted file mode 100644 index 41613f0..0000000 --- a/frosted-doom/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -/info/cvsroot/ diff --git a/frosted-doom/ChangeLog b/frosted-doom/ChangeLog deleted file mode 100644 index 717db2e..0000000 --- a/frosted-doom/ChangeLog +++ /dev/null @@ -1,922 +0,0 @@ - - - - * TODO: see below, and in the "TODO" file. Enjoy! - -Mon Dec 22 20:29:16 1997 - - * 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 - - - * 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 - - * 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 - - * 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 - - * 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 - - * 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 - - * 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 - - * 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 - - * 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 - - * 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 - - * 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 - - * 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 - - * 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 - - * 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 - - * 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 - - * 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(...)' - -Wed Jan 22 12:15:00 1997 - - * 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' - - 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' - 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' - 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' - warning: implicit declaration of function `close' - - 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' - - 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' - - w_wad.c: In function `strupr': - warning: implicit declaration of function `toupper' - w_wad.c: In function `W_AddFile': - warning: implicit declaration of function `read' - warning: implicit declaration of function `lseek' - warning: implicit declaration of function `close' - - 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 - - * 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 - - * 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 - - * 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 - - * r_draw.c: - fixed !defined(USEASM) lines for R_DrawColumn/Span. - Removed fpfunc.o/S from Makefile, now compiling - X11 w/o any assembler. - Got a running linuxxdoom again. We are in business. - This source is going to be used for the initial CVS - check in. - - * Tried a quick hack compiling it as COFF a.out instead - of ELF, with "gcc -b i486-linuxaout". Same linker - errors. - Tried removing -DUSE_ASM. Still using fpfunc.S. - - - * Tried linuxxdoom. - Compile run: some warnings (redefinition of MAX/MIN - SHORT/INT/LONG) in doomdef.h and (PI redefined) - r_local.h. - Link run: crashed, undefined references in - d_main.c: undefined reference to `FixedDiv2' - am_map.c: undefined reference to `FixedMul' - r_main.c: undefined reference to `R_DrawColumn' - r_main.c: undefined reference to `R_DrawSpan' - r_plane.c: undefined reference to `FixedMul' - - This stuff is defined in fpfunc.S (Fixed point) and - in r_draw.c (assembler in tmap.S not used). - However, "nm," shows that r_draw.o does not include - the drawing functions (see below - USE_ASM). - Furthermore, the global symbols in fpfunc.S begin - with an underscore, "_FixedMul" and "_FixedDiv2". - - More problems within fpfunc.o: undefined references to - - `_dc_yl' `_dc_yh' - `_ylookup' - `_centery' - `_dc_x' - `_columnofs' - `_dc_iscale' - `_dc_texturemid' - `_dc_source' - `_dc_colormap' - - `_ds_y' `_ds_x1' `_ds_x2' - `_ds_xfrac' `_ds_yfrac' - `_ds_xstep' `_ds_ystep' - `_ds_colormap' - `_ds_source' - - Again, underscore problem. - Note: tmap.S currently obsolete, as somebody pasted all - the texture mapping assembly into fpfunc.S. Gotta clean - that up. - - * Created initial release from CD sources, created ChangeLog. - Let the games begin. - - - ************************************************************** - DOOM source code ChangeLog file - ************************************************************** - diff --git a/frosted-doom/DOOMLIC.TXT b/frosted-doom/DOOMLIC.TXT deleted file mode 100644 index 2b2252e..0000000 --- a/frosted-doom/DOOMLIC.TXT +++ /dev/null @@ -1,112 +0,0 @@ - - - LIMITED USE SOFTWARE LICENSE AGREEMENT - - This Limited Use Software License Agreement (the "Agreement") -is a legal agreement between you, the end-user, and Id Software, Inc. -("ID"). By downloading or purchasing the software material, which -includes source code (the "Source Code"), artwork data, music and -software tools (collectively, the "Software"), you are agreeing to -be bound by the terms of this Agreement. If you do not agree to the -terms of this Agreement, promptly destroy the Software you may have -downloaded or copied. - -ID SOFTWARE LICENSE - -1. Grant of License. ID grants to you the right to use the -Software. You have no ownership or proprietary rights in or to the -Software, or the Trademark. For purposes of this section, "use" means -loading the Software into RAM, as well as installation on a hard disk -or other storage device. The Software, together with any archive copy -thereof, shall be destroyed when no longer used in accordance with -this Agreement, or when the right to use the Software is terminated. -You agree that the Software will not be shipped, transferred or -exported into any country in violation of the U.S. Export -Administration Act (or any other law governing such matters) and that -you will not utilize, in any other manner, the Software in violation -of any applicable law. - -2. Permitted Uses. For educational purposes only, you, the -end-user, may use portions of the Source Code, such as particular -routines, to develop your own software, but may not duplicate the -Source Code, except as noted in paragraph 4. The limited right -referenced in the preceding sentence is hereinafter referred to as -"Educational Use." By so exercising the Educational Use right you -shall not obtain any ownership, copyright, proprietary or other -interest in or to the Source Code, or any portion of the Source -Code. You may dispose of your own software in your sole discretion. -With the exception of the Educational Use right, you may not -otherwise use the Software, or an portion of the Software, which -includes the Source Code, for commercial gain. - -3. Prohibited Uses: Under no circumstances shall you, the -end-user, be permitted, allowed or authorized to commercially exploit -the Software. Neither you nor anyone at your direction shall do any -of the following acts with regard to the Software, or any portion -thereof: - - Rent; - - Sell; - - Lease; - - Offer on a pay-per-play basis; - - Distribute for money or any other consideration; or - - In any other manner and through any medium whatsoever -commercially exploit or use for any commercial purpose. - -Notwithstanding the foregoing prohibitions, you may commercially -exploit the software you develop by exercising the Educational Use -right, referenced in paragraph 2. hereinabove. - -4. Copyright. The Software and all copyrights related thereto -(including all characters and other images generated by the Software -or depicted in the Software) are owned by ID and is protected by -United States copyright laws and international treaty provisions. -Id shall retain exclusive ownership and copyright in and to the -Software and all portions of the Software and you shall have no -ownership or other proprietary interest in such materials. You must -treat the Software like any other copyrighted material. You may not -otherwise reproduce, copy or disclose to others, in whole or in any -part, the Software. You may not copy the written materials -accompanying the Software. You agree to use your best efforts to -see that any user of the Software licensed hereunder complies with -this Agreement. - -5. NO WARRANTIES. ID DISCLAIMS ALL WARRANTIES, BOTH EXPRESS -IMPLIED, INCLUDING BUT NOT LIMITED TO, IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE WITH RESPECT -TO THE SOFTWARE. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL -RIGHTS. YOU MAY HAVE OTHER RIGHTS WHICH VARY FROM JURISDICTION TO -JURISDICTION. ID DOES NOT WARRANT THAT THE OPERATION OF THE SOFTWARE -WILL BE UNINTERRUPTED, ERROR FREE OR MEET YOUR SPECIFIC REQUIREMENTS. -THE WARRANTY SET FORTH ABOVE IS IN LIEU OF ALL OTHER EXPRESS -WARRANTIES WHETHER ORAL OR WRITTEN. THE AGENTS, EMPLOYEES, -DISTRIBUTORS, AND DEALERS OF ID ARE NOT AUTHORIZED TO MAKE -MODIFICATIONS TO THIS WARRANTY, OR ADDITIONAL WARRANTIES ON BEHALF -OF ID. - - Exclusive Remedies. The Software is being offered to you -free of any charge. You agree that you have no remedy against ID, its -affiliates, contractors, suppliers, and agents for loss or damage -caused by any defect or failure in the Software regardless of the form -of action, whether in contract, tort, includinegligence, strict -liability or otherwise, with regard to the Software. This Agreement -shall be construed in accordance with and governed by the laws of the -State of Texas. Copyright and other proprietary matters will be -governed by United States laws and international treaties. IN ANY -CASE, ID SHALL NOT BE LIABLE FOR LOSS OF DATA, LOSS OF PROFITS, LOST -SAVINGS, SPECIAL, INCIDENTAL, CONSEQUENTIAL, INDIRECT OR OTHER -SIMILAR DAMAGES ARISING FROM BREACH OF WARRANTY, BREACH OF CONTRACT, -NEGLIGENCE, OR OTHER LEGAL THEORY EVEN IF ID OR ITS AGENT HAS BEEN -ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY -OTHER PARTY. Some jurisdictions do not allow the exclusion or -limitation of incidental or consequential damages, so the above -limitation or exclusion may not apply to you. - - - - diff --git a/frosted-doom/FILES b/frosted-doom/FILES deleted file mode 100644 index 33af95d..0000000 --- a/frosted-doom/FILES +++ /dev/null @@ -1,98 +0,0 @@ -total 1258 --rw-r--r-- 1 b1 prog 0 Jan 18 15:08 FILES --rw-r--r-- 1 b1 prog 5799 Jan 18 15:07 Makefile --rw-r--r-- 1 b1 prog 1943 Jan 18 15:07 am_data.h --rw-r--r-- 1 b1 prog 20263 Jan 18 15:07 am_map.c --rw-r--r-- 1 b1 prog 2494 Jan 18 15:07 am_map.h --rw-r--r-- 1 b1 prog 1499 Jan 18 15:07 am_oids.c --rw-r--r-- 1 b1 prog 338 Jan 18 15:07 am_oids.h --rw-r--r-- 1 b1 prog 14005 Jan 18 15:07 d_french.h --rw-r--r-- 1 b1 prog 25287 Jan 18 15:07 d_main.c --rw-r--r-- 1 b1 prog 15586 Jan 18 15:07 d_net.c --rw-r--r-- 1 b1 prog 744 Jan 18 15:07 defs.inc --rw-r--r-- 1 b1 prog 3569 Jan 18 15:07 dither.c --rw-r--r-- 1 b1 prog 355 Jan 18 15:07 dither.h --rw-r--r-- 1 b1 prog 4234 Jan 18 15:07 doomdata.h --rw-r--r-- 1 b1 prog 32779 Jan 18 15:07 doomdef.h --rw-r--r-- 1 b1 prog 192 Jan 18 15:07 drcoord.h --rw-r--r-- 1 b1 prog 22377 Jan 18 15:07 dstrings.h --rw-r--r-- 1 b1 prog 6582 Jan 18 15:07 dutils.c --rw-r--r-- 1 b1 prog 1821 Jan 18 15:07 dutils.h --rw-r--r-- 1 b1 prog 14072 Jan 18 15:07 f_finale.c --rw-r--r-- 1 b1 prog 7357 Jan 18 15:07 fpfunc.S --rw-r--r-- 1 b1 prog 34770 Jan 18 15:07 g_game.c --rw-r--r-- 1 b1 prog 5394 Jan 18 15:07 hu_lib.c --rw-r--r-- 1 b1 prog 2878 Jan 18 15:07 hu_lib.h --rw-r--r-- 1 b1 prog 12040 Jan 18 15:07 hu_stuff.c --rw-r--r-- 1 b1 prog 934 Jan 18 15:07 hu_stuff.h --rw-r--r-- 1 b1 prog 6238 Jan 18 15:07 i_cyber.c --rw-r--r-- 1 b1 prog 18324 Jan 18 15:07 i_dga.c --rw-r--r-- 1 b1 prog 2499 Jan 18 15:07 i_header.h --rw-r--r-- 1 b1 prog 32815 Jan 18 15:07 i_ibm.c --rw-r--r-- 1 b1 prog 1867 Jan 18 15:07 i_ibm_a.asm --rw-r--r-- 1 b1 prog 121 Jan 18 15:07 i_main.c --rw-r--r-- 1 b1 prog 8251 Jan 18 15:07 i_pcnet.c --rw-r--r-- 1 b1 prog 8561 Jan 18 15:07 i_sound.c --rw-r--r-- 1 b1 prog 439 Jan 18 15:07 i_sound.h --rw-r--r-- 1 b1 prog 9537 Jan 18 15:07 i_svgalib.c --rw-r--r-- 1 b1 prog 10886 Jan 18 15:07 i_unix.c --rw-r--r-- 1 b1 prog 20891 Jan 18 15:07 i_x.c --rw-r--r-- 1 b1 prog 128797 Jan 18 15:07 info.c --rw-r--r-- 1 b1 prog 15840 Jan 18 15:07 info.h --rw-r--r-- 1 b1 prog 3477 Jan 18 15:07 irix.c --rw-r--r-- 1 b1 prog 240 Jan 18 15:07 irix.h --rw-r--r-- 1 b1 prog 1363 Jan 18 15:07 linux.c --rw-r--r-- 1 b1 prog 34628 Jan 18 15:07 m_menu.c --rw-r--r-- 1 b1 prog 13741 Jan 18 15:07 m_misc.c --rw-r--r-- 1 b1 prog 6117 Jan 18 15:07 p_ceilng.c --rw-r--r-- 1 b1 prog 15062 Jan 18 15:07 p_doors.c --rw-r--r-- 1 b1 prog 33758 Jan 18 15:07 p_enemy.c --rw-r--r-- 1 b1 prog 11409 Jan 18 15:07 p_floor.c --rw-r--r-- 1 b1 prog 16265 Jan 18 15:07 p_inter.c --rw-r--r-- 1 b1 prog 7592 Jan 18 15:07 p_lights.c --rw-r--r-- 1 b1 prog 6447 Jan 18 15:07 p_local.h --rw-r--r-- 1 b1 prog 30138 Jan 18 15:07 p_map.c --rw-r--r-- 1 b1 prog 14672 Jan 18 15:07 p_maputl.c --rw-r--r-- 1 b1 prog 17276 Jan 18 15:07 p_mobj.c --rw-r--r-- 1 b1 prog 5940 Jan 18 15:07 p_plats.c --rw-r--r-- 1 b1 prog 17084 Jan 18 15:07 p_pspr.c --rw-r--r-- 1 b1 prog 12828 Jan 18 15:07 p_setup.c --rw-r--r-- 1 b1 prog 5962 Jan 18 15:07 p_sight.c --rw-r--r-- 1 b1 prog 23846 Jan 18 15:07 p_spec.c --rw-r--r-- 1 b1 prog 11140 Jan 18 15:07 p_spec.h --rw-r--r-- 1 b1 prog 14229 Jan 18 15:07 p_switch.c --rw-r--r-- 1 b1 prog 1910 Jan 18 15:07 p_telept.c --rw-r--r-- 1 b1 prog 14075 Jan 18 15:07 p_tick.c --rw-r--r-- 1 b1 prog 7044 Jan 18 15:07 p_user.c --rw-r--r-- 1 b1 prog 13013 Jan 18 15:07 planar.asm --rw-r--r-- 1 b1 prog 9811 Jan 18 15:07 r_bsp.c --rw-r--r-- 1 b1 prog 14619 Jan 18 15:07 r_data.c --rw-r--r-- 1 b1 prog 13591 Jan 18 15:07 r_draw.c --rw-r--r-- 1 b1 prog 11378 Jan 18 15:07 r_local.h --rw-r--r-- 1 b1 prog 14868 Jan 18 15:07 r_main.c --rw-r--r-- 1 b1 prog 7108 Jan 18 15:07 r_plane.c --rw-r--r-- 1 b1 prog 15420 Jan 18 15:07 r_segs.c --rw-r--r-- 1 b1 prog 18969 Jan 18 15:07 r_things.c --rw-r--r-- 1 b1 prog 12274 Jan 18 15:07 s_sound.c --rw-r--r-- 1 b1 prog 12812 Jan 18 15:07 sndserver.c --rw-r--r-- 1 b1 prog 141 Jan 18 15:07 sndserver.h --rw-r--r-- 1 b1 prog 5811 Jan 18 15:07 sounds.c --rw-r--r-- 1 b1 prog 2674 Jan 18 15:07 sounds.h --rw-r--r-- 1 b1 prog 3975 Jan 18 15:07 soundst.h --rw-r--r-- 1 b1 prog 3461 Jan 18 15:07 st_lib.c --rw-r--r-- 1 b1 prog 2254 Jan 18 15:07 st_lib.h --rw-r--r-- 1 b1 prog 22769 Jan 18 15:07 st_stuff.c --rw-r--r-- 1 b1 prog 4685 Jan 18 15:07 st_stuff.h --rw-r--r-- 1 b1 prog 1725 Jan 18 15:07 sun.c --rw-r--r-- 1 b1 prog 75 Jan 18 15:07 t.c --rw-r--r-- 1 b1 prog 114621 Jan 18 15:07 tables.c --rw-r--r-- 1 b1 prog 5485 Jan 18 15:07 tmap.S --rw-r--r-- 1 b1 prog 10904 Jan 18 15:07 v_video.c --rw-r--r-- 1 b1 prog 268 Jan 18 15:07 vgaview.h --rw-r--r-- 1 b1 prog 9920 Jan 18 15:07 w_wad.c --rw-r--r-- 1 b1 prog 3629 Jan 18 15:07 wadread.c --rw-r--r-- 1 b1 prog 551 Jan 18 15:07 wadread.h --rw-r--r-- 1 b1 prog 3583 Jan 18 15:07 wi_data.h --rw-r--r-- 1 b1 prog 25608 Jan 18 15:07 wi_stuff.c --rw-r--r-- 1 b1 prog 1544 Jan 18 15:07 wi_stuff.h --rw-r--r-- 1 b1 prog 8501 Jan 18 15:07 z_zone.c diff --git a/frosted-doom/FILES2 b/frosted-doom/FILES2 deleted file mode 100644 index 066a4ef..0000000 --- a/frosted-doom/FILES2 +++ /dev/null @@ -1,221 +0,0 @@ -ChangeLog -FILES -FILES2 -Makefile - ------------------------------------------------------------------------ -Global and misc. stuff ------------------------------------------------------------------------ -doomdata.h - external data definitions (WAD file structure) -doomdef.h - internal data definitions (game structs) -dstrings.h - printed strings for translation, english -d_french.h - printed strings for translation - -info.h -info.c - LUT's for Thing TAB, Frame TAB, - generated by multigen utility -dutils.h -dutils.c - Dave's utilities - including doubly-linked lists & simple state machines. - Used in WI, ST, AM, and d_main.c - ------------------------------------------------------------------------- -DOOM game loop and top level stuff ------------------------------------------------------------------------- -g_game.c - Game loop functions, event handling etc. - - boolean G_CheckDemoStatus (void); - void G_ReadDemoTiccmd (ticcmd_t *cmd); - void G_WriteDemoTiccmd (ticcmd_t *cmd); - void G_PlayerReborn (int player); - void G_InitNew (skill_t skill, int episode, int map); - - void G_DoReborn (int playernum); - - void G_DoLoadLevel (void); - void G_DoNewGame (void); - void G_DoLoadGame (void); - void G_DoPlayDemo (void); - void G_DoCompleted (void); - void G_DoVictory (void); - void G_DoWorldDone (void); - void G_DoSaveGame (void); - -d_main.c - event handling, D_DoomMain() and other functions - NOT int main() - -d_net.c - high level networking protocol code - ------------------------------------------------------------------- -I Interfaces, system specifics ------------------------------------------------------------------- -i_main.c - main(), calls D_DoomMain(). -i_svgalib.c - Linux SVGAlib code, including main(), - replaces i_main.c - -i_x.c - X11 with SHM code, use with i_main.c -i_dga.c - X11 DGA code, use with i_main.c -i_unix.c - fixed point, networking, and display stuff for UNIX - -i_ibm.c - IBM DOS VGA graphics and key/mouse/joystick, - use with i_main.c -i_pcnet.c - IPX networking, DOS - -fpfunc.S - fixed point assembly and (currently) duplicate of -tmap.S - texture mapping assembly (currently unused) - ------------------------------------------------------------------- -AM AutoMap ------------------------------------------------------------------- -am_data.h - vector graphics for the automap - -am_map.h -am_map.c - automap code - ------------------------------------------------------------------- -HU Heads Up ------------------------------------------------------------------- -hu_lib.h -hu_lib.c - heads-up text and input code - -hu_stuff.h -hu_stuff.c - Heads-up displays - - -------------------------------------------------------------------- -M Menu -------------------------------------------------------------------- -m_menu.c - DOOM options code and leaving messages - -m_misc.c - misc. HUD text display, input checks, and - random table, file I/O - - -------------------------------------------------------------------- -P Play??? -------------------------------------------------------------------- -p_local.h - header for all play modules - -p_spec.h - specials, lighting, doors, plats, texture animation -p_spec.c - specials, texture animation - -p_doors.c - door code -p_plats.c - platform raising/lowering code -p_ceilng.c - active (e.g. crushing) ceilings -p_floor.c - active (e.g. raising) floors -p_lights.c - dynamic (e.g. flickering) lighting -p_switch.c - button switches and animation - -p_enemy.c - enemy AI and animation -p_inter.c - object/object interaction? -p_map.c - movement objects, handling of collisions -p_maputl.c - distance, position etc. utilities for movement -p_mobj.c - mobile objects handling, spawn etc. -p_user.c - more movement, bobbing etc. - -p_telept.c - teleportation code - -p_sight.c - LOS checks, REJECT - - -p_pspr.c - weapon overlays, bobbing, raising, sprite tables, - firing, ammo bookkeeping - -p_setup.c - load map from WAF file, setup code - - -p_tick.c - savegame function (archive/unarchive), - thinker list handling, allocation, - game tick execution (updates) - - -------------------------------------------------------------------- -R Rendering -------------------------------------------------------------------- -r_local.h - header for all rendering modules, - internal map data structure definitions - -r_bsp.c - BSP seg's clipping - -r_data.c - texture column caching, patch assembly, - flats, colormaps, sprites, - lookup by name - -r_draw.c - access to framebuffer API, drawing C functions - - -r_main.c - geometry functions, trigonometry lookups, - R_RenderPlayerView - -r_plane.c - floor/ceiling visplanes, sky - -r_segs.c - drawing segs, marking hslices for floors/ceilings - -r_things.c - sprite and sprite frame/rotation handling, drawing - - -tables.c - trigonometry lookup tables, static - -v_video.c - gamma correction lookup, patch drawing to rectangle - -------------------------------------------------------------------- -S Sound -------------------------------------------------------------------- -s_sound.c - more sound and music handling - -soundst.h - sound and music data structures -sounds.h -sounds.c - sound and music lump LUT's (manually maintained) - -sndserver.h -sndserver.c - (Irix) sndserver code - -irix.h -irix.c - SGI Irix sound/sndserver support code - -linux.c - Linux voxware sound/sndserver support code, - replaces irix.c, uses irix.h -sun.c - SUN replacement for irix.c - - -i_sound.h -i_sound.c - DOS DMX music and sound interface - -------------------------------------------------------------------- -ST STatus bar -------------------------------------------------------------------- -st_lib.h -st_lib.c - status bar widget code - -st_stuff.c -st_stuff.h - status bar code - - -------------------------------------------------------------------- -W Wad file I/O -------------------------------------------------------------------- -w_wad.c - lump based functions -wadread.h -wadread.c - lump I/O, get SFX - -------------------------------------------------------------------- -WI WIn / level end screens -------------------------------------------------------------------- -wi_data.h - lookups for intermission screens, patch positions - -wi_stuff.h -wi_stuff.c - intermission animation patchwork - -------------------------------------------------------------------- -Z Zone memory allocation -------------------------------------------------------------------- -z_zone.c - -------------------------------------------------------------------- -F Final screen animation -------------------------------------------------------------------- -f_finale.c - DOOM mission end screens? (bunny) - - - -------------------------------------------------------------------- diff --git a/frosted-doom/Makefile b/frosted-doom/Makefile index 8bb5bef..038ae01 100644 --- a/frosted-doom/Makefile +++ b/frosted-doom/Makefile @@ -15,7 +15,7 @@ endif ifeq ($(ARM),1) CROSS_COMPILE = arm-frosted-eabi- - OBJS+=$(O)/i_video_fbdev.o + OBJS+=$(OBJDIR)/i_video_fbdev.o CFLAGS+=-mthumb -mlittle-endian -mthumb-interwork -ffunction-sections -fdata-sections -mcpu=cortex-m3 CFLAGS+=-DCORE_M3 -D__frosted__ # COMPILER FLAGS -- No gcc libraries @@ -26,109 +26,51 @@ ifeq ($(ARM),1) LDFLAGS+=-fPIC -mlong-calls -fno-common -Wl,-elf2flt -lgloss else CFLAGS+=-m32 -fsanitize=address -Wunused-const-variable=0 - LIBS+=-lXext -lX11 -lnsl -lm -lSDL2 - OBJS+=$(O)/i_video_SDL.o + LIBS+=-lXext -lX11 -lnsl -lm -lSDL + OBJS+=$(OBJDIR)/i_video.o endif CC= $(CROSS_COMPILE)gcc # gcc or g++ - - -# Debugging -CFLAGS+=-ggdb3 +CFLAGS+=-ggdb3 -Os LDFLAGS+=-Wl,--gc-sections CFLAGS+=-ggdb3 -Wall -DNORMALUNIX -DLINUX -DSNDSERV # -DUSEASM -CFLAGS+=-Icompat LIBS+=-lm -lc -#LDFLAGS=-L/usr/X11R6/lib -#LIBS=-lXext -lX11 -lnsl -lm - # subdirectory for objects -O=frosted +OBJDIR=build +OUTPUT=fdoom -# not too sophisticated dependency -OBJS+= \ - $(O)/stubs.o \ - $(O)/doomdef.o \ - $(O)/doomstat.o \ - $(O)/dstrings.o \ - $(O)/i_system.o \ - $(O)/i_sound_dummy.o \ - $(O)/i_net.o \ - $(O)/tables.o \ - $(O)/f_finale.o \ - $(O)/f_wipe.o \ - $(O)/d_main.o \ - $(O)/d_net.o \ - $(O)/d_items.o \ - $(O)/g_game.o \ - $(O)/m_menu.o \ - $(O)/m_misc.o \ - $(O)/m_argv.o \ - $(O)/m_bbox.o \ - $(O)/m_fixed.o \ - $(O)/m_swap.o \ - $(O)/m_cheat.o \ - $(O)/m_random.o \ - $(O)/am_map.o \ - $(O)/p_ceilng.o \ - $(O)/p_doors.o \ - $(O)/p_enemy.o \ - $(O)/p_floor.o \ - $(O)/p_inter.o \ - $(O)/p_lights.o \ - $(O)/p_map.o \ - $(O)/p_maputl.o \ - $(O)/p_plats.o \ - $(O)/p_pspr.o \ - $(O)/p_setup.o \ - $(O)/p_sight.o \ - $(O)/p_spec.o \ - $(O)/p_switch.o \ - $(O)/p_mobj.o \ - $(O)/p_telept.o \ - $(O)/p_tick.o \ - $(O)/p_saveg.o \ - $(O)/p_user.o \ - $(O)/r_bsp.o \ - $(O)/r_data.o \ - $(O)/r_draw.o \ - $(O)/r_main.o \ - $(O)/r_plane.o \ - $(O)/r_segs.o \ - $(O)/r_sky.o \ - $(O)/r_things.o \ - $(O)/w_wad.o \ - $(O)/wi_stuff.o \ - $(O)/v_video.o \ - $(O)/st_lib.o \ - $(O)/st_stuff.o \ - $(O)/hu_stuff.o \ - $(O)/hu_lib.o \ - $(O)/s_sound.o \ - $(O)/z_zone.o \ - $(O)/info.o \ - $(O)/sounds.o +SRC_DOOM = i_main.o dummy.o am_map.o doomdef.o doomstat.o dstrings.o d_event.o d_items.o d_iwad.o d_loop.o d_main.o d_mode.o d_net.o f_finale.o f_wipe.o g_game.o hu_lib.o hu_stuff.o info.o i_cdmus.o i_endoom.o i_joystick.o i_scale.o i_sound.o i_system.o i_timer.o memio.o m_argv.o m_bbox.o m_cheat.o m_config.o m_controls.o m_fixed.o m_menu.o m_misc.o m_random.o p_ceilng.o p_doors.o p_enemy.o p_floor.o p_inter.o p_lights.o p_map.o p_maputl.o p_mobj.o p_plats.o p_pspr.o p_saveg.o p_setup.o p_sight.o p_spec.o p_switch.o p_telept.o p_tick.o p_user.o r_bsp.o r_data.o r_draw.o r_main.o r_plane.o r_segs.o r_sky.o r_things.o sha1.o sounds.o statdump.o st_lib.o st_stuff.o s_sound.o tables.o v_video.o wi_stuff.o w_checksum.o w_file.o w_file_stdc_unbuffered.o w_main.o w_wad.o z_zone.o +OBJS += $(addprefix $(OBJDIR)/, $(SRC_DOOM)) -all: $(O)/fdoom +all: $(OUTPUT) clean: - rm -f *.o *~ *.flc - rm -f frosted/*.o - rm -f frosted/fdoom + rm -rf $(OBJDIR) + rm -f $(OUTPUT) + rm -f $(OUTPUT).gdb + rm -f $(OUTPUT).map -$(O)/fdoom: $(OBJS) $(O)/i_main.o +$(OUTPUT): $(OBJS) @echo [Linking $@] - $(VB)$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(O)/i_main.o \ - -o $(O)/fdoom $(LIBS) -Wl,-Map,fdoom.map + $(VB)$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) \ + -o $(OUTPUT) $(LIBS) -Wl,-Map,$(OUTPUT).map + @echo [Size] + -$(CROSS_COMPILE)size $(OUTPUT) + -$(CROSS_COMPILE)flthdr $(OUTPUT) -$(O): - mkdir -p $(O) +$(OBJS): | $(OBJDIR) -$(O)/%.o: %.c $(O) +$(OBJDIR): + mkdir -p $(OBJDIR) + +$(OBJDIR)/%.o: %.c @echo [Compiling $<] $(VB)$(CC) $(CFLAGS) -c $< -o $@ +print: + @echo OBJS: $(OBJS) + ############################################################# # ############################################################# diff --git a/frosted-doom/README.asm b/frosted-doom/README.asm deleted file mode 100644 index 8962976..0000000 --- a/frosted-doom/README.asm +++ /dev/null @@ -1,283 +0,0 @@ - -README - DOOM assembly code - -Okay, I add the DOS assembly module for the historically -inclined here (may rec.games.programmer suffer). If anyone -feels the urge to port these to GNU GCC; either inline or -as separate modules including Makefile support, be my guest. - -Module tmap.S includes the inner loops for texture mapping, -the interesting one being the floor/ceiling span rendering. - -There was another module in the source dump, fpfunc.S, that -had both texture mapping and fixed point functions. It -contained implementations both for i386 and M68k. For -brevity, I include only the i386 fixed point stuff below. - -//==================================================== -// tmap.S as of January 10th, 1997 - -//================ -// -// R_DrawColumn -// -//================ - - .data -loopcount .long 0 -pixelcount .long 0 - - .text - - .align 16 -.globl _R_DrawColumn -_R_DrawColumn: - - pushad - - movl ebp,[_dc_yl] - movl ebx,ebp - movl edi,[_ylookup+ebx*4] - movl ebx,[_dc_x] - addl edi,[_columnofs + ebx*4] - - movl eax,[_dc_yh] - incl eax - subl eax,ebp // pixel count - movl [pixelcount],eax // save for final pixel - js done // nothing to scale - shrl eax,1 // double pixel count - movl [loopcount],eax - - movl ecx,[_dc_iscale] - - movl eax,[_centery] - subl eax,ebp - imull ecx - movl ebp,[_dc_texturemid] - subl ebp,eax - shll ebp,9 // 7 significant bits, 25 frac - - movl esi,[_dc_source] - - - movl ebx,[_dc_iscale] - shll ebx,9 - movl eax,OFFSET patch1+2 // convice tasm to modify code... - movl [eax],ebx - movl eax,OFFSET patch2+2 // convice tasm to modify code... - movl [eax],ebx - -// eax aligned colormap -// ebx aligned colormap -// ecx,edx scratch -// esi virtual source -// edi moving destination pointer -// ebp frac - - movl ecx,ebp // begin calculating first pixel - addl ebp,ebx // advance frac pointer - shrl ecx,25 // finish calculation for first pixel - movl edx,ebp // begin calculating second pixel - addl ebp,ebx // advance frac pointer - shrl edx,25 // finish calculation for second pixel - movl eax,[_dc_colormap] - movl ebx,eax - movb al,[esi+ecx] // get first pixel - movb bl,[esi+edx] // get second pixel - movb al,[eax] // color translate first pixel - movb bl,[ebx] // color translate second pixel - - testl [pixelcount],0fffffffeh - jnz doubleloop // at least two pixels to map - jmp checklast - - .align 16 -doubleloop: - movl ecx,ebp // begin calculating third pixel -patch1: - addl ebp,12345678h // advance frac pointer - movb [edi],al // write first pixel - shrl ecx,25 // finish calculation for third pixel - movl edx,ebp // begin calculating fourth pixel -patch2: - addl ebp,12345678h // advance frac pointer - movl [edi+SCREENWIDTH],bl // write second pixel - shrl edx,25 // finish calculation for fourth pixel - movb al,[esi+ecx] // get third pixel - addl edi,SCREENWIDTH*2 // advance to third pixel destination - movb bl,[esi+edx] // get fourth pixel - decl [loopcount] // done with loop? - movb al,[eax] // color translate third pixel - movb bl,[ebx] // color translate fourth pixel - jnz doubleloop - -// check for final pixel -checklast: - testl [pixelcount],1 - jz done - movb [edi],al // write final pixel - -done: - popad - ret - - - -//================ -// -// R_DrawSpan -// -// Horizontal texture mapping -// -//================ - - - .align 16 -.globl _R_DrawSpan -_R_DrawSpan: - pushad - -// -// find loop count -// - movl eax,[_ds_x2] - incl eax - subl eax,[_ds_x1] // pixel count - movl [pixelcount],eax // save for final pixel - js hdone // nothing to scale - shrl eax,1 // double pixel count - movl [loopcount],eax - -// -// build composite position -// - movl ebp,[_ds_xfrac] - shll ebp,10 - andl ebp,0ffff0000h - movl eax,[_ds_yfrac] - shrl eax,6 - andl eax,0ffffh - orl ebp,eax - - movl esi,[_ds_source] - -// -// calculate screen dest -// - movl edi,[_ds_y] - movl edi,[_ylookup+edi*4] - movl eax,[_ds_x1] - addl edi,[_columnofs+eax*4] - -// -// build composite step -// - movl ebx,[_ds_xstep] - shll ebx,10 - andl ebx,0ffff0000h - movl eax,[_ds_ystep] - shrl eax,6 - andl eax,0ffffh - orl ebx,eax - - movl eax,OFFSET hpatch1+2 // convice tasm to modify code... - movl [eax],ebx - movl eax,OFFSET hpatch2+2 // convice tasm to modify code... - movl [eax],ebx - -// eax aligned colormap -// ebx aligned colormap -// ecx,edx scratch -// esi virtual source -// edi moving destination pointer -// ebp frac - - shldl ecx,ebp,22 // begin calculating third pixel (y units) - shldl ecx,ebp,6 // begin calculating third pixel (x units) - addl ebp,ebx // advance frac pointer - andl ecx,4095 // finish calculation for third pixel - shldl edx,ebp,22 // begin calculating fourth pixel (y units) - shldl edx,ebp,6 // begin calculating fourth pixel (x units) - addl ebp,ebx // advance frac pointer - andl edx,4095 // finish calculation for fourth pixel - movl eax,[_ds_colormap] - movl ebx,eax - movb al,[esi+ecx] // get first pixel - movb bl,[esi+edx] // get second pixel - movb al,[eax] // color translate first pixel - movb bl,[ebx] // color translate second pixel - - testl [pixelcount],0fffffffeh - jnz hdoubleloop // at least two pixels to map - jmp hchecklast - - - .align 16 -hdoubleloop: - shldl ecx,ebp,22 // begin calculating third pixel (y units) - shldl ecx,ebp,6 // begin calculating third pixel (x units) -hpatch1: - addl ebp,12345678h // advance frac pointer - movb [edi],al // write first pixel - andl ecx,4095 // finish calculation for third pixel - shldl edx,ebp,22 // begin calculating fourth pixel (y units) - shldl edx,ebp,6 // begin calculating fourth pixel (x units) -hpatch2: - addl ebp,12345678h // advance frac pointer - movb [edi+1],bl // write second pixel - andl edx,4095 // finish calculation for fourth pixel - movb al,[esi+ecx] // get third pixel - addl edi,2 // advance to third pixel destination - movb bl,[esi+edx] // get fourth pixel - decl [loopcount] // done with loop? - movb al,[eax] // color translate third pixel - movb bl,[ebx] // color translate fourth pixel - jnz hdoubleloop - -// check for final pixel -hchecklast: - testl [pixelcount],1 - jz hdone - movb [edi],al // write final pixel - -hdone: - popad - ret - - - - -//==================================================== -// fpfunc.S as of January 10th, 1997 (parts) - -#ifdef i386 - -.text - .align 4 -.globl _FixedMul -_FixedMul: - pushl %ebp - movl %esp,%ebp - movl 8(%ebp),%eax - imull 12(%ebp) - shrdl $16,%edx,%eax - popl %ebp - ret - - - .align 4 -.globl _FixedDiv2 -_FixedDiv2: - pushl %ebp - movl %esp,%ebp - movl 8(%ebp),%eax - cdq - shldl $16,%eax,%edx - sall $16,%eax - idivl 12(%ebp) - popl %ebp - ret - -#endif - diff --git a/frosted-doom/README.b b/frosted-doom/README.b deleted file mode 100644 index 3d2fa2f..0000000 --- a/frosted-doom/README.b +++ /dev/null @@ -1,140 +0,0 @@ - -README for Linux DOOM Source distribution -========================================= - - -DISCLAIMER ----------- -This is not "The DOOM Source Code" dump for a bunch -of reasons. It is based on a DOOM development directory -snapshot as of January 10th, but has been stripped and -changed. Thus it is the DOOM source, but there are many -minor differences to the source as last used by id -Software. - -Note that thus neither John Carmack nor Dave Taylor nor -anybody else at id is responsible for the contents of -this archive, or the changes introduced to the original -source. - -If there are any questions, contact me at bk@gamers.org, -or preferably post to the mailing list at - - doom-editing@gamers.org - -(send mail to majordomo@gamers.org, content just -a single "info doom-editing"). I will post any updates -or notifcation of corrections there. I will probably -put some stuff at - - http://www.gamers.org/dEngine/doom/ - -as well. Look there for the "Unofficial DOOM Specs" as -minimal recommended documentation. - - - -REMARKS -------- -I made a few minor bug fixes, added some experimental sound -code, and, and changed the handling of IWAD dependend game -modes. Most of the changes though have been shuffling -around sources in a sometimes futile attempt to separate -modules more cleanly, and make certain parts easier -to locate and modify. There is still much left to do, but -I hope that the current source is a good base to start -with, especially with a cooperative effort in mind. Those -so inclined will find the source prepared for CVS. - -There is a list of changes and fixes I did not get around -to in TODO, and an incomplete worklog in ChangeLog, that -also includes some minor ToDo statements scattered throughout -the log. - - -a) Linux SVGA -There is no SVGA support. For development and debug -purposes, the X11 version seems to be more handy. - -b) Sound - see README.sound, - and the sndserver.tgz archive. - -c) GLDOOM - see README.gl - -d) Win32 -There was no Win32 support in the original dump. - -e) DOS -Original DOS support (including the texture -mapping and fixed point assembler) has been -removed, mainly because of the lack of sound -support. - -f) DoomEd -The NeXTStep DoomEd sources in the dump were -garbled (filenames - prolly an issue of ISO9660 -with or w/o extensions). Somehow Bear never got -around to send me a list of the correct filenames, -and I won't bother guessing without a NeXT box -at hand. - -There is a plethora of useful editors -for DOOM. I suggest using DEU for X11. - -g) BSP Tools -The BSP builder and other tools have -been released by John Carmack long ago, -and since improved/replaced by others. -Again, I recommend taking a pick among -the tools available for Linux. - -h) DOOM game tools -There are a number of tools that have -not been released, namely those which -compiled the Things and State Tables, -the frame animation LUT's, sound tables -etc. Basically, they compile similarly -complex LUT's to generate C files. The -tools are omitted from this distribution. - -There are some files in the -distribution (info.h/c, sounds.h/c) -that are essentially the output of these -tools. This is the data that defines -DOOM (as a game) for all practical -purposes. - -I recommend keeping them, as they are -part of the source. In the long run, -handling them as well as the action/ -animation functions as a separate game.so -library (as with Quake2) seems to be a -good idea. - -i) Artwork -Neither the original artwork nor the -misc. WAD files are included in this -archive. You will at least need the -shareware WAD file to run the executable, -but it shouldn't be to difficult to get -a hold of that. - -Note that the mechanism to detect the -presence of a registered or commercial -version is still in the source, and -homebrew maps are still disabled. This -is easily removed now, but as FinalDOOM, -Ultimate DOOM and DOOM 2 are still in -the shops, it is probably polite not -to distribute a source or binary without -that mechanism. - -This version of Linuxdoom supports Plutonia -and TNT WAD from FinalDOOM as well. No -guarantees, though. - - -Enjoy! - - - b. 97/12/22 diff --git a/frosted-doom/README.book b/frosted-doom/README.book deleted file mode 100644 index 0fe5949..0000000 --- a/frosted-doom/README.book +++ /dev/null @@ -1,57 +0,0 @@ - -The DOOM Book - -Shortly after the Wolfenstein 3D source release, -I sent a mail to Jay Wilbur suggesting a book -about the DOOM engine. I anticipated a similar -release of the DOOM sources within a year or -two, and the obvious problems with the Wolfenstein -sources (lack of accompanying artwork, a code -base not maintained for quite some time) seemed -to demand a better approach. I talked to some -publishing company reps at the Book Fair in 1995, -and while they were cautiously interested, id was -not. - -In the last weeks of 1996, following a visit at -id Software two months earlier, and after the -departure of Jay Wilbur, John Carmack asked me -whether I was still interested in doing the book. -I was, Bear sent me a code dump, and Todd -Hollenshead set out to address the legal concerns -(of which were many). - -Unfortunately, what might have worked in 1995 -turned out to be a doomed attempt in 1997. I won't -go into the details - let's just say that my -leaving university and going back to full time -writing for a living repeatedly forced me to -change priorities on what looked more and more -like a project unlikely to generate any revenue. - -By mid of the year, when the legal issues had -finally been settled, it didn't look like I was -going to find a publisher at all. Following the -Book Fair in 1997 and some more discussions -(with about a dozen publishers, total), I gritted -my teeth and decided to abandon the project. - -Note that the book project as such wasn't supposed -to hold up the source release to the public. -However, given the legal concerns relating to -the third party sound code in DOS DOOM, and the -lack of Win32 support as well as the advantages of -an OpenGL based release, the idea was to put -together a consistent, stable code base prior to -public release - most of which was supposed to be -an offspring of my reformatting and modifying the -code for the book. - -None of this worked out as intended. However, I -hope that, at long last, this distribution -will finally provide a good point to start for -any cooperative effort to extend the already -impressive lifespan of DOOM into the age of -multiplayer servers and hardware-accelerated -clients. - diff --git a/frosted-doom/README.gl b/frosted-doom/README.gl deleted file mode 100644 index df443a9..0000000 --- a/frosted-doom/README.gl +++ /dev/null @@ -1,149 +0,0 @@ - -README: glDOOM - -I never got around to do anything with respect to -a Linux glDOOM port except for assembling a Linux3Dfx -HOWTO (which, at that time, was a prerequisite -to get permission to publicly distribute the -already finished LinuxGlide port by Daryll Strauss). - -Linux q2test (and soon LinuxQuake2) demonstrate that -Mesa with the MesaVoodoo driver is quite up to the -requirements for a glDOOM port. If anybody wants to -get into Linux glDOOM, please drop me a line. - -There is a Win32 GLDOOM port in the works, by Jim Dose. -Quoting a recent posting by him: - -"I haven't had as much time lately to really work on -the conversion. I currently have the renderer drawing -the walls and floors as texture spans as the are in -the software renderer. There's lighting on the walls, -but not the floors, and sprites are being drawn, but -not with the right texture. I figure that this is one -nights work to get the game looking "normal". I haven't -tested the game on less than a p200, so I'm not sure -how it will perform under the average machine, but I -don't expect it to be blindingly fast because of the -number of spans that have to be drawn each frame. -Rendering as polys is definitely the way to go. - -The reason I chose to do spans first was because it -left the base renderer intact and I could concentrate -on ironing out any Windows compatibility problems. -Actually, the first version I had running was simply -a blit of the 320x200 game screen through Open GL. -Surprisingly, this actually was very playable, but -certainly wasn't taking any advantage of 3D acceleration. -Once the game was running, I started converting all -the span routines over." - -Comment: for merging Linuxdoom with Win32, this is -probably the best source for getting the Win32 -environment done - before more significant changes -occur. - -"One problem with drawing spans is that the engine -doesn't calculate the texture coordinates with -fractional accuracy, so the bilinear filtering works -vertically, but not horizontally on the walls. I may -try to fix this, but since I plan to use polys for -the final version, it's not really high priority. -Also, spans don't really allow for looking up and -down." - -Comment: true looking up/down vs. Heretic-style -y-shearing seems to require either a strange kind -of transofrmation matrix (he probably does not use -the OpenGL transformation at all), or rendering -all the spans as textured rectangular slices -instead of using glDrawBitmap. No, polys are the -way to go. - -"When I tackle the conversion to polys, one big problem -I'll encounter is drawing floors. Since the world is -stored in a 2D bsp tree, there is no information on -the shape of the floors. In fact the floors can be -concave and may include holes (typically, most renderers -break concave polys down into a collection of convex -polys or triangles). In software, the floors are actually -drawn using an algorithm that's similar to a flood fill -(except that a list of open spans is kept instead of a -buffer of pixels). This makes drawing the floors as -polys fairly difficult." - -A polygon based approach will require significant changes -to the data structures used in the refresh module. I -recommend either separating a libref_soft.so first (a -Quake2 like approach), and creating libref_gl afterwards, -or abandoning the software rendering entirely. - -John Carmack wrote once upon a time: -"... the U64 DOOM engine is much more what I would consider -The Right Thing now -- it turns the subsector boundaries -into polygons for the floors and ceilings ahead of time, -then for rendering it walks the BSP front to back, doing -visibility determination of subsectors by the one dimensional -occlusion buffer and clipping sprites into subsectors, then -it goes backwards through the visible subsectors, drawing -floors, ceilings, walls, then sorted internal sprite fragments. -It's a ton simpler and a ton faster, although it does suffer -some overdraw when a high subsector overlooks a low one (but -that is more than made up for by the simplicity of everything -else)." - -Well, IMO compiling a separate list of floor/ceiling polygons -after having read the WAD file, and thus introducing this as -a completely separate data structure to the current code base -might be the easiest thing to do. Jim Dose writes: - -"One method I may use to draw the floors as polys was suggested -by Billy Zelsnack of Rebel Boat Rocker when we were working -at 3D Realms together a few years ago. Basically, Billy was -designing an engine that dealt with the world in a 2D portal -format similar to the one that Build used, except that it had -true looking up and down (no shearing). Since floors were -basically implicit and could be concave, Billy drew them as -if the walls extended downwards to infinity, but fixed the -texture coordinates to appear that they were on the plane of -the floor. The effect was that you could look up and down and -there were no gaps or overdraw. It's a fairly clever method -and allows you to store the world in a simpler data format. -Had perspective texture mapping been fast enough back then, -both Build and Doom could have done this in software." - -Perhaps the above is sufficient to get you started. -Other Issues: - -1. Occlusion -DOOM uses a per-column lookup (top/bottom index) to do HLHSR. -This works fine with span based rendering (well, getting -horizontal spans of floors/ceilings into the picture is a -separate story). It isn't really mindboggling with polygon -based rendering. GLDOOM should abandon that. - -2. Precalculated Visibility -DOOM has the data used by Quake's PVS - in REJECT. -During Quake development, lots of replacements for the -occlusion buffer were tried, and PVS turned out to be best. -I suggest usind the REJECT as PVS. - -There have been special effects using a utility named RMB. -REJECT is a lump meant for enemy AI LoS calculation - a -nonstandard REJECT will not work as a PVS, and introduce -rendering errors. I suggest looking for a PVS lump in the -WAD, and using REJECT if none is found. That way, it might -be feasible to eat the cake and keep it. - -3. Mipmaps -DOOM does not have mipmapping. As we have 8bit palettized -textures, OpenGL mipmapping might not give the desired -results. Plus, composing textures from patches at runtime -would require runtime mipmapping. Precalculated mipmaps -in the WAD? - -4. Sprites -Partly transparent textures and sprites impose another -problem related to mipmapping. Without alpha channel, -this could give strange results. Precalculated, valid -sprite mipmaps (w/o alpha)? diff --git a/frosted-doom/README.sound b/frosted-doom/README.sound deleted file mode 100644 index 79541b4..0000000 --- a/frosted-doom/README.sound +++ /dev/null @@ -1,110 +0,0 @@ - -README: sound in DOOM - - -1) DOS/Win32 sound - -id licensed a third party sound library called -DMX for DOS DOOM. The situation exhibited -many symptons of serious NIH "Not Invented Here"), -and one of the consequences is that the original -DOOM sound code does not work without DMX. As -DMX is not publicly available, the original DOOM -sound support is removed. - -Win32 was not supported in the source dump I got. -I have no knowledge how the WinDOOM port did the -sound handling. A Win32 port should probaly rely on -DirectSound. So far, the Win32 glDOOM port Jim Dose -is working on has no sound support. - -In consequence, the only target with a working sound -code is UNIX, which I could only verify with Linux -on Intel586. - -2) Linux sound - -DOOM for Linux used a separate process, sndserver. - -Quoting Dave Taylor: - -"Sound drivers should be an asychronous model, either -a seperate thread or a seperate process. This is -because sound should always be fed to the card without -interruption or else you get pops and with low latency -or else you get angry players. - -Now it turns out that this kind of code isn't too fun -to write. In the days of Linux Doom, threads were not a -happnin thing in Linux. In fact, they still largely -aren't. You can use them these days if you have gnu's -libc installed, but you still can't debug them because -gdb doesn't support them properly yet. I believe the -original seperate process had a bad latency delay -because of the time it took for commands to be flushed -through the pipe used to communicate with the seperate -process. I should have looked into this more thoroughly. - -In Quake, I discovered that I could feed multiple -acknowledgements to a SoundBlaster or compatible without -any side-effects such as pops or other malfunctions. -This discovery led me to switch to a completely synchronous -model, much much easier to debug and understand, so I -think this was fairly intelligent. Although we had to -populate the game with calls in the right places to keep -the sound buffers fed, and although it wasn't gauranteed to -be always fed, well over 99% of the time, it was fed, and -your the latency was never worse than the frequency of your -refills (several times per frame) plus a small lead time -(40th of a second?)." - -The separate sndserver code base introduced some redundancy -(WAD access for sound lumps) for each UNIX target (Sun, SGI, -Linux) and more differences between DOS and UNIX version. -However, I kept the IPC based parts in the source, and -separated the sndserver target in another directory to avoid -further redundancy. There seem to be a few bug-like things -going on in the sndserver that do not receive penalty as -the program has to do only a simple task. One example would -be a libc realloc mixed with zone memory allocation. - -Ungraceful and untimely demise of Linuxdoom (core instead -of I_Error) will leave idle sndserver processes in your -system, blocking /dev/bsp. Kill them manually. - -I put the non-redundant parts of the sndserver program -into the i_sound module of doom, and with the SND_SERV -compiler switch you can choose to use the internal sound -support. However, there is a problem with e.g. the -double shotgun and the plasma gun - walk up to a wall, -face it straight, and fire. The sound output is crappy. -This vanishes with decreasing screen size. A similar -problem occurs with trimer driven asynchronous output -enabled by SNDINTR. - -I agree with Dave that threads would be preferable. -With respect to Linux ports of John Carmack's next -Trinity engine, this one will rely on Win32 -multithreading e.g. for input sampling. So the Linux -community will have to sort out threads anyway :-). - -To improve the current sound server, other means of -IPC should take care of the latency. The mixing -buffer/command buffer as shared memory comes to mind. - - - -3) Music support - -There is, and was, no music support in Linuxdoom. Fine with -me - I wouldn't give a bat's tail feathers for DOOM music. -Your mileage may vary. There are a few leftovers of the DOS -music support also interfacing DMX, so there is a place -to start. However, in the age of CDROM based music, I -recommend getting e.g. Workman to cooperate with DOOM -(currently, DOOM accessing the soundcard SpekerOut -interferes with Workman controlling the CD drives -SpeakerOut), so musci could be chosen and run completely -independend of the game. You could try Linuxdoom with -Q2 music that way. - diff --git a/frosted-doom/TODO b/frosted-doom/TODO deleted file mode 100644 index 89529c9..0000000 --- a/frosted-doom/TODO +++ /dev/null @@ -1,123 +0,0 @@ - -- create Web repository for sources, patches, - news, and pointer to doom-editing mailing - list. - -- get DOOM Public License from id - ------------------------------------------------ - -- remove m_fixed, switch to floating point - More stable, and prolly even faster. - -- make SCREENWIDTH/HEIGHT work at startup? - Well, the HUD/STBar stuff is tied to the - scales implied by the graphics. Rather do - GLDOOM and use texture mapping. - -- fix aspect ratio? - 320x200 is nothing viable nowadays. - A 320x240 base (4:3) would be a lot better. - See above on width/height. - -- limited look up/down by y-shearing? - Prolly not worth it, rather switch to GLDOOM. - -- switch to C++? - The action function pointers have varying - argument lists (no parameter, one, etc.). - C++ doesn't like that much. A major rewrite. - -- switch to doommain.c plus libdoom? Have - libref, libgame etc.? - Another major rewrite. - -- use XFree86 DGA, prolly not that much faster - than MIT SHM, but allows for directly sampled - mouse (and even freelook). Recommended for - GLDOOM. - -- put together an accompanying developer toolkit - source distribution: DEU, RMB, BSP for Linux/X. - -- move info.h, info.c, sounds.h, sounds.c and - other data to a separate lump in the WAD, - or into a libgame.so, to separate the - generic stuff (refresh, I/O) from the - DOOM specifics. - -- decide whether precaching all sounds is - better than retrieving and releasing - every so often. DOOM seems to do that - frequently (8bit stuff, originally for - DOS), and the Linux sound is 16bit - (conversion in the mixing, requires - some padding) - we prolly got the memory - to spare. - -- 16bpp CLUT. The lightmaps and the - framebuffer could be changed to switch - to 64K colors. Prolly better to do - GLDOOM right away. - -- remove checks for commercial etc., in - non-essential issues (enabling PWAD's). - -- change (simplify) determination of - sky texture (done by game version). - Explicit? - -- remove all game version checks - -- different handling of Demo - don't - exit on "different game version" - -- how about shareware/retail "You are here" - intermission animation? Wasn't in - commercial (DOOM 2). - -- double shotgun in DOOM1, all weapons with - shareware - -- checks for required lumps. We need fallbacks - for lumps that are not present, that is, - default sounds etc. to be used instead, - or removing THINGS w/o sprites etc. - -- client/server? I'd suggest ripping off some stuff - from the abandoned IBM WebView project - -- Blockmap - The BLOCKMAP lump might be (partly) redundant, - as the BSP allows for clipping (except certain - LineDefs that will not spawn Segs). - -- LOS - REJECT and intersection based LOS checking could be - done using the BSP. In case of REJECT, certain - monster AI special effects would be lost, though. - -- correct handling of height in collision. This is - not done, and the checks are scattered around in - many places. It does require handling of "player - on top of monster" situations, too - we have to - make sure the players falls off far enough to - avoid getting "stuck in monster". - -- remove obsolete menus (Detail. Music Volume?) - -- clip explosion range damage (and sprites) using - REJECT? That is, if one Sector/SSector not - visible from the other, do not apply damage, - not render sprite if player in other sector. - Hmmm - explosion behind small pillar might not be - visible at all, but do we care? - - -- Ungraceful and untimely demise of Linuxdoom (core - instead of I_Error) will leave idle sndserver - processes in your system, blocking /dev/bsp. - A timeout on lack of input for "sndserver"? - -- threaded sndserver? SHM mixing buffer? - Or internal, timer-based? diff --git a/frosted-doom/am_map.c b/frosted-doom/am_map.c index 84c9cf7..d3d504e 100644 --- a/frosted-doom/am_map.c +++ b/frosted-doom/am_map.c @@ -1,38 +1,36 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // -// $Log:$ -// // DESCRIPTION: the automap code // -//----------------------------------------------------------------------------- -static const char rcsid[] = "$Id: am_map.c,v 1.4 1997/02/03 21:24:33 b1 Exp $"; #include +#include "deh_main.h" #include "z_zone.h" +#include "doomkeys.h" #include "doomdef.h" #include "st_stuff.h" #include "p_local.h" #include "w_wad.h" #include "m_cheat.h" +#include "m_controls.h" +#include "m_misc.h" #include "i_system.h" // Needs access to LFB. @@ -85,21 +83,6 @@ static const char rcsid[] = "$Id: am_map.c,v 1.4 1997/02/03 21:24:33 b1 Exp $"; #define XHAIRCOLORS GRAYS // drawing stuff -#define FB 0 - -#define AM_PANDOWNKEY KEY_DOWNARROW -#define AM_PANUPKEY KEY_UPARROW -#define AM_PANRIGHTKEY KEY_RIGHTARROW -#define AM_PANLEFTKEY KEY_LEFTARROW -#define AM_ZOOMINKEY '=' -#define AM_ZOOMOUTKEY '-' -#define AM_STARTKEY KEY_TAB -#define AM_ENDKEY KEY_TAB -#define AM_GOBIGKEY '0' -#define AM_FOLLOWKEY 'f' -#define AM_GRIDKEY 'g' -#define AM_MARKKEY 'm' -#define AM_CLEARMARKKEY 'c' #define AM_NUMMARKPOINTS 10 @@ -168,7 +151,6 @@ mline_t player_arrow[] = { { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } } }; #undef R -#define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t)) #define R ((8*PLAYERRADIUS)/7) mline_t cheat_player_arrow[] = { @@ -190,25 +172,22 @@ mline_t cheat_player_arrow[] = { { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } } }; #undef R -#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t)) #define R (FRACUNIT) mline_t triangle_guy[] = { - { { -.867*R, -.5*R }, { .867*R, -.5*R } }, - { { .867*R, -.5*R } , { 0, R } }, - { { 0, R }, { -.867*R, -.5*R } } + { { (fixed_t)(-.867*R), (fixed_t)(-.5*R) }, { (fixed_t)(.867*R ), (fixed_t)(-.5*R) } }, + { { (fixed_t)(.867*R ), (fixed_t)(-.5*R) }, { (fixed_t)(0 ), (fixed_t)(R ) } }, + { { (fixed_t)(0 ), (fixed_t)(R ) }, { (fixed_t)(-.867*R), (fixed_t)(-.5*R) } } }; #undef R -#define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t)) #define R (FRACUNIT) mline_t thintriangle_guy[] = { - { { -.5*R, -.7*R }, { R, 0 } }, - { { R, 0 }, { -.5*R, .7*R } }, - { { -.5*R, .7*R }, { -.5*R, -.7*R } } + { { (fixed_t)(-.5*R), (fixed_t)(-.7*R) }, { (fixed_t)(R ), (fixed_t)(0 ) } }, + { { (fixed_t)(R ), (fixed_t)(0 ) }, { (fixed_t)(-.5*R), (fixed_t)(.7*R ) } }, + { { (fixed_t)(-.5*R), (fixed_t)(.7*R ) }, { (fixed_t)(-.5*R), (fixed_t)(-.7*R) } } }; #undef R -#define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t)) @@ -272,7 +251,7 @@ static fixed_t old_m_x, old_m_y; static mpoint_t f_oldloc; // used by MTOF to scale from map-to-frame-buffer coords -static fixed_t scale_mtof = INITSCALEMTOF; +static fixed_t scale_mtof = (fixed_t)INITSCALEMTOF; // used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof) static fixed_t scale_ftom; @@ -284,23 +263,10 @@ static int markpointnum = 0; // next point to be assigned static int followplayer = 1; // specifies whether to follow the player around -static unsigned char cheat_amap_seq[] = { 0xb2, 0x26, 0x26, 0x2e, 0xff }; -static cheatseq_t cheat_amap = { cheat_amap_seq, 0 }; +cheatseq_t cheat_amap = CHEAT("iddt", 0); static boolean stopped = true; -extern boolean viewactive; -//extern byte screens[][SCREENWIDTH*SCREENHEIGHT]; - - - -void -V_MarkRect -( int x, - int y, - int width, - int height ); - // Calculates the slope and slope according to the x-axis of a line // segment in map coordinates (with the upright y-axis n' all) so // that it can be used with the brain-dead drawing stuff. @@ -314,9 +280,9 @@ AM_getIslope dy = ml->a.y - ml->b.y; dx = ml->b.x - ml->a.x; - if (!dy) is->islp = (dx<0?-MAXINT:MAXINT); + if (!dy) is->islp = (dx<0?-INT_MAX:INT_MAX); else is->islp = FixedDiv(dx, dy); - if (!dx) is->slp = (dy<0?-MAXINT:MAXINT); + if (!dx) is->slp = (dy<0?-INT_MAX:INT_MAX); else is->slp = FixedDiv(dy, dx); } @@ -392,8 +358,8 @@ void AM_findMinMaxBoundaries(void) fixed_t a; fixed_t b; - min_x = min_y = MAXINT; - max_x = max_y = -MAXINT; + min_x = min_y = INT_MAX; + max_x = max_y = -INT_MAX; for (i=0;imo->x - m_w/2; m_y = plr->mo->y - m_h/2; AM_changeWindowLoc(); @@ -506,7 +484,7 @@ void AM_loadPics(void) for (i=0;i<10;i++) { - sprintf(namebuf, "AMMNUM%d", i); + DEH_snprintf(namebuf, 9, "AMMNUM%d", i); marknums[i] = W_CacheLumpName(namebuf, PU_STATIC); } @@ -515,10 +493,13 @@ void AM_loadPics(void) void AM_unloadPics(void) { int i; + char namebuf[9]; for (i=0;i<10;i++) - Z_ChangeTag(marknums[i], PU_CACHE); - + { + DEH_snprintf(namebuf, 9, "AMMNUM%d", i); + W_ReleaseLumpName(namebuf); + } } void AM_clearMarks(void) @@ -559,7 +540,7 @@ void AM_LevelInit(void) // void AM_Stop (void) { - static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED }; + static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED, 0 }; AM_unloadPics(); automapactive = false; @@ -616,118 +597,138 @@ AM_Responder { int rc; - //static int cheatstate=0; static int bigstate=0; static char buffer[20]; + int key; rc = false; if (!automapactive) { - if (ev->type == ev_keydown && ev->data1 == AM_STARTKEY) + if (ev->type == ev_keydown && ev->data1 == key_map_toggle) { AM_Start (); viewactive = false; rc = true; } } - else if (ev->type == ev_keydown) { - rc = true; - switch(ev->data1) - { - case AM_PANRIGHTKEY: // pan right - if (!followplayer) m_paninc.x = FTOM(F_PANINC); - else rc = false; - break; - case AM_PANLEFTKEY: // pan left - if (!followplayer) m_paninc.x = -FTOM(F_PANINC); - else rc = false; - break; - case AM_PANUPKEY: // pan up - if (!followplayer) m_paninc.y = FTOM(F_PANINC); - else rc = false; - break; - case AM_PANDOWNKEY: // pan down - if (!followplayer) m_paninc.y = -FTOM(F_PANINC); - else rc = false; - break; - case AM_ZOOMOUTKEY: // zoom out - mtof_zoommul = M_ZOOMOUT; - ftom_zoommul = M_ZOOMIN; - break; - case AM_ZOOMINKEY: // zoom in - mtof_zoommul = M_ZOOMIN; - ftom_zoommul = M_ZOOMOUT; - break; - case AM_ENDKEY: - bigstate = 0; - viewactive = true; - AM_Stop (); - break; - case AM_GOBIGKEY: - bigstate = !bigstate; - if (bigstate) - { - AM_saveScaleAndLoc(); - AM_minOutWindowScale(); - } - else AM_restoreScaleAndLoc(); - break; - case AM_FOLLOWKEY: - followplayer = !followplayer; - f_oldloc.x = MAXINT; - plr->message = followplayer ? AMSTR_FOLLOWON : AMSTR_FOLLOWOFF; - break; - case AM_GRIDKEY: - grid = !grid; - plr->message = grid ? AMSTR_GRIDON : AMSTR_GRIDOFF; - break; - case AM_MARKKEY: - sprintf(buffer, "%s %d", AMSTR_MARKEDSPOT, markpointnum); - plr->message = buffer; - AM_addMark(); - break; - case AM_CLEARMARKKEY: - AM_clearMarks(); - plr->message = AMSTR_MARKSCLEARED; - break; - default: - //cheatstate=0; - rc = false; - } - if (!deathmatch && cht_CheckCheat(&cheat_amap, ev->data1)) + key = ev->data1; + + if (key == key_map_east) // pan right + { + if (!followplayer) m_paninc.x = FTOM(F_PANINC); + else rc = false; + } + else if (key == key_map_west) // pan left + { + if (!followplayer) m_paninc.x = -FTOM(F_PANINC); + else rc = false; + } + else if (key == key_map_north) // pan up + { + if (!followplayer) m_paninc.y = FTOM(F_PANINC); + else rc = false; + } + else if (key == key_map_south) // pan down + { + if (!followplayer) m_paninc.y = -FTOM(F_PANINC); + else rc = false; + } + else if (key == key_map_zoomout) // zoom out + { + mtof_zoommul = M_ZOOMOUT; + ftom_zoommul = M_ZOOMIN; + } + else if (key == key_map_zoomin) // zoom in + { + mtof_zoommul = M_ZOOMIN; + ftom_zoommul = M_ZOOMOUT; + } + else if (key == key_map_toggle) + { + bigstate = 0; + viewactive = true; + AM_Stop (); + } + else if (key == key_map_maxzoom) + { + bigstate = !bigstate; + if (bigstate) + { + AM_saveScaleAndLoc(); + AM_minOutWindowScale(); + } + else AM_restoreScaleAndLoc(); + } + else if (key == key_map_follow) + { + followplayer = !followplayer; + f_oldloc.x = INT_MAX; + if (followplayer) + plr->message = DEH_String(AMSTR_FOLLOWON); + else + plr->message = DEH_String(AMSTR_FOLLOWOFF); + } + else if (key == key_map_grid) + { + grid = !grid; + if (grid) + plr->message = DEH_String(AMSTR_GRIDON); + else + plr->message = DEH_String(AMSTR_GRIDOFF); + } + else if (key == key_map_mark) + { + M_snprintf(buffer, sizeof(buffer), "%s %d", + DEH_String(AMSTR_MARKEDSPOT), markpointnum); + plr->message = buffer; + AM_addMark(); + } + else if (key == key_map_clearmark) + { + AM_clearMarks(); + plr->message = DEH_String(AMSTR_MARKSCLEARED); + } + else + { + rc = false; + } + + if (!deathmatch && cht_CheckCheat(&cheat_amap, ev->data2)) { rc = false; cheating = (cheating+1) % 3; } } - else if (ev->type == ev_keyup) { - rc = false; - switch (ev->data1) - { - case AM_PANRIGHTKEY: - if (!followplayer) m_paninc.x = 0; - break; - case AM_PANLEFTKEY: - if (!followplayer) m_paninc.x = 0; - break; - case AM_PANUPKEY: - if (!followplayer) m_paninc.y = 0; - break; - case AM_PANDOWNKEY: - if (!followplayer) m_paninc.y = 0; - break; - case AM_ZOOMOUTKEY: - case AM_ZOOMINKEY: - mtof_zoommul = FRACUNIT; - ftom_zoommul = FRACUNIT; - break; - } + rc = false; + key = ev->data1; + + if (key == key_map_east) + { + if (!followplayer) m_paninc.x = 0; + } + else if (key == key_map_west) + { + if (!followplayer) m_paninc.x = 0; + } + else if (key == key_map_north) + { + if (!followplayer) m_paninc.y = 0; + } + else if (key == key_map_south) + { + if (!followplayer) m_paninc.y = 0; + } + else if (key == key_map_zoomout || key == key_map_zoomin) + { + mtof_zoommul = FRACUNIT; + ftom_zoommul = FRACUNIT; + } } return rc; @@ -792,7 +793,7 @@ void AM_updateLightLev(void) if (amclock>nexttic) { lightlev = litelevels[litelevelscnt++]; - if (litelevelscnt == sizeof(litelevels)/sizeof(int)) litelevelscnt = 0; + if (litelevelscnt == arrlen(litelevels)) litelevelscnt = 0; nexttic = amclock + 6 - (amclock % 6); } @@ -856,9 +857,9 @@ AM_clipMline TOP =8 }; - register int outcode1 = 0; - register int outcode2 = 0; - register int outside; + register int outcode1 = 0; + register int outcode2 = 0; + register int outside; fpoint_t tmp; int dx; @@ -950,6 +951,11 @@ AM_clipMline tmp.y = fl->a.y + (dy*(-fl->a.x))/dx; tmp.x = 0; } + else + { + tmp.x = 0; + tmp.y = 0; + } if (outside == outcode1) { @@ -989,7 +995,7 @@ AM_drawFline register int ay; register int d; - //static fuck = 0; + static int fuck = 0; // For debugging only if ( fl->a.x < 0 || fl->a.x >= f_w @@ -997,7 +1003,7 @@ AM_drawFline || fl->b.x < 0 || fl->b.x >= f_w || fl->b.y < 0 || fl->b.y >= f_h) { - //fprintf(stderr, "fuck %d \r", fuck++); + DEH_fprintf(stderr, "fuck %d \r", fuck++); return; } @@ -1249,11 +1255,11 @@ void AM_drawPlayers(void) { if (cheating) AM_drawLineCharacter - (cheat_player_arrow, NUMCHEATPLYRLINES, 0, + (cheat_player_arrow, arrlen(cheat_player_arrow), 0, plr->mo->angle, WHITE, plr->mo->x, plr->mo->y); else AM_drawLineCharacter - (player_arrow, NUMPLYRLINES, 0, plr->mo->angle, + (player_arrow, arrlen(player_arrow), 0, plr->mo->angle, WHITE, plr->mo->x, plr->mo->y); return; } @@ -1275,7 +1281,7 @@ void AM_drawPlayers(void) color = their_colors[their_color]; AM_drawLineCharacter - (player_arrow, NUMPLYRLINES, 0, p->mo->angle, + (player_arrow, arrlen(player_arrow), 0, p->mo->angle, color, p->mo->x, p->mo->y); } @@ -1295,7 +1301,7 @@ AM_drawThings while (t) { AM_drawLineCharacter - (thintriangle_guy, NUMTHINTRIANGLEGUYLINES, + (thintriangle_guy, arrlen(thintriangle_guy), 16<angle, colors+lightlev, t->x, t->y); t = t->snext; } @@ -1317,7 +1323,7 @@ void AM_drawMarks(void) fx = CXMTOF(markpoints[i].x); fy = CYMTOF(markpoints[i].y); if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h) - V_DrawPatch(fx, fy, FB, marknums[i]); + V_DrawPatch(fx, fy, marknums[i]); } } diff --git a/frosted-doom/am_map.h b/frosted-doom/am_map.h index ff2e0b4..572d238 100644 --- a/frosted-doom/am_map.h +++ b/frosted-doom/am_map.h @@ -1,27 +1,27 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // AutoMap module. // -//----------------------------------------------------------------------------- #ifndef __AMMAP_H__ #define __AMMAP_H__ +#include "d_event.h" +#include "m_cheat.h" + // Used by ST StatusBar stuff. #define AM_MSGHEADER (('a'<<24)+('m'<<16)) #define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8)) @@ -43,10 +43,7 @@ void AM_Drawer (void); void AM_Stop (void); +extern cheatseq_t cheat_amap; + #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/compat/values.h b/frosted-doom/compat/values.h deleted file mode 100644 index 389b9d2..0000000 --- a/frosted-doom/compat/values.h +++ /dev/null @@ -1,67 +0,0 @@ -/* Old compatibility names for and 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 - . */ - -/* This interface is obsolete. New programs should use - and/or instead of . */ - -#ifndef _VALUES_H -#define _VALUES_H 1 - -#include - -#include - -#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 - -#define MAXDOUBLE DBL_MAX -#define MINDOUBLE DBL_MIN -#define MINFLOAT FLT_MIN -#define DMINEXP DBL_MIN_EXP -#define FMINEXP FLT_MIN_EXP -#define DMAXEXP DBL_MAX_EXP -#define FMAXEXP FLT_MAX_EXP - - -#ifdef __USE_MISC -/* Some systems define this name instead of CHAR_BIT or CHARBITS. */ -# define BITSPERBYTE CHAR_BIT -#endif - -#endif /* values.h */ diff --git a/frosted-doom/config.h b/frosted-doom/config.h new file mode 100644 index 0000000..6c68fca --- /dev/null +++ b/frosted-doom/config.h @@ -0,0 +1,100 @@ +/* config.hin. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the header file. */ +#undef HAVE_DEV_ISA_SPKRIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_DEV_SPEAKER_SPEAKER_H + +/* Define to 1 if you have the 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 header file. */ +#undef HAVE_LINUX_KD_H + +/* Define to 1 if you have the 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 header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the 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" diff --git a/frosted-doom/d_englsh.h b/frosted-doom/d_englsh.h index c0b0786..cfb0572 100644 --- a/frosted-doom/d_englsh.h +++ b/frosted-doom/d_englsh.h @@ -1,24 +1,21 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Printed strings for translation. // English language support (default). // -//----------------------------------------------------------------------------- #ifndef __D_ENGLSH__ #define __D_ENGLSH__ @@ -63,7 +60,7 @@ #define NETEND "you can't end a netgame!\n\n"PRESSKEY #define ENDGAME "are you sure you want to end the game?\n\n"PRESSYN -#define DOSY "(press y to quit)" +#define DOSY "(press y to quit to dos.)" #define DETAILHI "High detail" #define DETAILLO "Low detail" @@ -694,8 +691,3 @@ #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/d_event.c b/frosted-doom/d_event.c new file mode 100644 index 0000000..3eef572 --- /dev/null +++ b/frosted-doom/d_event.c @@ -0,0 +1,63 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// +// DESCRIPTION: Event handling. +// +// Events are asynchronous inputs generally generated by the game user. +// Events can be discarded if no responder claims them +// + +#include +#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; +} + + diff --git a/frosted-doom/d_event.h b/frosted-doom/d_event.h index feb5783..c9374b2 100644 --- a/frosted-doom/d_event.h +++ b/frosted-doom/d_event.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // // -//----------------------------------------------------------------------------- #ifndef __D_EVENT__ @@ -37,35 +34,40 @@ typedef enum ev_keydown, ev_keyup, ev_mouse, - ev_joystick + ev_joystick, + ev_quit } evtype_t; // Event structure. typedef struct { - evtype_t type; - int data1; // keys / mouse/joystick buttons - int data2; // mouse/joystick x move - int data3; // mouse/joystick y move + evtype_t type; + + // Event-related data that depends on the type of event: + // + // ev_keydown/ev_keyup: + // data1: Key code (from doomkeys.h) of the key that was + // pressed or released. + // data2: Ascii text of the character that was pressed, + // shifted appropriately (eg. '$' if 4 was pressed + // while shift was held). + // + // ev_mouse: + // data1: Bitfield of buttons currently held down. + // (bit 0 = left; bit 1 = right; bit 2 = middle). + // data2: X axis mouse movement (turn). + // data3: Y axis mouse movement (forward/backward). + // + // ev_joystick: + // data1: Bitfield of buttons currently pressed. + // data2: X axis mouse movement (turn). + // data3: Y axis mouse movement (forward/backward). + // data4: Third axis mouse movement (strafe). + + int data1, data2, data3, data4; } event_t; -typedef enum -{ - ga_nothing, - ga_loadlevel, - ga_newgame, - ga_loadgame, - ga_savegame, - ga_playdemo, - ga_completed, - ga_victory, - ga_worlddone, - ga_screenshot -} gameaction_t; - - - // // Button/action code definitions. // @@ -99,24 +101,37 @@ typedef enum } buttoncode_t; +// villsa [STRIFE] Strife specific buttons +// TODO - not finished +typedef enum +{ + // Player view look up + BT2_LOOKUP = 1, + // Player view look down + BT2_LOOKDOWN = 2, + // Center player's view + BT2_CENTERVIEW = 4, + // Use inventory item + BT2_INVUSE = 8, + // Drop inventory item + BT2_INVDROP = 16, + // Jump up and down + BT2_JUMP = 32, + // Use medkit + BT2_HEALTH = 128, + +} buttoncode2_t; -// -// GLOBAL VARIABLES -// -#define MAXEVENTS 64 -extern event_t events[MAXEVENTS]; -extern int eventhead; -extern int eventtail; +// Called by IO functions when input is detected. +void D_PostEvent (event_t *ev); -extern gameaction_t gameaction; +// Read an event from the event queue + +event_t *D_PopEvent(void); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- + diff --git a/frosted-doom/d_french.h b/frosted-doom/d_french.h deleted file mode 100644 index d4807ab..0000000 --- a/frosted-doom/d_french.h +++ /dev/null @@ -1,433 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// DESCRIPTION: -// Printed strings, french translation. -// -//----------------------------------------------------------------------------- - - -#ifndef __D_FRENCH__ -#define __D_FRENCH__ - -// -// D_Main.C -// -#define D_DEVSTR "MODE DEVELOPPEMENT ON.\n" -#define D_CDROM "VERSION CD-ROM: DEFAULT.CFG DANS C:\\DOOMDATA\n" - -// -// M_Menu.C -// -#define PRESSKEY "APPUYEZ SUR UNE TOUCHE." -#define PRESSYN "APPUYEZ SUR Y OU N" -#define QUITMSG "VOUS VOULEZ VRAIMENT\nQUITTER CE SUPER JEU?" -#define LOADNET "VOUS NE POUVEZ PAS CHARGER\nUN JEU EN RESEAU!\n\n"PRESSKEY -#define QLOADNET "CHARGEMENT RAPIDE INTERDIT EN RESEAU!\n\n"PRESSKEY -#define QSAVESPOT "VOUS N'AVEZ PAS CHOISI UN EMPLACEMENT!\n\n"PRESSKEY -#define SAVEDEAD "VOUS NE POUVEZ PAS SAUVER SI VOUS NE JOUEZ "\ -"PAS!\n\n"PRESSKEY -#define QSPROMPT "SAUVEGARDE RAPIDE DANS LE FICHIER \n\n'%s'?\n\n"PRESSYN -#define QLPROMPT "VOULEZ-VOUS CHARGER LA SAUVEGARDE"\ -"\n\n'%s'?\n\n"PRESSYN -#define NEWGAME "VOUS NE POUVEZ PAS LANCER\n"\ -"UN NOUVEAU JEU SUR RESEAU.\n\n"PRESSKEY -#define NIGHTMARE "VOUS CONFIRMEZ? CE NIVEAU EST\n"\ -"VRAIMENT IMPITOYABLE!n"PRESSYN -#define SWSTRING "CECI EST UNE VERSION SHAREWARE DE DOOM.\n\n"\ -"VOUS DEVRIEZ COMMANDER LA TRILOGIE COMPLETE.\n\n"PRESSKEY -#define MSGOFF "MESSAGES OFF" -#define MSGON "MESSAGES ON" -#define NETEND "VOUS NE POUVEZ PAS METTRE FIN A UN JEU SUR "\ -"RESEAU!\n\n"PRESSKEY -#define ENDGAME "VOUS VOULEZ VRAIMENT METTRE FIN AU JEU?\n\n"PRESSYN - -#define DOSY "(APPUYEZ SUR Y POUR REVENIR AU OS.)" - -#define DETAILHI "GRAPHISMES MAXIMUM " -#define DETAILLO "GRAPHISMES MINIMUM " -#define GAMMALVL0 "CORRECTION GAMMA OFF" -#define GAMMALVL1 "CORRECTION GAMMA NIVEAU 1" -#define GAMMALVL2 "CORRECTION GAMMA NIVEAU 2" -#define GAMMALVL3 "CORRECTION GAMMA NIVEAU 3" -#define GAMMALVL4 "CORRECTION GAMMA NIVEAU 4" -#define EMPTYSTRING "EMPLACEMENT VIDE" - -// -// P_inter.C -// -#define GOTARMOR "ARMURE RECUPEREE." -#define GOTMEGA "MEGA-ARMURE RECUPEREE!" -#define GOTHTHBONUS "BONUS DE SANTE RECUPERE." -#define GOTARMBONUS "BONUS D'ARMURE RECUPERE." -#define GOTSTIM "STIMPACK RECUPERE." -#define GOTMEDINEED "MEDIKIT RECUPERE. VOUS EN AVEZ VRAIMENT BESOIN!" -#define GOTMEDIKIT "MEDIKIT RECUPERE." -#define GOTSUPER "SUPERCHARGE!" - -#define GOTBLUECARD "CARTE MAGNETIQUE BLEUE RECUPEREE." -#define GOTYELWCARD "CARTE MAGNETIQUE JAUNE RECUPEREE." -#define GOTREDCARD "CARTE MAGNETIQUE ROUGE RECUPEREE." -#define GOTBLUESKUL "CLEF CRANE BLEUE RECUPEREE." -#define GOTYELWSKUL "CLEF CRANE JAUNE RECUPEREE." -#define GOTREDSKULL "CLEF CRANE ROUGE RECUPEREE." - -#define GOTINVUL "INVULNERABILITE!" -#define GOTBERSERK "BERSERK!" -#define GOTINVIS "INVISIBILITE PARTIELLE " -#define GOTSUIT "COMBINAISON ANTI-RADIATIONS " -#define GOTMAP "CARTE INFORMATIQUE " -#define GOTVISOR "VISEUR A AMPLIFICATION DE LUMIERE " -#define GOTMSPHERE "MEGASPHERE!" - -#define GOTCLIP "CHARGEUR RECUPERE." -#define GOTCLIPBOX "BOITE DE BALLES RECUPEREE." -#define GOTROCKET "ROQUETTE RECUPEREE." -#define GOTROCKBOX "CAISSE DE ROQUETTES RECUPEREE." -#define GOTCELL "CELLULE D'ENERGIE RECUPEREE." -#define GOTCELLBOX "PACK DE CELLULES D'ENERGIE RECUPERE." -#define GOTSHELLS "4 CARTOUCHES RECUPEREES." -#define GOTSHELLBOX "BOITE DE CARTOUCHES RECUPEREE." -#define GOTBACKPACK "SAC PLEIN DE MUNITIONS RECUPERE!" - -#define GOTBFG9000 "VOUS AVEZ UN BFG9000! OH, OUI!" -#define GOTCHAINGUN "VOUS AVEZ LA MITRAILLEUSE!" -#define GOTCHAINSAW "UNE TRONCONNEUSE!" -#define GOTLAUNCHER "VOUS AVEZ UN LANCE-ROQUETTES!" -#define GOTPLASMA "VOUS AVEZ UN FUSIL A PLASMA!" -#define GOTSHOTGUN "VOUS AVEZ UN FUSIL!" -#define GOTSHOTGUN2 "VOUS AVEZ UN SUPER FUSIL!" - -// -// P_Doors.C -// -#define PD_BLUEO "IL VOUS FAUT UNE CLEF BLEUE" -#define PD_REDO "IL VOUS FAUT UNE CLEF ROUGE" -#define PD_YELLOWO "IL VOUS FAUT UNE CLEF JAUNE" -#define PD_BLUEK PD_BLUEO -#define PD_REDK PD_REDO -#define PD_YELLOWK PD_YELLOWO - -// -// G_game.C -// -#define GGSAVED "JEU SAUVEGARDE." - -// -// HU_stuff.C -// -#define HUSTR_MSGU "[MESSAGE NON ENVOYE]" - -#define HUSTR_E1M1 "E1M1: HANGAR" -#define HUSTR_E1M2 "E1M2: USINE NUCLEAIRE " -#define HUSTR_E1M3 "E1M3: RAFFINERIE DE TOXINES " -#define HUSTR_E1M4 "E1M4: CENTRE DE CONTROLE " -#define HUSTR_E1M5 "E1M5: LABORATOIRE PHOBOS " -#define HUSTR_E1M6 "E1M6: TRAITEMENT CENTRAL " -#define HUSTR_E1M7 "E1M7: CENTRE INFORMATIQUE " -#define HUSTR_E1M8 "E1M8: ANOMALIE PHOBOS " -#define HUSTR_E1M9 "E1M9: BASE MILITAIRE " - -#define HUSTR_E2M1 "E2M1: ANOMALIE DEIMOS " -#define HUSTR_E2M2 "E2M2: ZONE DE CONFINEMENT " -#define HUSTR_E2M3 "E2M3: RAFFINERIE" -#define HUSTR_E2M4 "E2M4: LABORATOIRE DEIMOS " -#define HUSTR_E2M5 "E2M5: CENTRE DE CONTROLE " -#define HUSTR_E2M6 "E2M6: HALLS DES DAMNES " -#define HUSTR_E2M7 "E2M7: CUVES DE REPRODUCTION " -#define HUSTR_E2M8 "E2M8: TOUR DE BABEL " -#define HUSTR_E2M9 "E2M9: FORTERESSE DU MYSTERE " - -#define HUSTR_E3M1 "E3M1: DONJON DE L'ENFER " -#define HUSTR_E3M2 "E3M2: BOURBIER DU DESESPOIR " -#define HUSTR_E3M3 "E3M3: PANDEMONIUM" -#define HUSTR_E3M4 "E3M4: MAISON DE LA DOULEUR " -#define HUSTR_E3M5 "E3M5: CATHEDRALE PROFANE " -#define HUSTR_E3M6 "E3M6: MONT EREBUS" -#define HUSTR_E3M7 "E3M7: LIMBES" -#define HUSTR_E3M8 "E3M8: DIS" -#define HUSTR_E3M9 "E3M9: CLAPIERS" - -#define HUSTR_1 "NIVEAU 1: ENTREE " -#define HUSTR_2 "NIVEAU 2: HALLS SOUTERRAINS " -#define HUSTR_3 "NIVEAU 3: LE FEU NOURRI " -#define HUSTR_4 "NIVEAU 4: LE FOYER " -#define HUSTR_5 "NIVEAU 5: LES EGOUTS " -#define HUSTR_6 "NIVEAU 6: LE BROYEUR " -#define HUSTR_7 "NIVEAU 7: L'HERBE DE LA MORT" -#define HUSTR_8 "NIVEAU 8: RUSES ET PIEGES " -#define HUSTR_9 "NIVEAU 9: LE PUITS " -#define HUSTR_10 "NIVEAU 10: BASE DE RAVITAILLEMENT " -#define HUSTR_11 "NIVEAU 11: LE CERCLE DE LA MORT!" - -#define HUSTR_12 "NIVEAU 12: L'USINE " -#define HUSTR_13 "NIVEAU 13: LE CENTRE VILLE" -#define HUSTR_14 "NIVEAU 14: LES ANTRES PROFONDES " -#define HUSTR_15 "NIVEAU 15: LA ZONE INDUSTRIELLE " -#define HUSTR_16 "NIVEAU 16: LA BANLIEUE" -#define HUSTR_17 "NIVEAU 17: LES IMMEUBLES" -#define HUSTR_18 "NIVEAU 18: LA COUR " -#define HUSTR_19 "NIVEAU 19: LA CITADELLE " -#define HUSTR_20 "NIVEAU 20: JE T'AI EU!" - -#define HUSTR_21 "NIVEAU 21: LE NIRVANA" -#define HUSTR_22 "NIVEAU 22: LES CATACOMBES " -#define HUSTR_23 "NIVEAU 23: LA GRANDE FETE " -#define HUSTR_24 "NIVEAU 24: LE GOUFFRE " -#define HUSTR_25 "NIVEAU 25: LES CHUTES DE SANG" -#define HUSTR_26 "NIVEAU 26: LES MINES ABANDONNEES " -#define HUSTR_27 "NIVEAU 27: CHEZ LES MONSTRES " -#define HUSTR_28 "NIVEAU 28: LE MONDE DE L'ESPRIT " -#define HUSTR_29 "NIVEAU 29: LA LIMITE " -#define HUSTR_30 "NIVEAU 30: L'ICONE DU PECHE " - -#define HUSTR_31 "NIVEAU 31: WOLFENSTEIN" -#define HUSTR_32 "NIVEAU 32: LE MASSACRE" - - -#define HUSTR_CHATMACRO1 "JE SUIS PRET A LEUR EN FAIRE BAVER!" -#define HUSTR_CHATMACRO2 "JE VAIS BIEN." -#define HUSTR_CHATMACRO3 "JE N'AI PAS L'AIR EN FORME!" -#define HUSTR_CHATMACRO4 "AU SECOURS!" -#define HUSTR_CHATMACRO5 "TU CRAINS!" -#define HUSTR_CHATMACRO6 "LA PROCHAINE FOIS, MINABLE..." -#define HUSTR_CHATMACRO7 "VIENS ICI!" -#define HUSTR_CHATMACRO8 "JE VAIS M'EN OCCUPER." -#define HUSTR_CHATMACRO9 "OUI" -#define HUSTR_CHATMACRO0 "NON" - -#define HUSTR_TALKTOSELF1 "VOUS PARLEZ TOUT SEUL " -#define HUSTR_TALKTOSELF2 "QUI EST LA?" -#define HUSTR_TALKTOSELF3 "VOUS VOUS FAITES PEUR " -#define HUSTR_TALKTOSELF4 "VOUS COMMENCEZ A DELIRER " -#define HUSTR_TALKTOSELF5 "VOUS ETES LARGUE..." - -#define HUSTR_MESSAGESENT "[MESSAGE ENVOYE]" - -// The following should NOT be changed unless it seems -// just AWFULLY necessary - -#define HUSTR_PLRGREEN "VERT: " -#define HUSTR_PLRINDIGO "INDIGO: " -#define HUSTR_PLRBROWN "BRUN: " -#define HUSTR_PLRRED "ROUGE: " - -#define HUSTR_KEYGREEN 'g' // french key should be "V" -#define HUSTR_KEYINDIGO 'i' -#define HUSTR_KEYBROWN 'b' -#define HUSTR_KEYRED 'r' - -// -// AM_map.C -// - -#define AMSTR_FOLLOWON "MODE POURSUITE ON" -#define AMSTR_FOLLOWOFF "MODE POURSUITE OFF" - -#define AMSTR_GRIDON "GRILLE ON" -#define AMSTR_GRIDOFF "GRILLE OFF" - -#define AMSTR_MARKEDSPOT "REPERE MARQUE " -#define AMSTR_MARKSCLEARED "REPERES EFFACES " - -// -// ST_stuff.C -// - -#define STSTR_MUS "CHANGEMENT DE MUSIQUE " -#define STSTR_NOMUS "IMPOSSIBLE SELECTION" -#define STSTR_DQDON "INVULNERABILITE ON " -#define STSTR_DQDOFF "INVULNERABILITE OFF" - -#define STSTR_KFAADDED "ARMEMENT MAXIMUM! " -#define STSTR_FAADDED "ARMES (SAUF CLEFS) AJOUTEES" - -#define STSTR_NCON "BARRIERES ON" -#define STSTR_NCOFF "BARRIERES OFF" - -#define STSTR_BEHOLD " inVuln, Str, Inviso, Rad, Allmap, or Lite-amp" -#define STSTR_BEHOLDX "AMELIORATION ACTIVEE" - -#define STSTR_CHOPPERS "... DOESN'T SUCK - GM" -#define STSTR_CLEV "CHANGEMENT DE NIVEAU..." - -// -// F_Finale.C -// -#define E1TEXT "APRES AVOIR VAINCU LES GROS MECHANTS\n"\ -"ET NETTOYE LA BASE LUNAIRE, VOUS AVEZ\n"\ -"GAGNE, NON? PAS VRAI? OU EST DONC VOTRE\n"\ -" RECOMPENSE ET VOTRE BILLET DE\n"\ -"RETOUR? QU'EST-QUE CA VEUT DIRE?CE"\ -"N'EST PAS LA FIN ESPEREE!\n"\ -"\n" \ -"CA SENT LA VIANDE PUTREFIEE, MAIS\n"\ -"ON DIRAIT LA BASE DEIMOS. VOUS ETES\n"\ -"APPAREMMENT BLOQUE AUX PORTES DE L'ENFER.\n"\ -"LA SEULE ISSUE EST DE L'AUTRE COTE.\n"\ -"\n"\ -"POUR VIVRE LA SUITE DE DOOM, JOUEZ\n"\ -"A 'AUX PORTES DE L'ENFER' ET A\n"\ -"L'EPISODE SUIVANT, 'L'ENFER'!\n" - -#define E2TEXT "VOUS AVEZ REUSSI. L'INFAME DEMON\n"\ -"QUI CONTROLAIT LA BASE LUNAIRE DE\n"\ -"DEIMOS EST MORT, ET VOUS AVEZ\n"\ -"TRIOMPHE! MAIS... OU ETES-VOUS?\n"\ -"VOUS GRIMPEZ JUSQU'AU BORD DE LA\n"\ -"LUNE ET VOUS DECOUVREZ L'ATROCE\n"\ -"VERITE.\n" \ -"\n"\ -"DEIMOS EST AU-DESSUS DE L'ENFER!\n"\ -"VOUS SAVEZ QUE PERSONNE NE S'EN\n"\ -"EST JAMAIS ECHAPPE, MAIS CES FUMIERS\n"\ -"VONT REGRETTER DE VOUS AVOIR CONNU!\n"\ -"VOUS REDESCENDEZ RAPIDEMENT VERS\n"\ -"LA SURFACE DE L'ENFER.\n"\ -"\n" \ -"VOICI MAINTENANT LE CHAPITRE FINAL DE\n"\ -"DOOM! -- L'ENFER." - -#define E3TEXT "LE DEMON ARACHNEEN ET REPUGNANT\n"\ -"QUI A DIRIGE L'INVASION DES BASES\n"\ -"LUNAIRES ET SEME LA MORT VIENT DE SE\n"\ -"FAIRE PULVERISER UNE FOIS POUR TOUTES.\n"\ -"\n"\ -"UNE PORTE SECRETE S'OUVRE. VOUS ENTREZ.\n"\ -"VOUS AVEZ PROUVE QUE VOUS POUVIEZ\n"\ -"RESISTER AUX HORREURS DE L'ENFER.\n"\ -"IL SAIT ETRE BEAU JOUEUR, ET LORSQUE\n"\ -"VOUS SORTEZ, VOUS REVOYEZ LES VERTES\n"\ -"PRAIRIES DE LA TERRE, VOTRE PLANETE.\n"\ -"\n"\ -"VOUS VOUS DEMANDEZ CE QUI S'EST PASSE\n"\ -"SUR TERRE PENDANT QUE VOUS AVEZ\n"\ -"COMBATTU LE DEMON. HEUREUSEMENT,\n"\ -"AUCUN GERME DU MAL N'A FRANCHI\n"\ -"CETTE PORTE AVEC VOUS..." - - - -// after level 6, put this: - -#define C1TEXT "VOUS ETES AU PLUS PROFOND DE L'ASTROPORT\n" \ -"INFESTE DE MONSTRES, MAIS QUELQUE CHOSE\n" \ -"NE VA PAS. ILS ONT APPORTE LEUR PROPRE\n" \ -"REALITE, ET LA TECHNOLOGIE DE L'ASTROPORT\n" \ -"EST AFFECTEE PAR LEUR PRESENCE.\n" \ -"\n"\ -"DEVANT VOUS, VOUS VOYEZ UN POSTE AVANCE\n" \ -"DE L'ENFER, UNE ZONE FORTIFIEE. SI VOUS\n" \ -"POUVEZ PASSER, VOUS POURREZ PENETRER AU\n" \ -"COEUR DE LA BASE HANTEE ET TROUVER \n" \ -"L'INTERRUPTEUR DE CONTROLE QUI GARDE LA \n" \ -"POPULATION DE LA TERRE EN OTAGE." - -// After level 11, put this: - -#define C2TEXT "VOUS AVEZ GAGNE! VOTRE VICTOIRE A PERMIS\n" \ -"A L'HUMANITE D'EVACUER LA TERRE ET \n"\ -"D'ECHAPPER AU CAUCHEMAR. VOUS ETES \n"\ -"MAINTENANT LE DERNIER HUMAIN A LA SURFACE \n"\ -"DE LA PLANETE. VOUS ETES ENTOURE DE \n"\ -"MUTANTS CANNIBALES, D'EXTRATERRESTRES \n"\ -"CARNIVORES ET D'ESPRITS DU MAL. VOUS \n"\ -"ATTENDEZ CALMEMENT LA MORT, HEUREUX \n"\ -"D'AVOIR PU SAUVER VOTRE RACE.\n"\ -"MAIS UN MESSAGE VOUS PARVIENT SOUDAIN\n"\ -"DE L'ESPACE: \"NOS CAPTEURS ONT LOCALISE\n"\ -"LA SOURCE DE L'INVASION EXTRATERRESTRE.\n"\ -"SI VOUS Y ALLEZ, VOUS POURREZ PEUT-ETRE\n"\ -"LES ARRETER. LEUR BASE EST SITUEE AU COEUR\n"\ -"DE VOTRE VILLE NATALE, PRES DE L'ASTROPORT.\n"\ -"VOUS VOUS RELEVEZ LENTEMENT ET PENIBLEMENT\n"\ -"ET VOUS REPARTEZ POUR LE FRONT." - -// After level 20, put this: - -#define C3TEXT "VOUS ETES AU COEUR DE LA CITE CORROMPUE,\n"\ -"ENTOURE PAR LES CADAVRES DE VOS ENNEMIS.\n"\ -"VOUS NE VOYEZ PAS COMMENT DETRUIRE LA PORTE\n"\ -"DES CREATURES DE CE COTE. VOUS SERREZ\n"\ -"LES DENTS ET PLONGEZ DANS L'OUVERTURE.\n"\ -"\n"\ -"IL DOIT Y AVOIR UN MOYEN DE LA FERMER\n"\ -"DE L'AUTRE COTE. VOUS ACCEPTEZ DE\n"\ -"TRAVERSER L'ENFER POUR LE FAIRE?" - -// After level 29, put this: - -#define C4TEXT "LE VISAGE HORRIBLE D'UN DEMON D'UNE\n"\ -"TAILLE INCROYABLE S'EFFONDRE DEVANT\n"\ -"VOUS LORSQUE VOUS TIREZ UNE SALVE DE\n"\ -"ROQUETTES DANS SON CERVEAU. LE MONSTRE\n"\ -"SE RATATINE, SES MEMBRES DECHIQUETES\n"\ -"SE REPANDANT SUR DES CENTAINES DE\n"\ -"KILOMETRES A LA SURFACE DE L'ENFER.\n"\ -"\n"\ -"VOUS AVEZ REUSSI. L'INVASION N'AURA.\n"\ -"PAS LIEU. LA TERRE EST SAUVEE. L'ENFER\n"\ -"EST ANEANTI. EN VOUS DEMANDANT OU IRONT\n"\ -"MAINTENANT LES DAMNES, VOUS ESSUYEZ\n"\ -"VOTRE FRONT COUVERT DE SUEUR ET REPARTEZ\n"\ -"VERS LA TERRE. SA RECONSTRUCTION SERA\n"\ -"BEAUCOUP PLUS DROLE QUE SA DESTRUCTION.\n" - -// Before level 31, put this: - -#define C5TEXT "FELICITATIONS! VOUS AVEZ TROUVE LE\n"\ -"NIVEAU SECRET! IL SEMBLE AVOIR ETE\n"\ -"CONSTRUIT PAR LES HUMAINS. VOUS VOUS\n"\ -"DEMANDEZ QUELS PEUVENT ETRE LES\n"\ -"HABITANTS DE CE COIN PERDU DE L'ENFER." - -// Before level 32, put this: - -#define C6TEXT "FELICITATIONS! VOUS AVEZ DECOUVERT\n"\ -"LE NIVEAU SUPER SECRET! VOUS FERIEZ\n"\ -"MIEUX DE FONCER DANS CELUI-LA!\n" - -// -// Character cast strings F_FINALE.C -// -#define CC_ZOMBIE "ZOMBIE" -#define CC_SHOTGUN "TYPE AU FUSIL" -#define CC_HEAVY "MEC SUPER-ARME" -#define CC_IMP "DIABLOTIN" -#define CC_DEMON "DEMON" -#define CC_LOST "AME PERDUE" -#define CC_CACO "CACODEMON" -#define CC_HELL "CHEVALIER DE L'ENFER" -#define CC_BARON "BARON DE L'ENFER" -#define CC_ARACH "ARACHNOTRON" -#define CC_PAIN "ELEMENTAIRE DE LA DOULEUR" -#define CC_REVEN "REVENANT" -#define CC_MANCU "MANCUBUS" -#define CC_ARCH "ARCHI-INFAME" -#define CC_SPIDER "L'ARAIGNEE CERVEAU" -#define CC_CYBER "LE CYBERDEMON" -#define CC_HERO "NOTRE HEROS" - - - -#endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- - - diff --git a/frosted-doom/d_items.c b/frosted-doom/d_items.c index 2267da4..33f310c 100644 --- a/frosted-doom/d_items.c +++ b/frosted-doom/d_items.c @@ -1,34 +1,24 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id:$"; // We are referring to sprite numbers. #include "info.h" -#ifdef __GNUG__ -#pragma implementation "d_items.h" -#endif #include "d_items.h" diff --git a/frosted-doom/d_items.h b/frosted-doom/d_items.h index 01b6411..3d22a06 100644 --- a/frosted-doom/d_items.h +++ b/frosted-doom/d_items.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Items: key cards, artifacts, weapon, ammunition. // -//----------------------------------------------------------------------------- #ifndef __D_ITEMS__ @@ -25,9 +22,6 @@ #include "doomdef.h" -#ifdef __GNUG__ -#pragma interface -#endif // Weapon info: sprite frames, ammunition use. @@ -45,8 +39,3 @@ typedef struct extern weaponinfo_t weaponinfo[NUMWEAPONS]; #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/d_iwad.c b/frosted-doom/d_iwad.c new file mode 100644 index 0000000..6a51ea8 --- /dev/null +++ b/frosted-doom/d_iwad.c @@ -0,0 +1,844 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Search for and locate an IWAD file, and initialize according +// to the IWAD type. +// + +#include +#include +#include +#include + +#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 + +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 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 + // + + 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 +#include + +#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 ; iconsoleplayer = 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 + // + // 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 + // + // 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
+ // @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 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 lowtic) + I_Error ("gametic>lowtic"); + + memcpy(local_playeringame, set->ingame, sizeof(local_playeringame)); + + loop_interface->RunTic(set->cmds, set->ingame); + gametic++; + + // modify command for duplicated tics + + TicdupSquash(set); + } + + NetUpdate (); // check for new console commands + } +} + +void D_RegisterLoopCallbacks(loop_interface_t *i) +{ + loop_interface = i; +} diff --git a/frosted-doom/d_loop.h b/frosted-doom/d_loop.h new file mode 100644 index 0000000..eb87d84 --- /dev/null +++ b/frosted-doom/d_loop.h @@ -0,0 +1,81 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Main loop stuff. +// + +#ifndef __D_LOOP__ +#define __D_LOOP__ + +#include "net_defs.h" + +// Callback function invoked while waiting for the netgame to start. +// The callback is invoked when new players are ready. The callback +// should return true, or return false to abort startup. + +typedef boolean (*netgame_startup_callback_t)(int ready_players, + int num_players); + +typedef struct +{ + // Read events from the event queue, and process them. + + void (*ProcessEvents)(); + + // Given the current input state, fill in the fields of the specified + // ticcmd_t structure with data for a new tic. + + void (*BuildTiccmd)(ticcmd_t *cmd, int maketic); + + // Advance the game forward one tic, using the specified player input. + + void (*RunTic)(ticcmd_t *cmds, boolean *ingame); + + // Run the menu (runs independently of the game). + + void (*RunMenu)(); +} loop_interface_t; + +// Register callback functions for the main loop code to use. +void D_RegisterLoopCallbacks(loop_interface_t *i); + +// Create any new ticcmds and broadcast to other players. +void NetUpdate (void); + +// Broadcasts special packets to other players +// to notify of game exit +void D_QuitNetGame (void); + +//? how many ticks to run? +void TryRunTics (void); + +// Called at start of game loop to initialize timers +void D_StartGameLoop(void); + +// Initialize networking code and connect to server. + +boolean D_InitNetGame(net_connect_data_t *connect_data); + +// Start game with specified settings. The structure will be updated +// with the actual settings for the game. + +void D_StartNetGame(net_gamesettings_t *settings, + netgame_startup_callback_t callback); + +extern boolean singletics; +extern int gametic, ticdup; + +#endif + diff --git a/frosted-doom/d_main.c b/frosted-doom/d_main.c index 337bc08..59f67d9 100644 --- a/frosted-doom/d_main.c +++ b/frosted-doom/d_main.c @@ -1,20 +1,16 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // DOOM main program (D_DoomMain) and game loop (D_DoomLoop), @@ -22,33 +18,26 @@ // 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 #include #include -#include -#include -#include -#include -#endif - +#include +#include "config.h" +#include "deh_main.h" #include "doomdef.h" #include "doomstat.h" #include "dstrings.h" +#include "doomfeatures.h" #include "sounds.h" +#include "d_iwad.h" #include "z_zone.h" +#include "w_main.h" #include "w_wad.h" #include "s_sound.h" #include "v_video.h" @@ -57,11 +46,16 @@ static const char rcsid[] = "$Id: d_main.c,v 1.8 1997/02/03 22:45:09 b1 Exp $"; #include "f_wipe.h" #include "m_argv.h" +#include "m_config.h" +#include "m_controls.h" #include "m_misc.h" #include "m_menu.h" +#include "p_saveg.h" +#include "i_endoom.h" +#include "i_joystick.h" #include "i_system.h" -#include "i_sound.h" +#include "i_timer.h" #include "i_video.h" #include "g_game.h" @@ -70,9 +64,13 @@ static const char rcsid[] = "$Id: d_main.c,v 1.8 1997/02/03 22:45:09 b1 Exp $"; #include "wi_stuff.h" #include "st_stuff.h" #include "am_map.h" +#include "net_client.h" +#include "net_dedicated.h" +#include "net_query.h" #include "p_setup.h" #include "r_local.h" +#include "statdump.h" #include "d_main.h" @@ -88,8 +86,13 @@ static const char rcsid[] = "$Id: d_main.c,v 1.8 1997/02/03 22:45:09 b1 Exp $"; // void D_DoomLoop (void); +// Location where savegames are stored -char* wadfiles[MAXWADFILES]; +char * savegamedir; + +// location of IWAD and WAD files + +char * iwadfile; boolean devparm; // started game with -devparm @@ -97,12 +100,6 @@ boolean nomonsters; // checkparm of -nomonsters boolean respawnparm; // checkparm of -respawn boolean fastparm; // checkparm of -fast -boolean drone; - -boolean singletics = false; // debug flag to cancel adaptiveness - - - //extern int soundVolume; //extern int sfxVolume; //extern int musicVolume; @@ -113,45 +110,27 @@ skill_t startskill; int startepisode; int startmap; boolean autostart; - -FILE* debugfile; +int startloadgame; boolean advancedemo; +// Store demo, do not accept any inputs +boolean storedemo; +// "BFG Edition" version of doom2.wad does not include TITLEPIC. +boolean bfgedition; +// If true, the main game loop has started. +boolean main_loop_started = false; char wadfile[1024]; // primary wad file char mapdir[1024]; // directory of development maps -char basedefault[1024]; // default file + +int show_endoom = 1; -void D_CheckNetGame (void); -void D_ProcessEvents (void); -void G_BuildTiccmd (ticcmd_t* cmd); -void D_DoAdvanceDemo (void); - - -// -// EVENT HANDLING -// -// Events are asynchronous inputs generally generated by the game user. -// Events can be discarded if no responder claims them -// -event_t events[MAXEVENTS]; -int eventhead; -int eventtail; - - -// -// D_PostEvent -// Called by the I/O functions when input is detected -// -void D_PostEvent (event_t* ev) -{ - events[eventhead] = *ev; - eventhead = (eventhead + 1) % MAXEVENTS; -} +void D_ConnectNetGame(void); +void D_CheckNetGame(void); // @@ -163,13 +142,11 @@ void D_ProcessEvents (void) event_t* ev; // IF STORE DEMO, DO NOT ACCEPT INPUT - if ( ( gamemode == commercial ) - && (W_CheckNumForName("map01")<0) ) - return; + if (storedemo) + return; - for ( ; eventtail != eventhead ; eventtail = (eventtail+1)%(MAXEVENTS) ) + while ((ev = D_PopEvent()) != NULL) { - ev = &events[eventtail]; if (M_Responder (ev)) continue; // menu ate the event G_Responder (ev); @@ -207,57 +184,57 @@ void D_Display (void) boolean redrawsbar; if (nodrawers) - return; // for comparative timing / profiling + return; // for comparative timing / profiling redrawsbar = false; // change the view size if needed if (setsizeneeded) { - R_ExecuteSetViewSize (); - oldgamestate = -1; // force background redraw - borderdrawcount = 3; + R_ExecuteSetViewSize (); + oldgamestate = -1; // force background redraw + borderdrawcount = 3; } // save the current screen if about to wipe if (gamestate != wipegamestate) - { - wipe = true; - wipe_StartScreen(0, 0, SCREENWIDTH, SCREENHEIGHT); + { + wipe = true; + wipe_StartScreen(0, 0, SCREENWIDTH, SCREENHEIGHT); } else - wipe = false; + wipe = false; if (gamestate == GS_LEVEL && gametic) - HU_Erase(); + HU_Erase(); // do buffered drawing switch (gamestate) { case GS_LEVEL: - if (!gametic) - break; - if (automapactive) - AM_Drawer (); - if (wipe || (viewheight != 200 && fullscreen) ) - redrawsbar = true; - if (inhelpscreensstate && !inhelpscreens) - redrawsbar = true; // just put away the help screen - ST_Drawer (viewheight == 200, redrawsbar ); - fullscreen = viewheight == 200; - break; + if (!gametic) + break; + if (automapactive) + AM_Drawer (); + if (wipe || (viewheight != 200 && fullscreen) ) + redrawsbar = true; + if (inhelpscreensstate && !inhelpscreens) + redrawsbar = true; // just put away the help screen + ST_Drawer (viewheight == 200, redrawsbar ); + fullscreen = viewheight == 200; + break; case GS_INTERMISSION: - WI_Drawer (); - break; + WI_Drawer (); + break; case GS_FINALE: - F_Drawer (); - break; + F_Drawer (); + break; case GS_DEMOSCREEN: - D_PageDrawer (); - break; + D_PageDrawer (); + break; } // draw buffered stuff to screen @@ -265,33 +242,39 @@ void D_Display (void) // draw the view directly if (gamestate == GS_LEVEL && !automapactive && gametic) - R_RenderPlayerView (&players[displayplayer]); + R_RenderPlayerView (&players[displayplayer]); if (gamestate == GS_LEVEL && gametic) - HU_Drawer (); + HU_Drawer (); // clean up border stuff if (gamestate != oldgamestate && gamestate != GS_LEVEL) - I_SetPalette (W_CacheLumpName ("PLAYPAL",PU_CACHE)); + I_SetPalette (W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE)); // see if the border needs to be initially drawn if (gamestate == GS_LEVEL && oldgamestate != GS_LEVEL) { - viewactivestate = false; // view was not active - R_FillBackScreen (); // draw the pattern into the back screen + viewactivestate = false; // view was not active + R_FillBackScreen (); // draw the pattern into the back screen } // see if the border needs to be updated to the screen if (gamestate == GS_LEVEL && !automapactive && scaledviewwidth != 320) { - if (menuactive || menuactivestate || !viewactivestate) - borderdrawcount = 3; - if (borderdrawcount) - { - R_DrawViewBorder (); // erase old menu stuff - borderdrawcount--; - } + if (menuactive || menuactivestate || !viewactivestate) + borderdrawcount = 3; + if (borderdrawcount) + { + R_DrawViewBorder (); // erase old menu stuff + borderdrawcount--; + } + } + if (testcontrols) + { + // Box showing current mouse speed + + V_DrawMouseSpeedBox(testcontrols_mousespeed); } menuactivestate = menuactive; @@ -302,12 +285,12 @@ void D_Display (void) // draw pause pic if (paused) { - if (automapactive) - y = 4; - else - y = viewwindowy+4; - V_DrawPatchDirect(viewwindowx+(scaledviewwidth-68)/2, - y,0,W_CacheLumpName ("M_PAUSE", PU_CACHE)); + if (automapactive) + y = 4; + else + y = viewwindowy+4; + V_DrawPatchDirect(viewwindowx + (scaledviewwidth - 68) / 2, y, + W_CacheLumpName (DEH_String("M_PAUSE"), PU_CACHE)); } @@ -334,7 +317,9 @@ void D_Display (void) { nowtime = I_GetTime (); tics = nowtime - wipestart; - } while (!tics); + I_Sleep(1); + } while (tics <= 0); + wipestart = nowtime; done = wipe_ScreenWipe(wipe_Melt , 0, 0, SCREENWIDTH, SCREENHEIGHT, tics); @@ -344,65 +329,131 @@ void D_Display (void) } while (!done); } +// +// Add configuration file variable bindings. +// +void D_BindVariables(void) +{ + int i; + + M_ApplyPlatformDefaults(); + + I_BindVideoVariables(); + I_BindJoystickVariables(); + I_BindSoundVariables(); + + M_BindBaseControls(); + M_BindWeaponControls(); + M_BindMapControls(); + M_BindMenuControls(); + M_BindChatControls(MAXPLAYERS); + + key_multi_msgplayer[0] = HUSTR_KEYGREEN; + key_multi_msgplayer[1] = HUSTR_KEYINDIGO; + key_multi_msgplayer[2] = HUSTR_KEYBROWN; + key_multi_msgplayer[3] = HUSTR_KEYRED; + +#ifdef FEATURE_MULTIPLAYER + NET_BindVariables(); +#endif + + M_BindVariable("mouse_sensitivity", &mouseSensitivity); + M_BindVariable("sfx_volume", &sfxVolume); + M_BindVariable("music_volume", &musicVolume); + M_BindVariable("show_messages", &showMessages); + M_BindVariable("screenblocks", &screenblocks); + M_BindVariable("detaillevel", &detailLevel); + M_BindVariable("snd_channels", &snd_channels); + M_BindVariable("vanilla_savegame_limit", &vanilla_savegame_limit); + M_BindVariable("vanilla_demo_limit", &vanilla_demo_limit); + M_BindVariable("show_endoom", &show_endoom); + + // Multiplayer chat macros + + for (i=0; i<10; ++i) + { + char buf[12]; + + M_snprintf(buf, sizeof(buf), "chatmacro%i", i); + M_BindVariable(buf, &chat_macros[i]); + } +} + +// +// D_GrabMouseCallback +// +// 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 // -extern boolean demorecording; - void D_DoomLoop (void) { - if (demorecording) - G_BeginRecording (); - - if (M_CheckParm ("-debugfile")) + if (bfgedition && + (demorecording || (gameaction == ga_playdemo) || netgame)) { - char filename[20]; - sprintf (filename,"debug%i.txt",consoleplayer); - printf ("debug output to: %s\n",filename); - debugfile = fopen (filename,"w"); + 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 (); + + 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) + { + 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 + // frame syncronous IO operations + I_StartFrame (); - // Update display, next frame, with current state. - D_Display (); + TryRunTics (); // will run at least one tic -#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 + S_UpdateSounds (players[consoleplayer].mo);// move positional sounds + + // Update display, next frame, with current state. + if (screenvisible) + { + D_Display (); + } } } @@ -433,7 +484,7 @@ void D_PageTicker (void) // void D_PageDrawer (void) { - V_DrawPatch (0,0, 0, W_CacheLumpName(pagename, PU_CACHE)); + V_DrawPatch (0, 0, W_CacheLumpName(pagename, PU_CACHE)); } @@ -451,7 +502,7 @@ void D_AdvanceDemo (void) // This cycles through the demo sequences. // FIXME - version dependend demo numbers? // - void D_DoAdvanceDemo (void) +void D_DoAdvanceDemo (void) { players[consoleplayer].playerstate = PST_LIVE; // not reborn advancedemo = false; @@ -459,7 +510,16 @@ void D_AdvanceDemo (void) paused = false; gameaction = ga_nothing; - if ( gamemode == retail ) + // The Ultimate Doom executable changed the demo sequence to add + // a DEMO4 demo. Final Doom was based on Ultimate, so also + // includes this change; however, the Final Doom IWADs do not + // include a DEMO4 lump, so the game bombs out with an error + // when it reaches this point in the demo sequence. + + // However! There is an alternate version of Final Doom that + // includes a fixed executable. + + if (gameversion == exe_ultimate || gameversion == exe_final) demosequence = (demosequence+1)%7; else demosequence = (demosequence+1)%6; @@ -468,33 +528,33 @@ void D_AdvanceDemo (void) { case 0: if ( gamemode == commercial ) - pagetic = 35 * 11; + pagetic = TICRATE * 11; else pagetic = 170; gamestate = GS_DEMOSCREEN; - pagename = "TITLEPIC"; + pagename = DEH_String("TITLEPIC"); if ( gamemode == commercial ) S_StartMusic(mus_dm2ttl); else S_StartMusic (mus_intro); break; case 1: - G_DeferedPlayDemo ("demo1"); + G_DeferedPlayDemo(DEH_String("demo1")); break; case 2: pagetic = 200; gamestate = GS_DEMOSCREEN; - pagename = "CREDIT"; + pagename = DEH_String("CREDIT"); break; case 3: - G_DeferedPlayDemo ("demo2"); + G_DeferedPlayDemo(DEH_String("demo2")); break; case 4: gamestate = GS_DEMOSCREEN; if ( gamemode == commercial) { - pagetic = 35 * 11; - pagename = "TITLEPIC"; + pagetic = TICRATE * 11; + pagename = DEH_String("TITLEPIC"); S_StartMusic(mus_dm2ttl); } else @@ -502,19 +562,27 @@ void D_AdvanceDemo (void) pagetic = 200; if ( gamemode == retail ) - pagename = "CREDIT"; + pagename = DEH_String("CREDIT"); else - pagename = "HELP2"; + pagename = DEH_String("HELP2"); } break; case 5: - G_DeferedPlayDemo ("demo3"); + G_DeferedPlayDemo(DEH_String("demo3")); break; // THE DEFINITIVE DOOM Special Edition demo case 6: - G_DeferedPlayDemo ("demo4"); + G_DeferedPlayDemo(DEH_String("demo4")); break; } + + // The Doom 3: BFG Edition version of doom2.wad does not have a + // TITLETPIC lump. Use INTERPIC instead as a workaround. + if (bfgedition && !strcasecmp(pagename, "TITLEPIC") + && W_CheckNumForName("titlepic") < 0) + { + pagename = DEH_String("INTERPIC"); + } } @@ -529,364 +597,736 @@ void D_StartTitle (void) D_AdvanceDemo (); } +// Strings for dehacked replacements of the startup banner +// +// These are from the original source: some of them are perhaps +// not used in any dehacked patches +static char *banners[] = +{ + // doom2.wad + " " + "DOOM 2: Hell on Earth v%i.%i" + " ", + // doom1.wad + " " + "DOOM Shareware Startup v%i.%i" + " ", + // doom.wad + " " + "DOOM Registered Startup v%i.%i" + " ", + // Registered DOOM uses this + " " + "DOOM System Startup v%i.%i" + " ", + // doom.wad (Ultimate DOOM) + " " + "The Ultimate DOOM Startup v%i.%i" + " ", + // tnt.wad + " " + "DOOM 2: TNT - Evilution v%i.%i" + " ", + // plutonia.wad + " " + "DOOM 2: Plutonia Experiment v%i.%i" + " ", +}; +// +// Get game name: if the startup banner has been replaced, use that. +// Otherwise, use the name given +// + +static char *GetGameName(char *gamename) +{ + size_t i; + char *deh_sub; + + for (i=0; i 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 + // + // 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 + +void D_SetGameDescription(void) +{ + boolean is_freedoom = W_CheckNumForName("FREEDOOM") >= 0, + is_freedm = W_CheckNumForName("FREEDM") >= 0; + + gamedescription = "Unknown"; + + if (logical_gamemission == doom) + { + // 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"); + } + } + else + { + // 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"); + } + } +} // print title for every printed line char title[128]; - - -// -// D_AddFile -// -void D_AddFile (char *file) +static boolean D_AddFile(char *filename) { - int numwadfiles; - char *newfile; - - for (numwadfiles = 0 ; wadfiles[numwadfiles] ; numwadfiles++) - ; + wad_file_t *handle; - newfile = malloc (strlen(file)+1); - strcpy (newfile, file); - - wadfiles[numwadfiles] = newfile; + printf(" adding %s\n", filename); + handle = W_AddFile(filename); + + return handle != NULL; } -// -// IdentifyVersion -// Checks availability of IWAD files by name, -// to determine whether registered/commercial features -// should be executed (notably loading PWAD's). -// -void IdentifyVersion (void) +// Copyright message banners +// Some dehacked mods replace these. These are only displayed if they are +// replaced by dehacked. + +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", - char* doom1wad; - char* doomwad; - char* doomuwad; - char* doom2wad; + "===========================================================================\n" + " Commercial product - do not distribute!\n" + " Please report software piracy to the SPA: 1-800-388-PIR8\n" + "===========================================================================\n", - char* doom2fwad; - char* plutoniawad; - char* tntwad; + "===========================================================================\n" + " Shareware!\n" + "===========================================================================\n" +}; -#ifdef NORMALUNIX - char *home; - char *doomwaddir; - doomwaddir = getenv("DOOMWADDIR"); -#ifdef __linux__ - doomwaddir = "."; -#endif - if (!doomwaddir) - doomwaddir = "/mnt"; +// Prints a message only if it has been modified by dehacked. - // Commercial. - doom2wad = malloc(strlen(doomwaddir)+1+9+1); - sprintf(doom2wad, "%s/doom2.wad", doomwaddir); +void PrintDehackedBanners(void) +{ + size_t i; - // Retail. - doomuwad = malloc(strlen(doomwaddir)+1+9+1); - sprintf(doomuwad, "%s/doomu.wad", doomwaddir); + for (i=0; i + // @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 (p) + { + 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]); + } + } + else + { + // 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; + } + } + } - // 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); + // The original exe does not support retail - 4th episode not supported - // Bug, dear Shawn. - // Insufficient malloc, caused spurious realloc errors. - plutoniawad = malloc(strlen(doomwaddir)+1+/*9*/12+1); - sprintf(plutoniawad, "%s/plutonia.wad", doomwaddir); - - tntwad = malloc(strlen(doomwaddir)+1+9+1); - sprintf(tntwad, "%s/tnt.wad", doomwaddir); - - - // French stuff. - doom2fwad = malloc(strlen(doomwaddir)+1+10+1); - sprintf(doom2fwad, "%s/doom2f.wad", doomwaddir); - - //home = getenv("HOME"); - home = "/mnt"; - if (!home) - I_Error("Please set $HOME to your home directory"); - sprintf(basedefault, "%s/.doomrc", home); -#endif - - if (M_CheckParm ("-shdev")) + if (gameversion < exe_ultimate && gamemode == retail) { - 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; + gamemode = registered; } - if (M_CheckParm ("-regdev")) + // 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 = 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; + gamemission = doom2; } - - 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; - } - - if ( !access (doom2fwad,R_OK) ) - { - gamemode = commercial; - // C'est ridicule! - // Let's handle languages in config files, okay? - language = french; - printf("French version\n"); - D_AddFile (doom2fwad); - return; - } - - if ( !access (doom2wad,R_OK) ) - { - gamemode = commercial; - D_AddFile (doom2wad); - return; - } - - if ( !access (plutoniawad, R_OK ) ) - { - gamemode = commercial; - D_AddFile (plutoniawad); - return; - } - - if ( !access ( tntwad, R_OK ) ) - { - gamemode = commercial; - D_AddFile (tntwad); - return; - } - - if ( !access (doomuwad,R_OK) ) - { - gamemode = retail; - D_AddFile (doomuwad); - return; - } - - if ( !access (doomwad,R_OK) ) - { - gamemode = registered; - D_AddFile (doomwad); - return; - } - - if ( !access (doom1wad,R_OK) ) - { - gamemode = shareware; - D_AddFile (doom1wad); - return; - } - - printf("Game mode indeterminate.\n"); - gamemode = indetermined; - - // We don't abort. Let's see what the PWAD contains. - //exit(1); - //I_Error ("Game mode indeterminate\n"); } -// -// Find a Response File -// -void FindResponseFile (void) +void PrintGameVersion(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 0) + { + return; + } + + endoom = W_CacheLumpName(DEH_String("ENDOOM"), PU_STATIC); + + I_Endoom(endoom); +} + +#if ORIGCODE +// Load dehacked patches needed for certain IWADs. +static void LoadIwadDeh(void) +{ + // 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); + } + + // 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
+ // @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 + // @vanilla + // + // Turbo mode. The player's speed is multiplied by x%. If unspecified, + // x defaults to 200. Values are rounded up to 10 and down to 400. + // + if ( (p=M_CheckParm ("-turbo")) ) { int scale = 200; @@ -899,132 +1339,221 @@ void D_DoomMain (void) scale = 10; if (scale > 400) scale = 400; - printf ("turbo scale: %i%%\n",scale); + DEH_printf("turbo scale: %i%%\n", scale); forwardmove[0] = forwardmove[0]*scale/100; forwardmove[1] = forwardmove[1]*scale/100; sidemove[0] = sidemove[0]*scale/100; sidemove[1] = sidemove[1]*scale/100; } - // add any files specified on the command line with -file wadfile - // to the wad list - // - // convenience hack to allow -wart e m to add a wad file - // prepend a tilde to the filename so wadfile will be reloadable - p = M_CheckParm ("-wart"); - if (p) - { - myargv[p][4] = 'p'; // big hack, change to -warp - - // 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) - { - // 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]); - } - - p = M_CheckParm ("-playdemo"); - - if (!p) - p = M_CheckParm ("-timedemo"); - - if (p && p < myargc-1) - { - sprintf (file,"%s.lmp", myargv[p+1]); - D_AddFile (file); - printf("Playing demo %s.lmp.\n",myargv[p+1]); - } - - // get skill / episode / map from parms - startskill = sk_medium; - startepisode = 1; - startmap = 1; - autostart = false; - - - p = M_CheckParm ("-skill"); - if (p && p < myargc-1) - { - startskill = myargv[p+1][0]-'1'; - autostart = true; - } - - p = M_CheckParm ("-episode"); - if (p && p < myargc-1) - { - startepisode = myargv[p+1][0]-'0'; - startmap = 1; - autostart = true; - } - - p = M_CheckParm ("-timer"); - if (p && p < myargc-1 && deathmatch) - { - int time; - time = atoi(myargv[p+1]); - printf("Levels will end after %d minute",time); - if (time>1) - printf("s"); - printf(".\n"); - } - - p = M_CheckParm ("-avg"); - if (p && p < myargc-1 && deathmatch) - printf("Austin Virtual Gaming: Levels will end after 20 minutes\n"); - - p = M_CheckParm ("-warp"); - if (p && p < myargc-1) - { - if (gamemode == commercial) - startmap = atoi (myargv[p+1]); - else - { - startepisode = myargv[p+1][0]-'0'; - startmap = myargv[p+2][0]-'0'; - } - autostart = true; - } - // init subsystems - printf ("V_Init: allocate screens.\n"); + DEH_printf("V_Init: allocate screens.\n"); V_Init (); - printf ("M_LoadDefaults: Load system defaults.\n"); - M_LoadDefaults (); // load before initing other systems + // 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(); - printf ("Z_Init: Init zone memory allocation daemon. \n"); - Z_Init (); + // Save configuration at exit. + I_AtExit(M_SaveDefaults, false); - printf ("W_Init: Init WADfiles.\n"); - W_InitMultipleFiles (wadfiles); - + // Find main IWAD file and load it. + iwadfile = D_FindIWAD(IWAD_MASK_DOOM, &gamemission); + + // None found? + + if (iwadfile == NULL) + { + I_Error("Game mode indeterminate. No IWAD file was found. Try\n" + "specifying one with the '-iwad' command line parameter.\n"); + } + + modifiedgame = false; + + 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 ORIGCODE + //! + // @category mod + // + // Disable automatic loading of Dehacked patches for certain + // IWAD files. + // + if (!M_ParmExists("-nodeh")) + { + // Some IWADs have dehacked patches that need to be loaded for + // them to be played properly. + LoadIwadDeh(); + } +#endif + + // 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) + { + 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"); + } + +#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 + // @category demo + // @vanilla + // + // Play back the demo named demo.lmp. + // + + p = M_CheckParmWithArgs ("-playdemo", 1); + + if (!p) + { + //! + // @arg + // @category demo + // @vanilla + // + // Play back the demo named demo.lmp, determining the framerate + // of the screen. + // + p = M_CheckParmWithArgs("-timedemo", 1); + + } + + if (p) + { + // 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); + } + + 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. + +#if ORIGCODE + //! + // @category mod + // + // Load Dehacked patches from DEHACKED lumps contained in one of the + // loaded PWAD files. + // + if (M_ParmExists("-dehlump")) + { + 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); + } +#endif + + // Set the gamedescription string. This is only possible now that + // we've finished loading Dehacked patches. + D_SetGameDescription(); + +#ifdef _WIN32 + // In -cdrom mode, we write savegames to c:\doomdata as well as configs. + if (M_ParmExists("-cdrom")) + { + savegamedir = configdir; + } + else +#endif + { + savegamedir = M_GetSaveGameDir(D_SaveGameIWADName(gamemission)); + } // Check for -file in shareware if (modifiedgame) @@ -1040,137 +1569,272 @@ void D_DoomMain (void) int i; if ( gamemode == shareware) - I_Error("\nYou cannot -file with the shareware " - "version. Register!"); + I_Error(DEH_String("\nYou cannot -file with the shareware " + "version. Register!")); // Check for fake IWAD with right name, // but w/o all the lumps of the registered version. if (gamemode == registered) for (i = 0;i < 23; i++) if (W_CheckNumForName(name[i])<0) - I_Error("\nThis is not the registered version."); - } - - // Iff additonal PWAD files are used, print modified banner - if (modifiedgame) - { - /*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 (); - } - - - // Check and print which version is executed. - switch ( gamemode ) - { - 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; - - default: - // Ouch. - break; + I_Error(DEH_String("\nThis is not the registered version.")); } - printf ("M_Init: Init miscellaneous info.\n"); - M_Init (); - - printf ("R_Init: Init DOOM refresh daemon - "); - R_Init (); - - printf ("\nP_Init: Init Playloop state.\n"); - P_Init (); - - printf ("I_Init: Setting up machine state.\n"); - I_Init (); - - 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*/ ); - - printf ("HU_Init: Setting up heads up display.\n"); - HU_Init (); - - printf ("ST_Init: Init status bar.\n"); - ST_Init (); - - // check for a driver that wants intermission stats - p = M_CheckParm ("-statcopy"); - if (p && p= 0 + || W_CheckNumForName("FF_END") >= 0) { - // for statistics driver - extern void* statcopy; - - statcopy = (void*)atoi(myargv[p+1]); - printf ("External statistics registered.\n"); + 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"); } - - // start the apropriate game based on parms - p = M_CheckParm ("-record"); - if (p && p < myargc-1) + 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) { - G_RecordDemo (myargv[p+1]); + 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 + // @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 + // @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; } - p = M_CheckParm ("-playdemo"); - if (p && p < myargc-1) - { - singledemo = true; // quit after one demo - G_DeferedPlayDemo (myargv[p+1]); - D_DoomLoop (); // never returns - } - - p = M_CheckParm ("-timedemo"); - if (p && p < myargc-1) - { - G_TimeDemo (myargv[p+1]); - D_DoomLoop (); // never returns - } - - p = M_CheckParm ("-loadgame"); - if (p && p < myargc-1) - { - 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); - } - + timelimit = 0; - if ( gameaction != ga_loadgame ) - { - if (autostart || netgame) - G_InitNew (startskill, startepisode, startmap); - else - D_StartTitle (); // start up intro loop + //! + // @arg + // @category net + // @vanilla + // + // For multiplayer games: exit each level after n minutes. + // + p = M_CheckParmWithArgs("-timer", 1); + + if (p) + { + timelimit = atoi(myargv[p+1]); + } + + //! + // @category net + // @vanilla + // + // Austin Virtual Gaming: end levels after 20 minutes. + // + + p = M_CheckParm ("-avg"); + + if (p) + { + timelimit = 20; + } + + //! + // @arg [ | ] + // @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 + // @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 (); + + DEH_printf("R_Init: Init DOOM refresh daemon - "); + R_Init (); + + DEH_printf("\nP_Init: Init Playloop state.\n"); + P_Init (); + + DEH_printf("S_Init: Setting up sound.\n"); + S_Init (sfxVolume * 8, musicVolume * 8); + + DEH_printf("D_CheckNetGame: Checking network game status.\n"); + D_CheckNetGame (); + + PrintGameVersion(); + + DEH_printf("HU_Init: Setting up heads up display.\n"); + HU_Init (); + + DEH_printf("ST_Init: Init status bar.\n"); + ST_Init (); + + // 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. + + if (gamemode == commercial && W_CheckNumForName("map01") < 0) + storedemo = true; + + if (M_CheckParmWithArgs("-statdump", 1)) + { + I_AtExit(StatDump, true); + DEH_printf("External statistics registered.\n"); + } + + //! + // @arg + // @category demo + // @vanilla + // + // Record a demo named x.lmp. + // + + p = M_CheckParmWithArgs("-record", 1); + + if (p) + { + G_RecordDemo (myargv[p+1]); + autostart = true; + } + + p = M_CheckParmWithArgs("-playdemo", 1); + if (p) + { + singledemo = true; // quit after one demo + G_DeferedPlayDemo (demolumpname); + D_DoomLoop (); // never returns + } + + p = M_CheckParmWithArgs("-timedemo", 1); + if (p) + { + G_TimeDemo (demolumpname); + D_DoomLoop (); // never returns + } + + if (startloadgame >= 0) + { + 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 } + diff --git a/frosted-doom/d_main.h b/frosted-doom/d_main.h index 7763e13..0fe9547 100644 --- a/frosted-doom/d_main.h +++ b/frosted-doom/d_main.h @@ -1,56 +1,33 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // System specific interface stuff. // -//----------------------------------------------------------------------------- #ifndef __D_MAIN__ #define __D_MAIN__ -#include "d_event.h" - -#ifdef __GNUG__ -#pragma interface -#endif +#include "doomdef.h" -#define MAXWADFILES 20 -extern char* wadfiles[MAXWADFILES]; -void D_AddFile (char *file); - - - -// -// 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); +// Read events from all input devices +void D_ProcessEvents (void); // @@ -59,6 +36,15 @@ void D_PostEvent (event_t* ev); void D_PageTicker (void); void D_PageDrawer (void); void D_AdvanceDemo (void); +void D_DoAdvanceDemo (void); void D_StartTitle (void); + +// +// GLOBAL VARIABLES +// + +extern gameaction_t gameaction; + #endif + diff --git a/frosted-doom/d_mode.c b/frosted-doom/d_mode.c new file mode 100644 index 0000000..afd84ac --- /dev/null +++ b/frosted-doom/d_mode.c @@ -0,0 +1,209 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// +// DESCRIPTION: +// Functions and definitions relating to the game type and operational +// mode. +// + +#include "doomtype.h" +#include "d_mode.h" + +// Valid game mode/mission combinations, with the number of +// episodes/maps for each. + +static struct +{ + GameMission_t mission; + GameMode_t mode; + int episode; + int map; +} valid_modes[] = { + { pack_chex, shareware, 1, 5 }, + { doom, shareware, 1, 9 }, + { doom, registered, 3, 9 }, + { doom, retail, 4, 9 }, + { doom2, commercial, 1, 32 }, + { pack_tnt, commercial, 1, 32 }, + { pack_plut, commercial, 1, 32 }, + { pack_hacx, commercial, 1, 32 }, + { heretic, shareware, 1, 9 }, + { heretic, registered, 3, 9 }, + { heretic, retail, 5, 9 }, + { hexen, commercial, 1, 60 }, + { strife, commercial, 1, 34 }, +}; + +// Check that a gamemode+gamemission received over the network is valid. + +boolean D_ValidGameMode(GameMission_t mission, GameMode_t mode) +{ + int i; + + for (i=0; i= 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= 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 -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]; - -int nodeforplayer[MAXPLAYERS]; - -int maketic; -int lastnettic; -int skiptics; -int ticdup; -int maxsend; // BACKUPTICS/(2*ticdup)-1 - - -void D_ProcessEvents (void); -void G_BuildTiccmd (ticcmd_t *cmd); -void D_DoAdvanceDemo (void); - -boolean reboundpacket; -doomdata_t reboundstore; - - - -// -// -// -int NetbufferSize (void) +static void PlayerQuitGame(player_t *player) { - return (int)&(((doomdata_t *)0)->cmds[netbuffer->numtics]); + static char exitmsg[80]; + unsigned int player_num; + + player_num = player - players; + + // 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)); + + exitmsg[7] += player_num; + + playeringame[player_num] = false; + players[consoleplayer].message = exitmsg; + + // TODO: check if it is sensible to do this: + + 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 - - l = (NetbufferSize () - (int)&(((doomdata_t *)0)->retransmitfrom))/4; - for (i=0 ; iretransmitfrom)[i] * (i+1); - - return c & NCMD_CHECKSUM; -} - -// -// -// -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; -} - - - -// -// HSendPacket -// -void -HSendPacket - (int node, - int flags ) -{ - netbuffer->checksum = NetbufferChecksum () | flags; - - if (!node) + for (i = 0; i < MAXPLAYERS; ++i) { - reboundstore = *netbuffer; - reboundpacket = true; - return; - } - - 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) - { - 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 ; idatalength ; i++) - fprintf (debugfile,"%i ",((byte *)netbuffer)[i]); - - fprintf (debugfile,"\n"); - } - - I_NetCmd (); -} - -// -// HGetPacket -// Returns false if no packet is waiting -// -boolean HGetPacket (void) -{ - if (reboundpacket) - { - *netbuffer = reboundstore; - doomcom->remotenode = 0; - reboundpacket = false; - return true; - } - - if (!netgame) - return false; - - if (demoplayback) - return false; - - doomcom->command = CMD_GET; - I_NetCmd (); - - if (doomcom->remotenode == -1) - return false; - - if (doomcom->datalength != NetbufferSize ()) - { - 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; - } - - if (debugfile) - { - 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 ; idatalength ; i++) - fprintf (debugfile,"%i ",((byte *)netbuffer)[i]); - fprintf (debugfile,"\n"); - } - } - return true; -} - - -// -// GetPackets -// -char exitmsg[80]; - -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 + if (!demoplayback && playeringame[i] && !ingame[i]) { - int start; + PlayerQuitGame(&players[i]); + } + } - remoteresend[netnode] = false; - - start = nettics[netnode] - realstart; - src = &netbuffer->cmds[start]; + netcmds = cmds; - while (nettics[netnode] < realend) - { - dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS]; - nettics[netnode]++; - *dest = *src; - src++; - } - } + // check that there are players in the game. if not, we cannot + // run a tic. + + if (advancedemo) + D_DoAdvanceDemo (); + + G_Ticker (); +} + +static loop_interface_t doom_loop_interface = { + D_ProcessEvents, + G_BuildTiccmd, + RunTic, + M_Ticker +}; + + +// Load game settings from the specified structure and +// set global variables. + +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) + { + printf("NOTE: Turning resolution is reduced; this is probably " + "because there is a client recording a Vanilla demo.\n"); + } + + for (i = 0; i < MAXPLAYERS; ++i) + { + playeringame[i] = i < settings->num_players; } } +// Save the game settings from global variables to the specified +// game settings structure. -// -// NetUpdate -// Builds ticcmds for console player, -// sends out a packet -// -int gametime; - -void NetUpdate (void) +static void SaveGameSettings(net_gamesettings_t *settings) { - 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; + // Fill in game settings structure with appropriate parameters + // for the new game - 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= BACKUPTICS/2-1) - break; // can't hold any more - - //printf ("mk:%i ",maketic); - G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]); - maketic++; - } + 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; - - if (singletics) - return; // singletic update is syncronous - - // send the packet to the other nodes - for (i=0 ; inumnodes ; 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 (); + settings->lowres_turn = M_CheckParm("-record") > 0 + && M_CheckParm("-longtics") == 0; } - - -// -// CheckAbort -// -void CheckAbort (void) +static void InitConnectData(net_connect_data_t *connect_data) { - 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."); - } -} + connect_data->max_players = MAXPLAYERS; + connect_data->drone = false; + //! + // @category net + // + // Run as the left screen in three screen mode. + // -// -// D_ArbitrateNetStart -// -void D_ArbitrateNetStart (void) -{ - int i; - boolean gotinfo[MAXNETNODES]; - - autostart = true; - memset (gotinfo,0,sizeof(gotinfo)); - - if (doomcom->consoleplayer) + if (M_CheckParm("-left") > 0) { - // 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; - } - } + viewangleoffset = ANG90; + connect_data->drone = true; } - else - { - // key player, send the setup info - printf ("sending network start info...\n"); - do - { - CheckAbort (); - for (i=0 ; inumnodes ; 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; - } + //! + // @category net + // + // Run as the right screen in three screen mode. + // + + if (M_CheckParm("-right") > 0) + { + viewangleoffset = ANG270; + connect_data->drone = true; + } + + // + // Connect data + // + + // Game type fields: + + connect_data->gamemode = gamemode; + connect_data->gamemission = gamemission; + + // Are we recording a demo? Possibly set lowres turn mode + + connect_data->lowres_turn = M_CheckParm("-record") > 0 + && M_CheckParm("-longtics") == 0; + + // Read checksums of our WAD directory and dehacked information + + W_Checksum(connect_data->wad_sha1sum); + +#if ORIGCODE + DEH_Checksum(connect_data->deh_sha1sum); #endif - for (i=1 ; inumnodes ; i++) - if (!gotinfo[i]) - break; - } while (i < doomcom->numnodes); + // Are we playing with the Freedoom IWAD? + + connect_data->is_freedoom = W_CheckNumForName("FREEDOOM") >= 0; +} + +void D_ConnectNetGame(void) +{ + net_connect_data_t connect_data; + + InitConnectData(&connect_data); + netgame = D_InitNetGame(&connect_data); + + //! + // @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. + // + + if (M_CheckParm("-solo-net") > 0) + { + netgame = true; } } @@ -550,218 +237,45 @@ void D_ArbitrateNetStart (void) // D_CheckNetGame // Works out player numbers among the net participants // -extern int viewangleoffset; - void D_CheckNetGame (void) { - int i; - - for (i=0 ; iid != DOOMCOM_ID) - I_Error ("Doomcom buffer invalid!"); - - netbuffer = &doomcom->data; - consoleplayer = displayplayer = doomcom->consoleplayer; + net_gamesettings_t settings; + 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 ; inumplayers ; i++) - playeringame[i] = true; - for (i=0 ; inumnodes ; i++) - nodeingame[i] = true; - - printf ("player %i of %i (%i nodes)\n", - consoleplayer+1, doomcom->numplayers, doomcom->numnodes); - -} - - -// -// 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++) { - for (j=1 ; jnumnodes ; 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); + + DEH_printf("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", + startskill, deathmatch, startmap, startepisode); + + DEH_printf("player %i of %i (%i nodes)\n", + consoleplayer+1, settings.num_players, settings.num_players); + + // Show players here; the server might have specified a time limit + + if (timelimit > 0 && deathmatch) + { + // 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"); + } } } - - -// -// TryRunTics -// -int frametics[4]; -int frameon; -int frameskip[4]; -int oldnettics; - -extern boolean advancedemo; - -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 ; inumnodes ; 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 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 ; inumnodes ; 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--) - { - for (i=0 ; i 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 ; jchatchar = 0; - if (cmd->buttons & BT_SPECIAL) - cmd->buttons = 0; - } - } - } - NetUpdate (); // check for new console commands - } -} diff --git a/frosted-doom/d_net.h b/frosted-doom/d_net.h deleted file mode 100644 index b277472..0000000 --- a/frosted-doom/d_net.h +++ /dev/null @@ -1,149 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// DESCRIPTION: -// Networking stuff. -// -//----------------------------------------------------------------------------- - - -#ifndef __D_NET__ -#define __D_NET__ - -#include "d_player.h" - - -#ifdef __GNUG__ -#pragma interface -#endif - - -// -// Network play related stuff. -// There is a data struct that stores network -// communication related stuff, and another -// one that defines the actual packets to -// be transmitted. -// - -#define DOOMCOM_ID 0x12345678l - -// Max computers/players in a game. -#define MAXNETNODES 8 - - -// Networking and tick handling related. -#define BACKUPTICS 12 - -typedef enum -{ - CMD_SEND = 1, - CMD_GET = 2 - -} command_t; - - -// -// Network packet data. -// -typedef struct -{ - // High bit is retransmit request. - unsigned checksum; - // Only valid if NCMD_RETRANSMIT. - byte retransmitfrom; - - byte starttic; - byte player; - byte numtics; - ticcmd_t cmds[BACKUPTICS]; - -} doomdata_t; - - - - -typedef struct -{ - // Supposed to be DOOMCOM_ID? - long id; - - // DOOM executes an int to execute commands. - short intnum; - // Communication between DOOM and the driver. - // Is CMD_SEND or CMD_GET. - short command; - // Is dest for send, set by get (-1 = no packet). - short remotenode; - - // Number of bytes in doomdata to be sent - short datalength; - - // Info common to all nodes. - // Console is allways node 0. - short numnodes; - // Flag: 1 = no duplication, 2-5 = dup for slow nets. - short ticdup; - // Flag: 1 = send a backup tic in every packet. - short extratics; - // Flag: 1 = deathmatch. - short deathmatch; - // Flag: -1 = new game, 0-5 = load savegame - short savegame; - short episode; // 1-3 - short map; // 1-9 - short skill; // 1-5 - - // Info specific to this node. - short consoleplayer; - short numplayers; - - // These are related to the 3-display mode, - // in which two drones looking left and right - // were used to render two additional views - // on two additional computers. - // Probably not operational anymore. - // 1 = left, 0 = center, -1 = right - short angleoffset; - // 1 = drone - short drone; - - // The packet data to be sent. - doomdata_t data; - -} doomcom_t; - - - -// Create any new ticcmds and broadcast to other players. -void NetUpdate (void); - -// Broadcasts special packets to other players -// to notify of game exit -void D_QuitNetGame (void); - -//? how many ticks to run? -void TryRunTics (void); - - -#endif - -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- - diff --git a/frosted-doom/d_player.h b/frosted-doom/d_player.h index 0a4d887..a72c2f5 100644 --- a/frosted-doom/d_player.h +++ b/frosted-doom/d_player.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // // -//----------------------------------------------------------------------------- #ifndef __D_PLAYER__ @@ -40,9 +37,7 @@ // as commands per game tick. #include "d_ticcmd.h" -#ifdef __GNUG__ -#pragma interface -#endif +#include "net_defs.h" @@ -212,8 +207,3 @@ typedef struct #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/d_textur.h b/frosted-doom/d_textur.h index 3624efb..1afe040 100644 --- a/frosted-doom/d_textur.h +++ b/frosted-doom/d_textur.h @@ -1,24 +1,21 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Typedefs related to to textures etc., // isolated here to make it easier separating modules. // -//----------------------------------------------------------------------------- #ifndef __D_TEXTUR__ @@ -44,8 +41,3 @@ typedef struct #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/d_think.h b/frosted-doom/d_think.h index 6a58165..0966ad9 100644 --- a/frosted-doom/d_think.h +++ b/frosted-doom/d_think.h @@ -1,34 +1,28 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // MapObj data. Map Objects or mobjs are actors, entities, // thinker, take-your-pick... anything that moves, acts, or // suffers state changes of more or less violent nature. // -//----------------------------------------------------------------------------- #ifndef __D_THINK__ #define __D_THINK__ -#ifdef __GNUG__ -#pragma interface -#endif @@ -44,8 +38,8 @@ typedef void (*actionf_p2)( void*, void* ); typedef union { - actionf_p1 acp1; actionf_v acv; + actionf_p1 acp1; actionf_p2 acp2; } actionf_t; @@ -72,8 +66,3 @@ typedef struct thinker_s #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/d_ticcmd.h b/frosted-doom/d_ticcmd.h index 5817989..daf0da3 100644 --- a/frosted-doom/d_ticcmd.h +++ b/frosted-doom/d_ticcmd.h @@ -1,23 +1,21 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 1993-2008 Raven Software +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // System specific interface stuff. // -//----------------------------------------------------------------------------- #ifndef __D_TICCMD__ @@ -25,29 +23,34 @@ #include "doomtype.h" -#ifdef __GNUG__ -#pragma interface -#endif // The data sampled per tick (single player) // and transmitted to other peers (multiplayer). // Mainly movements/button commands per game tick, // plus a checksum for internal state consistency. + typedef struct { - char forwardmove; // *2048 for move - char sidemove; // *2048 for move - short angleturn; // <<16 for angle delta - short consistancy; // checks for net game - byte chatchar; - byte buttons; + signed char forwardmove; // *2048 for move + signed char sidemove; // *2048 for move + short angleturn; // <<16 for angle delta + byte chatchar; + byte buttons; + // villsa [STRIFE] according to the asm, + // consistancy is a short, not a byte + byte consistancy; // checks for net game + + // villsa - Strife specific: + + byte buttons2; + int inventory; + + // Heretic/Hexen specific: + + byte lookfly; // look/fly up/down/centering + byte arti; // artitype_t to use } ticcmd_t; #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/deh_main.h b/frosted-doom/deh_main.h new file mode 100644 index 0000000..10ac236 --- /dev/null +++ b/frosted-doom/deh_main.h @@ -0,0 +1,48 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// +// Dehacked entrypoint and common code +// + +#ifndef DEH_MAIN_H +#define DEH_MAIN_H + +#include "doomtype.h" +#include "doomfeatures.h" +#include "deh_str.h" +#include "sha1.h" + +// These are the limits that dehacked uses (from dheinit.h in the dehacked +// source). If these limits are exceeded, it does not generate an error, but +// a warning is displayed. + +#define DEH_VANILLA_NUMSTATES 966 +#define DEH_VANILLA_NUMSFX 107 + +void DEH_ParseCommandLine(void); +int DEH_LoadFile(char *filename); +int DEH_LoadLump(int lumpnum, boolean allow_long, boolean allow_error); +int DEH_LoadLumpByName(char *name, boolean allow_long, boolean allow_error); + +boolean DEH_ParseAssignment(char *line, char **variable_name, char **value); + +void DEH_Checksum(sha1_digest_t digest); + +extern boolean deh_allow_extended_strings; +extern boolean deh_allow_long_strings; +extern boolean deh_allow_long_cheats; +extern boolean deh_apply_cheats; + +#endif /* #ifndef DEH_MAIN_H */ + diff --git a/frosted-doom/deh_misc.h b/frosted-doom/deh_misc.h new file mode 100644 index 0000000..319a145 --- /dev/null +++ b/frosted-doom/deh_misc.h @@ -0,0 +1,83 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// +// Parses "Misc" sections in dehacked files +// + +#ifndef DEH_MISC_H +#define DEH_MISC_H + +#include "doomfeatures.h" + +#define DEH_DEFAULT_INITIAL_HEALTH 100 +#define DEH_DEFAULT_INITIAL_BULLETS 50 +#define DEH_DEFAULT_MAX_HEALTH 200 +#define DEH_DEFAULT_MAX_ARMOR 200 +#define DEH_DEFAULT_GREEN_ARMOR_CLASS 1 +#define DEH_DEFAULT_BLUE_ARMOR_CLASS 2 +#define DEH_DEFAULT_MAX_SOULSPHERE 200 +#define DEH_DEFAULT_SOULSPHERE_HEALTH 100 +#define DEH_DEFAULT_MEGASPHERE_HEALTH 200 +#define DEH_DEFAULT_GOD_MODE_HEALTH 100 +#define DEH_DEFAULT_IDFA_ARMOR 200 +#define DEH_DEFAULT_IDFA_ARMOR_CLASS 2 +#define DEH_DEFAULT_IDKFA_ARMOR 200 +#define DEH_DEFAULT_IDKFA_ARMOR_CLASS 2 +#define DEH_DEFAULT_BFG_CELLS_PER_SHOT 40 +#define DEH_DEFAULT_SPECIES_INFIGHTING 0 + +#ifdef FEATURE_DEHACKED + +extern int deh_initial_health; +extern int deh_initial_bullets; +extern int deh_max_health; +extern int deh_max_armor; +extern int deh_green_armor_class; +extern int deh_blue_armor_class; +extern int deh_max_soulsphere; +extern int deh_soulsphere_health; +extern int deh_megasphere_health; +extern int deh_god_mode_health; +extern int deh_idfa_armor; +extern int deh_idfa_armor_class; +extern int deh_idkfa_armor; +extern int deh_idkfa_armor_class; +extern int deh_bfg_cells_per_shot; +extern int deh_species_infighting; + +#else + +// If dehacked is disabled, hard coded values + +#define deh_initial_health DEH_DEFAULT_INITIAL_HEALTH +#define deh_initial_bullets DEH_DEFAULT_INITIAL_BULLETS +#define deh_max_health DEH_DEFAULT_MAX_HEALTH +#define deh_max_armor DEH_DEFAULT_MAX_ARMOR +#define deh_green_armor_class DEH_DEFAULT_GREEN_ARMOR_CLASS +#define deh_blue_armor_class DEH_DEFAULT_BLUE_ARMOR_CLASS +#define deh_max_soulsphere DEH_DEFAULT_MAX_SOULSPHERE +#define deh_soulsphere_health DEH_DEFAULT_SOULSPHERE_HEALTH +#define deh_megasphere_health DEH_DEFAULT_MEGASPHERE_HEALTH +#define deh_god_mode_health DEH_DEFAULT_GOD_MODE_HEALTH +#define deh_idfa_armor DEH_DEFAULT_IDFA_ARMOR +#define deh_idfa_armor_class DEH_DEFAULT_IDFA_ARMOR_CLASS +#define deh_idkfa_armor DEH_DEFAULT_IDKFA_ARMOR +#define deh_idkfa_armor_class DEH_DEFAULT_IDKFA_ARMOR_CLASS +#define deh_bfg_cells_per_shot DEH_DEFAULT_BFG_CELLS_PER_SHOT +#define deh_species_infighting DEH_DEFAULT_SPECIES_INFIGHTING + +#endif + +#endif /* #ifndef DEH_MISC_H */ + diff --git a/frosted-doom/deh_str.h b/frosted-doom/deh_str.h new file mode 100644 index 0000000..cdecaf0 --- /dev/null +++ b/frosted-doom/deh_str.h @@ -0,0 +1,47 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// +// Dehacked string replacements +// + +#ifndef DEH_STR_H +#define DEH_STR_H + +#include + +#include "doomfeatures.h" + +// Used to do dehacked text substitutions throughout the program + +#ifdef FEATURE_DEHACKED + +char *DEH_String(char *s); +void DEH_printf(char *fmt, ...); +void DEH_fprintf(FILE *fstream, char *fmt, ...); +void DEH_snprintf(char *buffer, size_t len, char *fmt, ...); +void DEH_AddStringReplacement(char *from_text, char *to_text); + + +#else + +#define DEH_String(x) (x) +#define DEH_printf printf +#define DEH_fprintf fprintf +#define DEH_snprintf snprintf +#define DEH_AddStringReplacement(x, y) + +#endif + +#endif /* #ifndef DEH_STR_H */ + diff --git a/frosted-doom/doom.h b/frosted-doom/doom.h new file mode 100644 index 0000000..3c0d0be --- /dev/null +++ b/frosted-doom/doom.h @@ -0,0 +1,42 @@ +/* + * doom.h + * + * Created on: 18.02.2015 + * Author: Florian + */ + + +#ifndef SRC_CHOCDOOM_DOOM_H_ +#define SRC_CHOCDOOM_DOOM_H_ + +/*---------------------------------------------------------------------* + * additional includes * + *---------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------* + * global definitions * + *---------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------* + * type declarations * + *---------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------* + * function prototypes * + *---------------------------------------------------------------------*/ + +void D_DoomMain (void); + +/*---------------------------------------------------------------------* + * global data * + *---------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------* + * inline functions and function-like macros * + *---------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------* + * eof * + *---------------------------------------------------------------------*/ + +#endif /* SRC_CHOCDOOM_DOOM_H_ */ diff --git a/frosted-doom/doomdata.h b/frosted-doom/doomdata.h index bab5e00..46b3e11 100644 --- a/frosted-doom/doomdata.h +++ b/frosted-doom/doomdata.h @@ -1,25 +1,22 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // all external data is defined here // most of the data is loaded into different structures at run time // some internal structures shared by many modules are here // -//----------------------------------------------------------------------------- #ifndef __DOOMDATA__ #define __DOOMDATA__ @@ -61,7 +58,7 @@ typedef struct { short x; short y; -} mapvertex_t; +} PACKEDATTR mapvertex_t; // A SideDef, defining the visual appearance of a wall, @@ -75,7 +72,7 @@ typedef struct char midtexture[8]; // Front sector, towards viewer. short sector; -} mapsidedef_t; +} PACKEDATTR mapsidedef_t; @@ -90,7 +87,7 @@ typedef struct short tag; // sidenum[1] will be -1 if one sided short sidenum[2]; -} maplinedef_t; +} PACKEDATTR maplinedef_t; // @@ -147,7 +144,7 @@ typedef struct short lightlevel; short special; short tag; -} mapsector_t; +} PACKEDATTR mapsector_t; // SubSector, as generated by BSP. typedef struct @@ -155,7 +152,7 @@ typedef struct short numsegs; // Index of first one, segs are stored sequentially. short firstseg; -} mapsubsector_t; +} PACKEDATTR mapsubsector_t; // LineSeg, generated by splitting LineDefs @@ -168,7 +165,7 @@ typedef struct short linedef; short side; short offset; -} mapseg_t; +} PACKEDATTR mapseg_t; @@ -193,7 +190,7 @@ typedef struct // else it's a node of another subtree. unsigned short children[2]; -} mapnode_t; +} PACKEDATTR mapnode_t; @@ -207,16 +204,10 @@ typedef struct short angle; short type; short options; -} mapthing_t; +} PACKEDATTR mapthing_t; #endif // __DOOMDATA__ -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- - diff --git a/frosted-doom/doomdef.c b/frosted-doom/doomdef.c index e5fb686..d31f3ef 100644 --- a/frosted-doom/doomdef.c +++ b/frosted-doom/doomdef.c @@ -1,34 +1,24 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // DoomDef - basic defines for DOOM, e.g. Version, game mode // and skill level, and display parameters. // -//----------------------------------------------------------------------------- - -static const char -rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $"; -#ifdef __GNUG__ -#pragma implementation "doomdef.h" -#endif + #include "doomdef.h" // Location for any defines turned variables. diff --git a/frosted-doom/doomdef.h b/frosted-doom/doomdef.h index a5a4ffa..62d729d 100644 --- a/frosted-doom/doomdef.h +++ b/frosted-doom/doomdef.h @@ -1,24 +1,21 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Internally used data structures for virtually everything, -// key definitions, lots of other stuff. +// lots of other stuff. // -//----------------------------------------------------------------------------- #ifndef __DOOMDEF__ #define __DOOMDEF__ @@ -26,104 +23,26 @@ #include #include +#include "doomtype.h" +#include "i_timer.h" +#include "d_mode.h" + // // Global parameters/defines. // // DOOM version -enum { VERSION = 110 }; +#define DOOM_VERSION 109 - -// 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; - - -// Identify language to use, software localization. -typedef enum -{ - english, - french, - german, - unknown - -} Language_t; +// Version code for cph's longtics hack ("v1.91") +#define DOOM_191_VERSION 111 // If rangecheck is undefined, // most parameter validation debugging code will not be compiled #define RANGECHECK -// Do or do not use external soundserver. -// The sndserver binary to be run separately -// has been introduced by Dave Taylor. -// The integrated sound support is experimental, -// and unfinished. Default is synchronous. -// Experimental asynchronous timer based is -// handled by SNDINTR. -#define SNDSERV 1 -//#define SNDINTR 1 - - -// This one switches between MIT SHM (no proper mouse) -// and XFree86 DGA (mickey sampling). The original -// linuxdoom used SHM, which is default. -//#define X11_DGA 1 - - -// -// For resize of screen, at start of game. -// It will not work dynamically, see visplanes. -// -#define BASE_WIDTH 320 -//#define BASE_WIDTH 480 - -// It is educational but futile to change this -// scaling e.g. to 2. Drawing of status bar, -// menues etc. is tied to the scale implied -// by the graphics. -#define SCREEN_MUL 1 -#define INV_ASPECT_RATIO 0.625 // 0.75, ideally -//#define INV_ASPECT_RATIO 0.567// 0.75, ideally - -// Defines suck. C sucks. -// C++ might sucks for OOP, but it sure is a better C. -// So there. -#define SCREENWIDTH 320 -//#define SCREENWIDTH 480 -//SCREEN_MUL*BASE_WIDTH //320 -#define SCREENHEIGHT 200 -//#define SCREENHEIGHT 272 -//(int)(SCREEN_MUL*BASE_WIDTH*INV_ASPECT_RATIO) //200 - - - - // The maximum number of players, multiplayer/networking. -#define MAXPLAYERS 4 - -// State updates, number of tics / second. -#define TICRATE 35 +#define MAXPLAYERS 4 // The current state of the game: whether we are // playing, gazing at the intermission screen, @@ -133,9 +52,23 @@ typedef enum GS_LEVEL, GS_INTERMISSION, GS_FINALE, - GS_DEMOSCREEN + GS_DEMOSCREEN, } gamestate_t; +typedef enum +{ + ga_nothing, + ga_loadlevel, + ga_newgame, + ga_loadgame, + ga_savegame, + ga_playdemo, + ga_completed, + ga_victory, + ga_worlddone, + ga_screenshot +} gameaction_t; + // // Difficulty/skill settings/filters. // @@ -148,17 +81,6 @@ typedef enum // Deaf monsters/do not react to sound. #define MTF_AMBUSH 8 -typedef enum -{ - sk_baby, - sk_easy, - sk_medium, - sk_hard, - sk_nightmare -} skill_t; - - - // // Key cards. @@ -243,100 +165,4 @@ typedef enum } powerduration_t; - - - -// -// DOOM keyboard definition. -// This is the stuff configured by Setup.Exe. -// Most key data are simple ascii (uppercased). -// -#define KEY_RIGHTARROW 0xae -#define KEY_LEFTARROW 0xac -#define KEY_UPARROW 0xad -#define KEY_DOWNARROW 0xaf -#define KEY_ESCAPE 27 -#define KEY_ENTER 13 -#define KEY_TAB 9 -#define KEY_F1 (0x80+0x3b) -#define KEY_F2 (0x80+0x3c) -#define KEY_F3 (0x80+0x3d) -#define KEY_F4 (0x80+0x3e) -#define KEY_F5 (0x80+0x3f) -#define KEY_F6 (0x80+0x40) -#define KEY_F7 (0x80+0x41) -#define KEY_F8 (0x80+0x42) -#define KEY_F9 (0x80+0x43) -#define KEY_F10 (0x80+0x44) -#define KEY_F11 (0x80+0x57) -#define KEY_F12 (0x80+0x58) - -#define KEY_BACKSPACE 127 -#define KEY_PAUSE 0xff - -#define KEY_EQUALS 0x3d -#define KEY_MINUS 0x2d - -#define KEY_RSHIFT (0x80+0x36) -#define KEY_RCTRL (0x80+0x1d) -#define KEY_RALT (0x80+0x38) - -#define KEY_LALT KEY_RALT - - - -// DOOM basic types (boolean), -// and max/min values. -//#include "doomtype.h" - -// Fixed point. -//#include "m_fixed.h" - -// Endianess handling. -//#include "m_swap.h" - - -// Binary Angles, sine/cosine/atan lookups. -//#include "tables.h" - -// Event type. -//#include "d_event.h" - -// Game function, skills. -//#include "g_game.h" - -// All external data is defined here. -//#include "doomdata.h" - -// All important printed strings. -// Language selection (message strings). -//#include "dstrings.h" - -// Player is a special actor. -//struct player_s; - - -//#include "d_items.h" -//#include "d_player.h" -//#include "p_mobj.h" -//#include "d_net.h" - -// PLAY -//#include "p_tick.h" - - - - -// Header, generated by sound utility. -// The utility was written by Dave Taylor. -//#include "sounds.h" - - - - #endif // __DOOMDEF__ -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/doomfeatures.h b/frosted-doom/doomfeatures.h new file mode 100644 index 0000000..f7b15f7 --- /dev/null +++ b/frosted-doom/doomfeatures.h @@ -0,0 +1,40 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// List of features which can be enabled/disabled to slim down the +// program. +// + +#ifndef DOOM_FEATURES_H +#define DOOM_FEATURES_H + +// Enables wad merging (the '-merge' command line parameter) + +#undef FEATURE_WAD_MERGE + +// Enables dehacked support ('-deh') + +#undef FEATURE_DEHACKED + +// Enables multiplayer support (network games) + +#undef FEATURE_MULTIPLAYER + +// Enables sound output + +#undef FEATURE_SOUND + +#endif /* #ifndef DOOM_FEATURES_H */ + + diff --git a/frosted-doom/doomkeys.h b/frosted-doom/doomkeys.h new file mode 100644 index 0000000..2dfc431 --- /dev/null +++ b/frosted-doom/doomkeys.h @@ -0,0 +1,97 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Key definitions +// + +#ifndef __DOOMKEYS__ +#define __DOOMKEYS__ + +// +// DOOM keyboard definition. +// This is the stuff configured by Setup.Exe. +// Most key data are simple ascii (uppercased). +// +#define KEY_RIGHTARROW 0xae +#define KEY_LEFTARROW 0xac +#define KEY_UPARROW 0xad +#define KEY_DOWNARROW 0xaf +#define KEY_STRAFE_L 0xa0 +#define KEY_STRAFE_R 0xa1 +#define KEY_USE 0xa2 +#define KEY_FIRE 0xa3 +#define KEY_ESCAPE 27 +#define KEY_ENTER 13 +#define KEY_TAB 9 +#define KEY_F1 (0x80+0x3b) +#define KEY_F2 (0x80+0x3c) +#define KEY_F3 (0x80+0x3d) +#define KEY_F4 (0x80+0x3e) +#define KEY_F5 (0x80+0x3f) +#define KEY_F6 (0x80+0x40) +#define KEY_F7 (0x80+0x41) +#define KEY_F8 (0x80+0x42) +#define KEY_F9 (0x80+0x43) +#define KEY_F10 (0x80+0x44) +#define KEY_F11 (0x80+0x57) +#define KEY_F12 (0x80+0x58) + +#define KEY_BACKSPACE 0x7f +#define KEY_PAUSE 0xff + +#define KEY_EQUALS 0x3d +#define KEY_MINUS 0x2d + +#define KEY_RSHIFT (0x80+0x36) +#define KEY_RCTRL (0x80+0x1d) +#define KEY_RALT (0x80+0x38) + +#define KEY_LALT KEY_RALT + +// new keys: + +#define KEY_CAPSLOCK (0x80+0x3a) +#define KEY_NUMLOCK (0x80+0x45) +#define KEY_SCRLCK (0x80+0x46) +#define KEY_PRTSCR (0x80+0x59) + +#define KEY_HOME (0x80+0x47) +#define KEY_END (0x80+0x4f) +#define KEY_PGUP (0x80+0x49) +#define KEY_PGDN (0x80+0x51) +#define KEY_INS (0x80+0x52) +#define KEY_DEL (0x80+0x53) + +#define KEYP_0 0 +#define KEYP_1 KEY_END +#define KEYP_2 KEY_DOWNARROW +#define KEYP_3 KEY_PGDN +#define KEYP_4 KEY_LEFTARROW +#define KEYP_5 '5' +#define KEYP_6 KEY_RIGHTARROW +#define KEYP_7 KEY_HOME +#define KEYP_8 KEY_UPARROW +#define KEYP_9 KEY_PGUP + +#define KEYP_DIVIDE '/' +#define KEYP_PLUS '+' +#define KEYP_MINUS '-' +#define KEYP_MULTIPLY '*' +#define KEYP_PERIOD 0 +#define KEYP_EQUALS KEY_EQUALS +#define KEYP_ENTER KEY_ENTER + +#endif // __DOOMKEYS__ + diff --git a/frosted-doom/doomstat.c b/frosted-doom/doomstat.c index 8d19ace..ed4c6cc 100644 --- a/frosted-doom/doomstat.c +++ b/frosted-doom/doomstat.c @@ -1,42 +1,31 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Put all global tate variables here. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $"; +#include - -#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; diff --git a/frosted-doom/doomstat.h b/frosted-doom/doomstat.h index 65f5225..acd65dc 100644 --- a/frosted-doom/doomstat.h +++ b/frosted-doom/doomstat.h @@ -1,18 +1,16 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // All the global variables that store the internal state. @@ -22,7 +20,6 @@ // this header file. // In practice, things are a bit messy. // -//----------------------------------------------------------------------------- #ifndef __D_STATE__ @@ -31,15 +28,15 @@ // We need globally shared data structures, // for defining the global state variables. #include "doomdata.h" -#include "d_net.h" +#include "d_loop.h" // We need the playr data structure as well. #include "d_player.h" +// Game mode/mission +#include "d_mode.h" -#ifdef __GNUG__ -#pragma interface -#endif +#include "net_defs.h" @@ -53,22 +50,30 @@ extern boolean fastparm; // checkparm of -fast extern boolean devparm; // DEBUG: launched with -devparm - // ----------------------------------------------------- // Game Mode - identify IWAD as shareware, retail etc. // extern GameMode_t gamemode; extern GameMission_t gamemission; +extern GameVersion_t gameversion; +extern char *gamedescription; + +// 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. + +#define logical_gamemission \ + (gamemission == pack_chex ? doom : \ + gamemission == pack_hacx ? doom2 : gamemission) // Set if homebrew PWAD stuff has been added. extern boolean modifiedgame; -// ------------------------------------------- -// Language. -extern Language_t language; - - // ------------------------------------------- // Selected skill type, map etc. // @@ -78,6 +83,11 @@ extern skill_t startskill; extern int startepisode; extern int startmap; +// Savegame slot to load on startup. This is the value provided to +// the -loadgame option. If this has not been provided, this is -1. + +extern int startloadgame; + extern boolean autostart; // Selected by user. @@ -85,29 +95,30 @@ extern skill_t gameskill; extern int gameepisode; extern int gamemap; +// If non-zero, exit the level after this number of minutes +extern int timelimit; + // Nightmare mode flag, single player. extern boolean respawnmonsters; // Netgame? Only true if >1 player. extern boolean netgame; -// Flag: true only if started as net deathmatch. -// An enum might handle altdeath/cooperative better. -extern boolean deathmatch; - +// 0=Cooperative; 1=Deathmatch; 2=Altdeath +extern int deathmatch; + // ------------------------- // Internal parameters for sound rendering. // These have been taken from the DOS version, // but are not (yet) supported with Linux // (e.g. no sound volume adjustment with menu. -// These are not used, but should be (menu). // From m_menu.c: // Sound FX volume has default, 0 - 15 // Music volume has default, 0 - 15 // These are multiplied by 8. -extern int snd_SfxVolume; // maximum volume for sound -extern int snd_MusicVolume; // maximum volume for music +extern int sfxVolume; +extern int musicVolume; // Current music/sfx card - index useless // w/o a reference LUT in a sound module. @@ -137,15 +148,10 @@ extern boolean paused; // Game Pause? extern boolean viewactive; extern boolean nodrawers; -extern boolean noblit; - -extern int viewwindowx; -extern int viewwindowy; -extern int viewheight; -extern int viewwidth; -extern int scaledviewwidth; +extern boolean testcontrols; +extern int testcontrols_mousespeed; @@ -183,6 +189,11 @@ extern boolean usergame; extern boolean demoplayback; extern boolean demorecording; +// Round angleturn in ticcmds to the nearest 256. This is used when +// recording Vanilla demos in netgames. + +extern boolean lowres_turn; + // Quit after playing a demo from cmdline. extern boolean singledemo; @@ -205,9 +216,6 @@ extern gamestate_t gamestate; -extern int gametic; - - // Bookkeeping on players - state. extern player_t players[MAXPLAYERS]; @@ -228,9 +236,6 @@ extern mapthing_t playerstarts[MAXPLAYERS]; extern wbstartstruct_t wminfo; -// LUT of ammunition limits for each kind. -// This doubles with BackPack powerup item. -extern int maxammo[NUMAMMO]; @@ -241,8 +246,8 @@ extern int maxammo[NUMAMMO]; // // File handling stuff. +extern char * savegamedir; extern char basedefault[1024]; -extern FILE* debugfile; // if true, load all graphics at level load extern boolean precache; @@ -253,9 +258,6 @@ extern boolean precache; extern gamestate_t wipegamestate; extern int mouseSensitivity; -//? -// debug flag to cancel adaptiveness -extern boolean singletics; extern int bodyqueslot; @@ -270,27 +272,10 @@ extern int skyflatnum; // Netgame stuff (buffers and pointers, i.e. indices). -// This is ??? -extern doomcom_t* doomcom; -// This points inside doomcom. -extern doomdata_t* netbuffer; - - -extern ticcmd_t localcmds[BACKUPTICS]; extern int rndindex; -extern int maketic; -extern int nettics[MAXNETNODES]; - -extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; -extern int ticdup; - +extern ticcmd_t *netcmds; #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/doomtype.h b/frosted-doom/doomtype.h index e89a7a6..b5298eb 100644 --- a/frosted-doom/doomtype.h +++ b/frosted-doom/doomtype.h @@ -1,66 +1,103 @@ -// 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 + +#else + +#include + +#endif + + +// +// 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 -#ifndef __BYTEBOOL__ -#define __BYTEBOOL__ -// Fixed to use builtin bool type with C++. #ifdef __cplusplus + +// Use builtin bool type with C++. + typedef bool boolean; + #else -typedef enum {false, true} boolean; -#endif -typedef unsigned char byte; + +typedef enum +{ + false = 0, + true = 1, + undef = 0xFFFFFFFF +} boolean; + #endif +typedef uint8_t byte; + +#include + +#ifdef _WIN32 + +#define DIR_SEPARATOR '\\' +#define DIR_SEPARATOR_S "\\" +#define PATH_SEPARATOR ';' -// Predefined with some OS. -#ifdef LINUX -#include #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) -#endif - - +#define DIR_SEPARATOR '/' +#define DIR_SEPARATOR_S "/" +#define PATH_SEPARATOR ':' #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- + +#define arrlen(array) (sizeof(array) / sizeof(*array)) + +#endif + diff --git a/frosted-doom/dstrings.c b/frosted-doom/dstrings.c index e6abe88..b87f198 100644 --- a/frosted-doom/dstrings.c +++ b/frosted-doom/dstrings.c @@ -1,58 +1,58 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Globally defined strings. // -//----------------------------------------------------------------------------- - -static const char -rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $"; -#ifdef __GNUG__ -#pragma implementation "dstrings.h" -#endif + #include "dstrings.h" - - -char* endmsg[NUM_QUITMESSAGES+1]= +char *doom1_endmsg[] = { - // DOOM1 - QUITMSG, + "are you sure you want to\nquit this great game?", "please don't leave, there's more\ndemons to toast!", "let's beat it -- this is turning\ninto a bloodbath!", "i wouldn't leave if i were you.\ndos is much worse.", "you're trying to say you like dos\nbetter than me, right?", "don't leave yet -- there's a\ndemon around that corner!", "ya know, next time you come in here\ni'm gonna toast ya.", - "go ahead and leave. see if i care." + "go ahead and leave. see if i care.", +}; +char *doom2_endmsg[] = +{ // QuitDOOM II messages + "are you sure you want to\nquit this great game?", "you want to quit?\nthen, thou hast lost an eighth!", "don't go now, there's a \ndimensional shambler waiting\nat the dos prompt!", "get outta here and go back\nto your boring programs.", "if i were your boss, i'd \n deathmatch ya in a minute!", "look, bud. you leave now\nand you forfeit your body count!", "just leave. when you come\nback, i'll be waiting with a bat.", - "you're lucky i don't smack\nyou for thinking about leaving." + "you're lucky i don't smack\nyou for thinking about leaving.", +}; +#if 0 + +// UNUSED messages included in the source release + +char* endmsg[] = +{ + // DOOM1 + QUITMSG, // FinalDOOM? "fuck you, pussy!\nget the fuck out!", "you quit and i'll jizz\nin your cystholes!", @@ -66,6 +66,7 @@ char* endmsg[NUM_QUITMESSAGES+1]= "THIS IS NO MESSAGE!\nPage intentionally left blank." }; +#endif diff --git a/frosted-doom/dstrings.h b/frosted-doom/dstrings.h index 291767b..d3240b4 100644 --- a/frosted-doom/dstrings.h +++ b/frosted-doom/dstrings.h @@ -1,26 +1,21 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // -// $Log:$ -// // DESCRIPTION: // DOOM strings, by language. // -//----------------------------------------------------------------------------- #ifndef __DSTRINGS__ @@ -28,39 +23,19 @@ // All important printed strings. -// Language selection (message strings). -// Use -DFRENCH etc. -#ifdef FRENCH -#include "d_french.h" -#else #include "d_englsh.h" -#endif // Misc. other strings. #define SAVEGAMENAME "doomsav" -// -// File locations, -// relative to current position. -// Path names are OS-sensitive. -// -#define DEVMAPS "devmaps" -#define DEVDATA "devdata" - - -// Not done in french? - // QuitDOOM messages -#define NUM_QUITMESSAGES 22 +// 8 per each game type +#define NUM_QUITMESSAGES 8 -extern char* endmsg[]; +extern char *doom1_endmsg[]; +extern char *doom2_endmsg[]; #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/dummy.c b/frosted-doom/dummy.c new file mode 100644 index 0000000..0068d03 --- /dev/null +++ b/frosted-doom/dummy.c @@ -0,0 +1,49 @@ +/* + * dummy.c + * + * Created on: 16.02.2015 + * Author: Florian + */ + + +/*---------------------------------------------------------------------* + * include files * + *---------------------------------------------------------------------*/ + +#include "doomtype.h" + +/*---------------------------------------------------------------------* + * local definitions * + *---------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------* + * external declarations * + *---------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------* + * public data * + *---------------------------------------------------------------------*/ + +boolean net_client_connected = false; + +boolean drone = false; + +/*---------------------------------------------------------------------* + * private data * + *---------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------* + * private functions * + *---------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------* + * public functions * + *---------------------------------------------------------------------*/ + +void I_InitTimidityConfig(void) +{ +} + +/*---------------------------------------------------------------------* + * eof * + *---------------------------------------------------------------------*/ diff --git a/frosted-doom/f_finale.c b/frosted-doom/f_finale.c index a6e74dd..ca6775e 100644 --- a/frosted-doom/f_finale.c +++ b/frosted-doom/f_finale.c @@ -1,86 +1,98 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Game completion, final screen animation. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: f_finale.c,v 1.5 1997/02/03 21:26:34 b1 Exp $"; - +#include #include // 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; +typedef struct +{ + GameMission_t mission; + int episode, level; + char *background; + char *text; +} textscreen_t; -char* c1text = C1TEXT; -char* c2text = C2TEXT; -char* c3text = C3TEXT; -char* c4text = C4TEXT; -char* c5text = C5TEXT; -char* c6text = C6TEXT; +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}, -char* p1text = P1TEXT; -char* p2text = P2TEXT; -char* p3text = P3TEXT; -char* p4text = P4TEXT; -char* p5text = P5TEXT; -char* p6text = P6TEXT; + { 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}, -char* t1text = T1TEXT; -char* t2text = T2TEXT; -char* t3text = T3TEXT; -char* t4text = T4TEXT; -char* t5text = T5TEXT; -char* t6text = T6TEXT; + { pack_tnt, 1, 6, "SLIME16", T1TEXT}, + { pack_tnt, 1, 11, "RROCK14", T2TEXT}, + { pack_tnt, 1, 20, "RROCK07", T3TEXT}, + { pack_tnt, 1, 30, "RROCK17", T4TEXT}, + { pack_tnt, 1, 15, "RROCK13", T5TEXT}, + { pack_tnt, 1, 31, "RROCK19", T6TEXT}, + + { pack_plut, 1, 6, "SLIME16", P1TEXT}, + { pack_plut, 1, 11, "RROCK14", P2TEXT}, + { pack_plut, 1, 20, "RROCK07", P3TEXT}, + { pack_plut, 1, 30, "RROCK17", P4TEXT}, + { pack_plut, 1, 15, "RROCK13", P5TEXT}, + { pack_plut, 1, 31, "RROCK19", P6TEXT}, +}; char* finaletext; char* finaleflat; @@ -95,97 +107,50 @@ void F_CastDrawer (void); // void F_StartFinale (void) { + size_t i; + gameaction = ga_nothing; gamestate = GS_FINALE; viewactive = false; automapactive = false; - // Okay - IWAD dependend stuff. - // This has been changed severly, and - // some stuff might have changed in the process. - switch ( gamemode ) + if (logical_gamemission == doom) { - - // 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; + S_ChangeMusic(mus_victor, true); } + else + { + S_ChangeMusic(mus_read_m, true); + } + + // Find the right screen and set the text and background + + for (i=0; imission == doom) + { + screen->level = 5; + } + + if (logical_gamemission == screen->mission + && (logical_gamemission != doom || gameepisode == screen->episode) + && gamemap == screen->level) + { + finaletext = screen->text; + finaleflat = screen->background; + } + } + + // Do dehacked substitutions of strings + + finaletext = DEH_String(finaletext); + finaleflat = DEH_String(finaleflat); - finalestage = 0; + finalestage = F_STAGE_TEXT; finalecount = 0; } @@ -194,7 +159,7 @@ void F_StartFinale (void) boolean F_Responder (event_t *event) { - if (finalestage == 2) + if (finalestage == F_STAGE_CAST) return F_CastResponder (event); return false; @@ -206,7 +171,7 @@ boolean F_Responder (event_t *event) // void F_Ticker (void) { - int i; + size_t i; // check for skipping if ( (gamemode == commercial) @@ -229,7 +194,7 @@ void F_Ticker (void) // advance animation finalecount++; - if (finalestage == 2) + if (finalestage == F_STAGE_CAST) { F_CastTicker (); return; @@ -238,10 +203,11 @@ void F_Ticker (void) if ( gamemode == commercial) return; - if (!finalestage && finalecount>strlen (finaletext)*TEXTSPEED + TEXTWAIT) + if (finalestage == F_STAGE_TEXT + && finalecount>strlen (finaletext)*TEXTSPEED + TEXTWAIT) { finalecount = 0; - finalestage = 1; + finalestage = F_STAGE_ARTSCREEN; wipegamestate = -1; // force a wipe if (gameepisode == 3) S_StartMusic (mus_bunny); @@ -264,7 +230,7 @@ void F_TextWrite (void) byte* dest; int x,y,w; - int count; + signed int count; char* ch; int c; int cx; @@ -272,7 +238,7 @@ void F_TextWrite (void) // erase the entire screen to a tiled background src = W_CacheLumpName ( finaleflat , PU_CACHE); - dest = screens[0]; + dest = I_VideoBuffer; for (y=0 ; ywidth); if (cx+w > SCREENWIDTH) break; - V_DrawPatch(cx, cy, 0, hu_font[c]); + V_DrawPatch(cx, cy, hu_font[c]); cx+=w; } @@ -371,9 +337,6 @@ boolean castattacking; // // F_StartCast // -extern gamestate_t wipegamestate; - - void F_StartCast (void) { wipegamestate = -1; // force a screen wipe @@ -381,7 +344,7 @@ void F_StartCast (void) caststate = &states[mobjinfo[castorder[castnum].type].seestate]; casttics = caststate->tics; castdeath = false; - finalestage = 2; + finalestage = F_STAGE_CAST; castframes = 0; castonmelee = 0; castattacking = false; @@ -564,7 +527,7 @@ void F_CastPrint (char* text) } w = SHORT (hu_font[c]->width); - V_DrawPatch(cx, 180, 0, hu_font[c]); + V_DrawPatch(cx, 180, hu_font[c]); cx+=w; } @@ -574,7 +537,6 @@ void F_CastPrint (char* text) // // F_CastDrawer // -void V_DrawPatchFlipped (int x, int y, int scrn, patch_t *patch); void F_CastDrawer (void) { @@ -585,9 +547,9 @@ void F_CastDrawer (void) patch_t* patch; // erase the entire screen to a background - V_DrawPatch (0,0,0, W_CacheLumpName ("BOSSBACK", PU_CACHE)); + V_DrawPatch (0, 0, W_CacheLumpName (DEH_String("BOSSBACK"), PU_CACHE)); - F_CastPrint (castorder[castnum].name); + F_CastPrint (DEH_String(castorder[castnum].name)); // draw the current frame in the middle of the screen sprdef = &sprites[caststate->sprite]; @@ -597,9 +559,9 @@ void F_CastDrawer (void) patch = W_CacheLumpNum (lump+firstspritelump, PU_CACHE); if (flip) - V_DrawPatchFlipped (160,170,0,patch); + V_DrawPatchFlipped(160, 170, patch); else - V_DrawPatch (160,170,0,patch); + V_DrawPatch(160, 170, patch); } @@ -619,7 +581,7 @@ F_DrawPatchCol int count; column = (column_t *)((byte *)patch + LONG(patch->columnofs[col])); - desttop = screens[0]+x; + desttop = I_VideoBuffer + x; // step through the posts in a column while (column->topdelta != 0xff ) @@ -643,7 +605,7 @@ F_DrawPatchCol // void F_BunnyScroll (void) { - int scrolled; + signed int scrolled; int x; patch_t* p1; patch_t* p2; @@ -651,12 +613,12 @@ void F_BunnyScroll (void) int stage; static int laststage; - p1 = W_CacheLumpName ("PFUB2", PU_LEVEL); - p2 = W_CacheLumpName ("PFUB1", PU_LEVEL); + p1 = W_CacheLumpName (DEH_String("PFUB2"), PU_LEVEL); + p2 = W_CacheLumpName (DEH_String("PFUB1"), PU_LEVEL); V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT); - scrolled = 320 - (finalecount-230)/2; + scrolled = (320 - ((signed int) finalecount-230)/2); if (scrolled > 320) scrolled = 320; if (scrolled < 0) @@ -674,8 +636,9 @@ void F_BunnyScroll (void) return; if (finalecount < 1180) { - V_DrawPatch ((SCREENWIDTH-13*8)/2, - (SCREENHEIGHT-8*8)/2,0, W_CacheLumpName ("END0",PU_CACHE)); + V_DrawPatch((SCREENWIDTH - 13 * 8) / 2, + (SCREENHEIGHT - 8 * 8) / 2, + W_CacheLumpName(DEH_String("END0"), PU_CACHE)); laststage = 0; return; } @@ -689,50 +652,67 @@ void F_BunnyScroll (void) laststage = stage; } - sprintf (name,"END%i",stage); - V_DrawPatch ((SCREENWIDTH-13*8)/2, (SCREENHEIGHT-8*8)/2,0, W_CacheLumpName (name,PU_CACHE)); + DEH_snprintf(name, 10, "END%i", stage); + V_DrawPatch((SCREENWIDTH - 13 * 8) / 2, + (SCREENHEIGHT - 8 * 8) / 2, + W_CacheLumpName (name,PU_CACHE)); } +static void F_ArtScreenDrawer(void) +{ + char *lumpname; + + if (gameepisode == 3) + { + F_BunnyScroll(); + } + else + { + switch (gameepisode) + { + case 1: + if (gamemode == retail) + { + lumpname = "CREDIT"; + } + else + { + lumpname = "HELP2"; + } + break; + case 2: + lumpname = "VICTORY2"; + break; + case 4: + lumpname = "ENDPIC"; + break; + default: + return; + } + + lumpname = DEH_String(lumpname); + + V_DrawPatch (0, 0, W_CacheLumpName(lumpname, PU_CACHE)); + } +} // // F_Drawer // void F_Drawer (void) { - if (finalestage == 2) + switch (finalestage) { - F_CastDrawer (); - return; + case F_STAGE_CAST: + F_CastDrawer(); + break; + case F_STAGE_TEXT: + F_TextWrite(); + break; + case F_STAGE_ARTSCREEN: + F_ArtScreenDrawer(); + break; } - - if (!finalestage) - F_TextWrite (); - else - { - switch (gameepisode) - { - case 1: - if ( gamemode == retail ) - V_DrawPatch (0,0,0, - W_CacheLumpName("CREDIT",PU_CACHE)); - else - V_DrawPatch (0,0,0, - W_CacheLumpName("HELP2",PU_CACHE)); - break; - case 2: - V_DrawPatch(0,0,0, - W_CacheLumpName("VICTORY2",PU_CACHE)); - break; - case 3: - F_BunnyScroll (); - break; - case 4: - V_DrawPatch (0,0,0, - W_CacheLumpName("ENDPIC",PU_CACHE)); - break; - } - } - } diff --git a/frosted-doom/f_finale.h b/frosted-doom/f_finale.h index c4fb561..daa71c3 100644 --- a/frosted-doom/f_finale.h +++ b/frosted-doom/f_finale.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // // -//----------------------------------------------------------------------------- #ifndef __F_FINALE__ @@ -46,8 +43,3 @@ void F_StartFinale (void); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/f_wipe.c b/frosted-doom/f_wipe.c index e8596f3..05852fd 100644 --- a/frosted-doom/f_wipe.c +++ b/frosted-doom/f_wipe.c @@ -1,37 +1,29 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Mission begin melt/wipe screen special effect. // -//----------------------------------------------------------------------------- - - -static const char rcsid[] = "$Id: f_wipe.c,v 1.2 1997/02/03 22:45:09 b1 Exp $"; - +#include #include "z_zone.h" #include "i_video.h" #include "v_video.h" #include "m_random.h" -#include "doomdef.h" +#include "doomtype.h" #include "f_wipe.h" @@ -230,6 +222,8 @@ wipe_exitMelt int ticks ) { Z_Free(y); + Z_Free(wipe_scr_start); + Z_Free(wipe_scr_end); return 0; } @@ -240,7 +234,7 @@ wipe_StartScreen int width, int height ) { - wipe_scr_start = screens[2]; + wipe_scr_start = Z_Malloc(SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL); I_ReadScreen(wipe_scr_start); return 0; } @@ -252,9 +246,9 @@ wipe_EndScreen int width, int height ) { - wipe_scr_end = screens[3]; + wipe_scr_end = Z_Malloc(SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL); I_ReadScreen(wipe_scr_end); - V_DrawBlock(x, y, 0, width, height, wipe_scr_start); // restore start scr. + V_DrawBlock(x, y, width, height, wipe_scr_start); // restore start scr. return 0; } @@ -274,14 +268,12 @@ wipe_ScreenWipe wipe_initMelt, wipe_doMelt, wipe_exitMelt }; - void V_MarkRect(int, int, int, int); - // initial stuff if (!go) { go = 1; // wipe_scr = (byte *) Z_Malloc(width*height, PU_STATIC, 0); // DEBUG - wipe_scr = screens[0]; + wipe_scr = I_VideoBuffer; (*wipes[wipeno*3])(width, height, ticks); } @@ -298,5 +290,5 @@ wipe_ScreenWipe } return !go; - } + diff --git a/frosted-doom/f_wipe.h b/frosted-doom/f_wipe.h index 4a9927d..f48a9ca 100644 --- a/frosted-doom/f_wipe.h +++ b/frosted-doom/f_wipe.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Mission start screen wipe/melt, special effects. // -//----------------------------------------------------------------------------- #ifndef __F_WIPE_H__ @@ -64,8 +61,3 @@ wipe_ScreenWipe int ticks ); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/g_game.c b/frosted-doom/g_game.c index eb76b02..30fcd48 100644 --- a/frosted-doom/g_game.c +++ b/frosted-doom/g_game.c @@ -1,42 +1,43 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: none // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: g_game.c,v 1.8 1997/02/03 22:45:09 b1 Exp $"; #include #include +#include #include "doomdef.h" +#include "doomkeys.h" #include "doomstat.h" +#include "deh_main.h" +#include "deh_misc.h" + #include "z_zone.h" #include "f_finale.h" #include "m_argv.h" +#include "m_controls.h" #include "m_misc.h" #include "m_menu.h" #include "m_random.h" #include "i_system.h" +#include "i_timer.h" +#include "i_video.h" #include "p_setup.h" #include "p_saveg.h" @@ -48,6 +49,7 @@ rcsid[] = "$Id: g_game.c,v 1.8 1997/02/03 22:45:09 b1 Exp $"; #include "hu_stuff.h" #include "st_stuff.h" #include "am_map.h" +#include "statdump.h" // Needs access to LFB. #include "v_video.h" @@ -72,27 +74,24 @@ rcsid[] = "$Id: g_game.c,v 1.8 1997/02/03 22:45:09 b1 Exp $"; #define SAVEGAMESIZE 0x2c000 -#define SAVESTRINGSIZE 24 - - -boolean G_CheckDemoStatus (void); void G_ReadDemoTiccmd (ticcmd_t* cmd); void G_WriteDemoTiccmd (ticcmd_t* cmd); void G_PlayerReborn (int player); -void G_InitNew (skill_t skill, int episode, int map); void G_DoReborn (int playernum); void G_DoLoadLevel (void); void G_DoNewGame (void); -void G_DoLoadGame (void); void G_DoPlayDemo (void); void G_DoCompleted (void); void G_DoVictory (void); void G_DoWorldDone (void); void G_DoSaveGame (void); +// Gamestate the last time G_Ticker was called. + +gamestate_t oldgamestate; gameaction_t gameaction; gamestate_t gamestate; @@ -100,7 +99,11 @@ skill_t gameskill; boolean respawnmonsters; int gameepisode; int gamemap; - + +// If non-zero, exit the level after this number of minutes. + +int timelimit; + boolean paused; boolean sendpause; // send a pause event next tic boolean sendsave; // send a save event next tic @@ -108,24 +111,26 @@ boolean usergame; // ok to save / end game boolean timingdemo; // if true, exit with report on completion boolean nodrawers; // for comparative timing purposes -boolean noblit; // for comparative timing purposes int starttime; // for comparative timing purposes boolean viewactive; -boolean deathmatch; // only if started as net death +int deathmatch; // only if started as net death boolean netgame; // only true if packets are broadcast boolean playeringame[MAXPLAYERS]; player_t players[MAXPLAYERS]; + +boolean turbodetected[MAXPLAYERS]; int consoleplayer; // player taking events and displaying int displayplayer; // view being displayed -int gametic; int levelstarttic; // gametic at level start int totalkills, totalitems, totalsecret; // for intermission -char demoname[32]; +char *demoname; boolean demorecording; +boolean longtics; // cph's doom 1.91 longtics hack +boolean lowres_turn; // low resolution turning for longtics boolean demoplayback; boolean netdemo; byte* demobuffer; @@ -134,91 +139,100 @@ byte* demoend; boolean singledemo; // quit after playing a demo from cmdline boolean precache = true; // if true, load all graphics at start + +boolean testcontrols = false; // Invoked by setup to test controls +int testcontrols_mousespeed; + + 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; - -int mousebfire; -int mousebstrafe; -int mousebforward; - -int joybfire; -int joybstrafe; -int joybuse; -int joybspeed; - - +byte consistancy[MAXPLAYERS][BACKUPTICS]; #define MAXPLMOVE (forwardmove[1]) #define TURBOTHRESHOLD 0x32 -fixed_t forwardmove[2] = {0x19, 0x32}; -fixed_t sidemove[2] = {0x18, 0x28}; -fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn +fixed_t forwardmove[2] = {0x19, 0x32}; +fixed_t sidemove[2] = {0x18, 0x28}; +fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn + +static int *weapon_keys[] = { + &key_weapon1, + &key_weapon2, + &key_weapon3, + &key_weapon4, + &key_weapon5, + &key_weapon6, + &key_weapon7, + &key_weapon8 +}; + +// Set to -1 or +1 to switch to the previous or next weapon. + +static int next_weapon = 0; + +// Used for prev/next weapon keys. + +static const struct +{ + weapontype_t weapon; + weapontype_t weapon_num; +} weapon_order_table[] = { + { wp_fist, wp_fist }, + { wp_chainsaw, wp_fist }, + { wp_pistol, wp_pistol }, + { wp_shotgun, wp_shotgun }, + { wp_supershotgun, wp_shotgun }, + { wp_chaingun, wp_chaingun }, + { wp_missile, wp_missile }, + { wp_plasma, wp_plasma }, + { wp_bfg, wp_bfg } +}; #define SLOWTURNTICS 6 #define NUMKEYS 256 +#define MAX_JOY_BUTTONS 20 -boolean gamekeydown[NUMKEYS]; -int turnheld; // for accelerative turning +static boolean gamekeydown[NUMKEYS]; +static int turnheld; // for accelerative turning -boolean mousearray[4]; -boolean* mousebuttons = &mousearray[1]; // allow [-1] +static boolean mousearray[MAX_MOUSE_BUTTONS + 1]; +static boolean *mousebuttons = &mousearray[1]; // allow [-1] // mouse values are used once int mousex; -int mousey; +int mousey; -int dclicktime; -int dclickstate; -int dclicks; -int dclicktime2; -int dclickstate2; -int dclicks2; +static int dclicktime; +static boolean dclickstate; +static int dclicks; +static int dclicktime2; +static boolean dclickstate2; +static int dclicks2; // joystick values are repeated -int joyxmove; -int joyymove; -boolean joyarray[5]; -boolean* joybuttons = &joyarray[1]; // allow [-1] - -int savegameslot; -char savedescription[32]; +static int joyxmove; +static int joyymove; +static int joystrafemove; +static boolean joyarray[MAX_JOY_BUTTONS + 1]; +static boolean *joybuttons = &joyarray[1]; // allow [-1] +static int savegameslot; +static char savedescription[32]; #define BODYQUESIZE 32 mobj_t* bodyque[BODYQUESIZE]; int bodyqueslot; -void* statcopy; // for statistics driver - - +int vanilla_savegame_limit = 1; +int vanilla_demo_limit = 1; int G_CmdChecksum (ticcmd_t* cmd) { - int i; + size_t i; int sum = 0; for (i=0 ; i< sizeof(*cmd)/4 - 1 ; i++) @@ -226,7 +240,78 @@ int G_CmdChecksum (ticcmd_t* cmd) return sum; } - + +static boolean WeaponSelectable(weapontype_t weapon) +{ + // Can't select the super shotgun in Doom 1. + + if (weapon == wp_supershotgun && logical_gamemission == doom) + { + return false; + } + + // These weapons aren't available in shareware. + + if ((weapon == wp_plasma || weapon == wp_bfg) + && gamemission == doom && gamemode == shareware) + { + return false; + } + + // Can't select a weapon if we don't own it. + + if (!players[consoleplayer].weaponowned[weapon]) + { + return false; + } + + // Can't select the fist if we have the chainsaw, unless + // we also have the berserk pack. + + if (weapon == wp_fist + && players[consoleplayer].weaponowned[wp_chainsaw] + && !players[consoleplayer].powers[pw_strength]) + { + return false; + } + + return true; +} + +static int G_NextWeapon(int direction) +{ + weapontype_t weapon; + int start_i, i; + + // Find index in the table. + + if (players[consoleplayer].pendingweapon == wp_nochange) + { + weapon = players[consoleplayer].readyweapon; + } + else + { + weapon = players[consoleplayer].pendingweapon; + } + + for (i=0; iconsistancy = consistancy[consoleplayer][maketic%BACKUPTICS]; - strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe] || joybuttons[joybstrafe]; - speed = gamekeydown[key_speed] || joybuttons[joybspeed]; + + // fraggle: support the old "joyb_speed = 31" hack which + // allowed an autorun effect + + speed = key_speed >= NUMKEYS + || joybspeed >= MAX_JOY_BUTTONS + || gamekeydown[key_speed] + || joybuttons[joybspeed]; forward = side = 0; @@ -315,15 +403,28 @@ void G_BuildTiccmd (ticcmd_t* cmd) // fprintf(stderr, "down\n"); forward -= forwardmove[speed]; } + if (joyymove < 0) - forward += forwardmove[speed]; + forward += forwardmove[speed]; if (joyymove > 0) - forward -= forwardmove[speed]; - if (gamekeydown[key_straferight]) - side += sidemove[speed]; - if (gamekeydown[key_strafeleft]) - side -= sidemove[speed]; - + forward -= forwardmove[speed]; + + if (gamekeydown[key_strafeleft] + || joybuttons[joybstrafeleft] + || mousebuttons[mousebstrafeleft] + || joystrafemove < 0) + { + side -= sidemove[speed]; + } + + if (gamekeydown[key_straferight] + || joybuttons[joybstraferight] + || mousebuttons[mousebstraferight] + || joystrafemove > 0) + { + side += sidemove[speed]; + } + // buttons cmd->chatchar = HU_dequeueChatChar(); @@ -331,83 +432,122 @@ void G_BuildTiccmd (ticcmd_t* cmd) || joybuttons[joybfire]) cmd->buttons |= BT_ATTACK; - if (gamekeydown[key_use] || joybuttons[joybuse] ) + if (gamekeydown[key_use] + || joybuttons[joybuse] + || mousebuttons[mousebuse]) { cmd->buttons |= BT_USE; // clear double clicks if hit use button dclicks = 0; } - // chainsaw overrides - for (i=0 ; ibuttons |= BT_CHANGE; - cmd->buttons |= i<buttons |= BT_CHANGE; + cmd->buttons |= i << BT_WEAPONSHIFT; + } + else + { + // Check weapon keys. + + for (i=0; ibuttons |= BT_CHANGE; + cmd->buttons |= i< 1 ) - { - dclickstate = mousebuttons[mousebforward]; - if (dclickstate) - dclicks++; - if (dclicks == 2) - { - cmd->buttons |= BT_USE; - dclicks = 0; - } - else - dclicktime = 0; - } - else - { - dclicktime += ticdup; - if (dclicktime > 20) - { - dclicks = 0; - dclickstate = 0; - } } - - // strafe double click - bstrafe = - mousebuttons[mousebstrafe] - || joybuttons[joybstrafe]; - if (bstrafe != dclickstate2 && dclicktime2 > 1 ) - { - dclickstate2 = bstrafe; - if (dclickstate2) - dclicks2++; - if (dclicks2 == 2) - { - cmd->buttons |= BT_USE; - dclicks2 = 0; - } - else - dclicktime2 = 0; - } - else - { - dclicktime2 += ticdup; - if (dclicktime2 > 20) - { - dclicks2 = 0; - dclickstate2 = 0; - } - } - + if (mousebuttons[mousebbackward]) + { + forward -= forwardmove[speed]; + } + + if (dclick_use) + { + // forward double click + if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1 ) + { + dclickstate = mousebuttons[mousebforward]; + if (dclickstate) + dclicks++; + if (dclicks == 2) + { + cmd->buttons |= BT_USE; + dclicks = 0; + } + else + dclicktime = 0; + } + else + { + dclicktime += ticdup; + if (dclicktime > 20) + { + dclicks = 0; + dclickstate = 0; + } + } + + // strafe double click + bstrafe = + mousebuttons[mousebstrafe] + || joybuttons[joybstrafe]; + if (bstrafe != dclickstate2 && dclicktime2 > 1 ) + { + dclickstate2 = bstrafe; + if (dclickstate2) + dclicks2++; + if (dclicks2 == 2) + { + cmd->buttons |= BT_USE; + dclicks2 = 0; + } + else + dclicktime2 = 0; + } + else + { + dclicktime2 += ticdup; + if (dclicktime2 > 20) + { + dclicks2 = 0; + dclickstate2 = 0; + } + } + } + forward += mousey; + if (strafe) side += mousex*2; else cmd->angleturn -= mousex*0x8; + if (mousex == 0) + { + // No movement in the previous frame + + testcontrols_mousespeed = 0; + } + mousex = mousey = 0; if (forward > MAXPLMOVE) @@ -434,14 +574,32 @@ void G_BuildTiccmd (ticcmd_t* cmd) sendsave = false; cmd->buttons = BT_SPECIAL | BTS_SAVEGAME | (savegameslot<angleturn + carry; + + // round angleturn to the nearest 256 unit boundary + // for recording demos with single byte values for turn + + cmd->angleturn = (desired_angleturn + 128) & 0xff00; + + // Carry forward the error from the reduced resolution to the + // next tic, so that successive small movements can accumulate. + + carry = desired_angleturn - cmd->angleturn; + } } // // G_DoLoadLevel // -extern gamestate_t wipegamestate; - void G_DoLoadLevel (void) { int i; @@ -451,20 +609,32 @@ void G_DoLoadLevel (void) // a flat. The data is in the WAD only because // we look for an actual index, instead of simply // setting one. - skyflatnum = R_FlatNumForName ( SKYFLATNAME ); - // DOOM determines the sky texture to be used - // depending on the current episode, and the game version. - if ( (gamemode == commercial) - || ( gamemode == pack_tnt ) - || ( gamemode == pack_plut ) ) + skyflatnum = R_FlatNumForName(DEH_String(SKYFLATNAME)); + + // The "Sky never changes in Doom II" bug was fixed in + // the id Anthology version of doom2.exe for Final Doom. + if ((gamemode == commercial) + && (gameversion == exe_final2 || gameversion == exe_chex)) { - skytexture = R_TextureNumForName ("SKY3"); - if (gamemap < 12) - skytexture = R_TextureNumForName ("SKY1"); - else - if (gamemap < 21) - skytexture = R_TextureNumForName ("SKY2"); + char *skytexturename; + + if (gamemap < 12) + { + skytexturename = "SKY1"; + } + else if (gamemap < 21) + { + skytexturename = "SKY2"; + } + else + { + skytexturename = "SKY3"; + } + + skytexturename = DEH_String(skytexturename); + + skytexture = R_TextureNumForName(skytexturename); } levelstarttic = gametic; // for time calculation @@ -476,6 +646,7 @@ void G_DoLoadLevel (void) for (i=0 ; itype == ev_keydown - && ev->data1 == KEY_F12 && (singledemo || !deathmatch) ) + && ev->data1 == key_spy && (singledemo || !deathmatch) ) { // spy mode do @@ -531,7 +760,7 @@ boolean G_Responder (event_t* ev) } return false; } - + if (gamestate == GS_LEVEL) { #if 0 @@ -554,17 +783,41 @@ boolean G_Responder (event_t* ev) if (F_Responder (ev)) return true; // finale ate the event } - + + if (testcontrols && ev->type == ev_mouse) + { + // If we are invoked by setup to test the controls, save the + // mouse speed so that we can display it on-screen. + // Perform a low pass filter on this so that the thermometer + // appears to move smoothly. + + testcontrols_mousespeed = abs(ev->data2); + } + + // If the next/previous weapon keys are pressed, set the next_weapon + // variable to change weapons when the next ticcmd is generated. + + if (ev->type == ev_keydown && ev->data1 == key_prevweapon) + { + next_weapon = -1; + } + else if (ev->type == ev_keydown && ev->data1 == key_nextweapon) + { + next_weapon = 1; + } + switch (ev->type) { case ev_keydown: - if (ev->data1 == KEY_PAUSE) + if (ev->data1 == key_pause) { sendpause = true; - return true; - } - if (ev->data1 data1 data1] = true; + } + return true; // eat key down events case ev_keyup: @@ -573,20 +826,16 @@ boolean G_Responder (event_t* ev) return false; // always let key up events filter down case ev_mouse: - mousebuttons[0] = ev->data1 & 1; - mousebuttons[1] = ev->data1 & 2; - mousebuttons[2] = ev->data1 & 4; + SetMouseButtons(ev->data1); mousex = ev->data2*(mouseSensitivity+5)/10; mousey = ev->data3*(mouseSensitivity+5)/10; return true; // eat events case ev_joystick: - joybuttons[0] = ev->data1 & 1; - joybuttons[1] = ev->data1 & 2; - joybuttons[2] = ev->data1 & 4; - joybuttons[3] = ev->data1 & 8; + SetJoyButtons(ev->data1); joyxmove = ev->data2; joyymove = ev->data3; + joystrafemove = ev->data4; return true; // eat events default: @@ -643,7 +892,8 @@ void G_Ticker (void) G_DoWorldDone (); break; case ga_screenshot: - M_ScreenShot (); + V_ScreenShot("DOOM%02i.%s"); + players[consoleplayer].message = DEH_String("screen shot"); gameaction = ga_nothing; break; case ga_nothing: @@ -660,24 +910,39 @@ void G_Ticker (void) if (playeringame[i]) { cmd = &players[i].cmd; - - memcpy (cmd, &netcmds[i][buf], sizeof(ticcmd_t)); - + + memcpy(cmd, &netcmds[i], sizeof(ticcmd_t)); + if (demoplayback) G_ReadDemoTiccmd (cmd); if (demorecording) G_WriteDemoTiccmd (cmd); // check for turbo cheats - if (cmd->forwardmove > TURBOTHRESHOLD - && !(gametic&31) && ((gametic>>5)&3) == i ) - { - static char turbomessage[80]; - extern char *player_names[4]; - sprintf (turbomessage, "%s is turbo!",player_names[i]); - players[consoleplayer].message = turbomessage; - } - + + // check ~ 4 seconds whether to display the turbo message. + // store if the turbo threshold was exceeded in any tics + // over the past 4 seconds. offset the checking period + // for each player so messages are not displayed at the + // same time. + + if (cmd->forwardmove > TURBOTHRESHOLD) + { + turbodetected[i] = true; + } + + if ((gametic & 31) == 0 + && ((gametic >> 5) % MAXPLAYERS) == i + && turbodetected[i]) + { + static char turbomessage[80]; + extern char *player_names[4]; + M_snprintf(turbomessage, sizeof(turbomessage), + "%s is turbo!", player_names[i]); + players[consoleplayer].message = turbomessage; + turbodetected[i] = false; + } + if (netgame && !netdemo && !(gametic%ticdup) ) { if (gametic > BACKUPTICS @@ -711,9 +976,13 @@ void G_Ticker (void) S_ResumeSound (); break; - case BTS_SAVEGAME: + case BTS_SAVEGAME: if (!savedescription[0]) - strcpy (savedescription, "NET GAME"); + { + M_StringCopy(savedescription, "NET GAME", + sizeof(savedescription)); + } + savegameslot = (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT; gameaction = ga_savegame; @@ -722,6 +991,15 @@ void G_Ticker (void) } } } + + // Have we just finished displaying an intermission screen? + + if (oldgamestate == GS_INTERMISSION && gamestate != GS_INTERMISSION) + { + WI_End(); + } + + oldgamestate = gamestate; // do main actions switch (gamestate) @@ -743,7 +1021,7 @@ void G_Ticker (void) case GS_DEMOSCREEN: D_PageTicker (); - break; + break; } } @@ -759,16 +1037,10 @@ void G_Ticker (void) // Called by the game initialization functions. // void G_InitPlayer (int player) -{ - //player_t* p; - - // set up the saved info - //p = &players[player]; - - // clear everything else to defaults +{ + // clear everything else to defaults G_PlayerReborn (player); - -} +} @@ -821,11 +1093,11 @@ void G_PlayerReborn (int player) p->usedown = p->attackdown = true; // don't do anything immediately p->playerstate = PST_LIVE; - p->health = MAXHEALTH; + p->health = deh_initial_health; // Use dehacked value p->readyweapon = p->pendingweapon = wp_pistol; p->weaponowned[wp_fist] = true; p->weaponowned[wp_pistol] = true; - p->ammo[am_clip] = 50; + p->ammo[am_clip] = deh_initial_bullets; for (i=0 ; imaxammo[i] = maxammo[i]; @@ -848,7 +1120,6 @@ G_CheckSpot fixed_t x; fixed_t y; subsector_t* ss; - unsigned an; mobj_t* mo; int i; @@ -873,15 +1144,70 @@ G_CheckSpot P_RemoveMobj (bodyque[bodyqueslot%BODYQUESIZE]); bodyque[bodyqueslot%BODYQUESIZE] = players[playernum].mo; bodyqueslot++; - - // spawn a teleport fog - ss = R_PointInSubsector (x,y); - an = ( ANG45 * (mthing->angle/45) ) >> ANGLETOFINESHIFT; - - mo = P_SpawnMobj (x+20*finecosine[an], y+20*finesine[an] - , ss->sector->floorheight - , MT_TFOG); - + + // spawn a teleport fog + ss = R_PointInSubsector (x,y); + + + // The code in the released source looks like this: + // + // an = ( ANG45 * (((unsigned int) mthing->angle)/45) ) + // >> ANGLETOFINESHIFT; + // mo = P_SpawnMobj (x+20*finecosine[an], y+20*finesine[an] + // , ss->sector->floorheight + // , MT_TFOG); + // + // But 'an' can be a signed value in the DOS version. This means that + // we get a negative index and the lookups into finecosine/finesine + // end up dereferencing values in finetangent[]. + // A player spawning on a deathmatch start facing directly west spawns + // "silently" with no spawn fog. Emulate this. + // + // This code is imported from PrBoom+. + + { + fixed_t xa, ya; + signed int an; + + // This calculation overflows in Vanilla Doom, but here we deliberately + // avoid integer overflow as it is undefined behavior, so the value of + // 'an' will always be positive. + an = (ANG45 >> ANGLETOFINESHIFT) * ((signed int) mthing->angle / 45); + + switch (an) + { + case 4096: // -4096: + xa = finetangent[2048]; // finecosine[-4096] + ya = finetangent[0]; // finesine[-4096] + break; + case 5120: // -3072: + xa = finetangent[3072]; // finecosine[-3072] + ya = finetangent[1024]; // finesine[-3072] + break; + case 6144: // -2048: + xa = finesine[0]; // finecosine[-2048] + ya = finetangent[2048]; // finesine[-2048] + break; + case 7168: // -1024: + xa = finesine[1024]; // finecosine[-1024] + ya = finetangent[3072]; // finesine[-1024] + break; + case 0: + case 1024: + case 2048: + case 3072: + xa = finecosine[an]; + ya = finesine[an]; + break; + default: + I_Error("G_CheckSpot: unexpected angle %d\n", an); + xa = ya = 0; + break; + } + mo = P_SpawnMobj(x + 20 * xa, y + 20 * ya, + ss->sector->floorheight, MT_TFOG); + } + if (players[consoleplayer].viewz != 1) S_StartSound (mo, sfx_telept); // don't start sound on first frame @@ -1030,18 +1356,33 @@ void G_DoCompleted (void) if (automapactive) AM_Stop (); - if ( gamemode != commercial) - switch(gamemap) - { - case 8: - gameaction = ga_victory; - return; - case 9: - for (i=0 ; i>16; - *save_p++ = leveltime>>8; - *save_p++ = leveltime; + char *savegame_file; + char *temp_savegame_file; + char *recovery_savegame_file; + + recovery_savegame_file = NULL; + temp_savegame_file = P_TempSaveGameFile(); + savegame_file = P_SaveGameFile(savegameslot); + + // Open the savegame file for writing. We write to a temporary file + // and then rename it at the end if it was successfully written. + // This prevents an existing savegame from being overwritten by + // a corrupted one, or if a savegame buffer overrun occurs. + save_stream = fopen(temp_savegame_file, "wb"); + + if (save_stream == NULL) + { + // Failed to save the game, so we're going to have to abort. But + // to be nice, save to somewhere else before we call I_Error(). + recovery_savegame_file = M_TempFile("recovery.dsg"); + save_stream = fopen(recovery_savegame_file, "wb"); + if (save_stream == NULL) + { + I_Error("Failed to open either '%s' or '%s' to write savegame.", + temp_savegame_file, recovery_savegame_file); + } + } + + savegame_error = false; + + P_WriteSaveGameHeader(savedescription); P_ArchivePlayers (); P_ArchiveWorld (); P_ArchiveThinkers (); P_ArchiveSpecials (); - *save_p++ = 0x1d; // consistancy marker + P_WriteSaveGameEOF(); - length = save_p - savebuffer; - if (length > SAVEGAMESIZE) - I_Error ("Savegame buffer overrun"); - M_WriteFile (name, savebuffer, length); - gameaction = ga_nothing; - savedescription[0] = 0; - - players[consoleplayer].message = GGSAVED; + // Enforce the same savegame size limit as in Vanilla Doom, + // except if the vanilla_savegame_limit setting is turned off. + + if (vanilla_savegame_limit && ftell(save_stream) > SAVEGAMESIZE) + { + I_Error ("Savegame buffer overrun"); + } + + // Finish up, close the savegame file. + + fclose(save_stream); + + if (recovery_savegame_file != NULL) + { + // We failed to save to the normal location, but we wrote a + // recovery file to the temp directory. Now we can bomb out + // with an error. + I_Error("Failed to open savegame file '%s' for writing.\n" + "But your game has been saved to '%s' for recovery.", + temp_savegame_file, recovery_savegame_file); + } + + // Now rename the temporary savegame file to the actual savegame + // file, overwriting the old savegame if there was one there. + + remove(savegame_file); + rename(temp_savegame_file, savegame_file); + + gameaction = ga_nothing; + M_StringCopy(savedescription, "", sizeof(savedescription)); + + players[consoleplayer].message = DEH_String(GGSAVED); // draw the pattern into the back screen R_FillBackScreen (); @@ -1358,34 +1722,34 @@ void G_DoNewGame (void) gameaction = ga_nothing; } -// The sky texture to be used instead of the F_SKY1 dummy. -extern int skytexture; - void G_InitNew ( skill_t skill, int episode, - int map ) -{ - int i; - - if (paused) - { - paused = false; - S_ResumeSound (); - } - + int map ) +{ + char *skytexturename; + int i; - if (skill > sk_nightmare) - skill = sk_nightmare; + if (paused) + { + paused = false; + S_ResumeSound (); + } + /* + // Note: This commented-out block of code was added at some point + // between the DOS version(s) and the Doom source release. It isn't + // found in disassemblies of the DOS version and causes IDCLEV and + // the -warp command line parameter to behave differently. + // This is left here for posterity. // This was quite messy with SPECIAL and commented parts. // Supposedly hacks to make the latest edition work. // It might not work properly. if (episode < 1) - episode = 1; + episode = 1; if ( gamemode == retail ) { @@ -1394,94 +1758,136 @@ G_InitNew } else if ( gamemode == shareware ) { - if (episode > 1) + if (episode > 1) episode = 1; // only start episode 1 on shareware - } + } else { if (episode > 3) episode = 3; } - + */ - - if (map < 1) + if (skill > sk_nightmare) + skill = sk_nightmare; + + 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>= 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 ; iforwardmove = ((signed char)*demo_p++); cmd->sidemove = ((signed char)*demo_p++); - cmd->angleturn = ((unsigned char)*demo_p++)<<8; + + // If this is a longtics demo, read back in higher resolution + + if (longtics) + { + cmd->angleturn = *demo_p++; + cmd->angleturn |= (*demo_p++) << 8; + } + else + { + cmd->angleturn = ((unsigned char) *demo_p++)<<8; + } + cmd->buttons = (unsigned char)*demo_p++; } +// Increase the size of the demo buffer to allow unlimited demos + +static void IncreaseDemoBuffer(void) +{ + int current_length; + byte *new_demobuffer; + byte *new_demop; + int new_length; + + // Find the current size + + current_length = demoend - demobuffer; + + // Generate a new buffer twice the size + new_length = current_length * 2; + + new_demobuffer = Z_Malloc(new_length, PU_STATIC, 0); + new_demop = new_demobuffer + (demo_p - demobuffer); + + // Copy over the old data + + memcpy(new_demobuffer, demobuffer, current_length); + + // Free the old buffer and point the demo pointers at the new buffer. + + Z_Free(demobuffer); + + demobuffer = new_demobuffer; + demo_p = new_demop; + demoend = demobuffer + new_length; +} void G_WriteDemoTiccmd (ticcmd_t* cmd) { - if (gamekeydown['q']) // press q to end demo recording + byte *demo_start; + + if (gamekeydown[key_demo_quit]) // press q to end demo recording G_CheckDemoStatus (); + + demo_start = demo_p; + *demo_p++ = cmd->forwardmove; *demo_p++ = cmd->sidemove; - *demo_p++ = (cmd->angleturn+128)>>8; + + // If this is a longtics demo, record in higher resolution + + if (longtics) + { + *demo_p++ = (cmd->angleturn & 0xff); + *demo_p++ = (cmd->angleturn >> 8) & 0xff; + } + else + { + *demo_p++ = cmd->angleturn >> 8; + } + *demo_p++ = cmd->buttons; - demo_p -= 4; + + // reset demo pointer back + demo_p = demo_start; + if (demo_p > demoend - 16) { - // no more space - G_CheckDemoStatus (); - return; + if (vanilla_demo_limit) + { + // no more space + G_CheckDemoStatus (); + return; + } + else + { + // Vanilla demo limit disabled: unlimited + // demo lengths! + + IncreaseDemoBuffer(); + } } G_ReadDemoTiccmd (cmd); // make SURE it is exactly the same @@ -1526,34 +2005,85 @@ void G_WriteDemoTiccmd (ticcmd_t* cmd) // -// G_RecordDemo -// -void G_RecordDemo (char* name) -{ - int i; - int maxsize; - - usergame = false; - strcpy (demoname, name); - strcat (demoname, ".lmp"); +// G_RecordDemo +// +void G_RecordDemo (char *name) +{ + size_t demoname_size; + int i; + int maxsize; + + usergame = false; + demoname_size = strlen(name) + 5; + demoname = Z_Malloc(demoname_size, PU_STATIC, NULL); + M_snprintf(demoname, demoname_size, "%s.lmp", name); maxsize = 0x20000; - i = M_CheckParm ("-maxdemo"); - if (i && i + // @category demo + // @vanilla + // + // Specify the demo buffer size (KiB) + // + + i = M_CheckParmWithArgs("-maxdemo", 1); + if (i) maxsize = atoi(myargv[i+1])*1024; demobuffer = Z_Malloc (maxsize,PU_STATIC,NULL); demoend = demobuffer + maxsize; demorecording = true; } - - + +// Get the demo version code appropriate for the version set in gameversion. +int G_VanillaVersionCode(void) +{ + switch (gameversion) + { + case exe_doom_1_2: + I_Error("Doom 1.2 does not have a version code!"); + case exe_doom_1_666: + return 106; + case exe_doom_1_7: + return 107; + case exe_doom_1_8: + return 108; + case exe_doom_1_9: + default: // All other versions are variants on v1.9: + return 109; + } +} + void G_BeginRecording (void) { int i; - + + //! + // @category demo + // + // Record a high resolution "Doom 1.91" demo. + // + + longtics = M_CheckParm("-longtics") != 0; + + // If not recording a longtics demo, record in low res + + lowres_turn = !longtics; + demo_p = demobuffer; - *demo_p++ = VERSION; + // Save the right version code for this demo + + if (longtics) + { + *demo_p++ = DOOM_191_VERSION; + } + else + { + *demo_p++ = G_VanillaVersionCode(); + } + *demo_p++ = gameskill; *demo_p++ = gameepisode; *demo_p++ = gamemap; @@ -1579,19 +2109,79 @@ void G_DeferedPlayDemo (char* name) defdemoname = name; gameaction = ga_playdemo; } - + +// Generate a string describing a demo version + +static char *DemoVersionDescription(int version) +{ + static char resultbuf[16]; + + switch (version) + { + case 104: + return "v1.4"; + case 105: + return "v1.5"; + case 106: + return "v1.6/v1.666"; + case 107: + return "v1.7/v1.7a"; + case 108: + return "v1.8"; + case 109: + return "v1.9"; + default: + break; + } + + // Unknown version. Perhaps this is a pre-v1.4 IWAD? If the version + // byte is in the range 0-4 then it can be a v1.0-v1.2 demo. + + if (version >= 0 && version <= 4) + { + return "v1.0/v1.1/v1.2"; + } + else + { + M_snprintf(resultbuf, sizeof(resultbuf), + "%i.%i (unknown)", version / 100, version % 100); + return resultbuf; + } +} + void G_DoPlayDemo (void) { skill_t skill; int i, episode, map; + int demoversion; gameaction = ga_nothing; demobuffer = demo_p = W_CacheLumpName (defdemoname, PU_STATIC); - if ( *demo_p++ != VERSION) + + demoversion = *demo_p++; + + if (demoversion == G_VanillaVersionCode()) { - fprintf( stderr, "Demo is from a different game version! - Trying anyway...\n"); - //gameaction = ga_nothing; - //return; + longtics = false; + } + else if (demoversion == DOOM_191_VERSION) + { + // demo recorded with cph's modified "v1.91" doom exe + longtics = true; + } + else + { + char *message = "Demo is from a different game version!\n" + "(read %i, should be %i)\n" + "\n" + "*** You may need to upgrade your version " + "of Doom to v1.9. ***\n" + " See: https://www.doomworld.com/classicdoom" + "/info/patches.php\n" + " This appears to be %s."; + + I_Error(message, demoversion, G_VanillaVersionCode(), + DemoVersionDescription(demoversion)); } skill = *demo_p++; @@ -1605,16 +2195,19 @@ void G_DoPlayDemo (void) for (i=0 ; i 0 + || M_CheckParm("-netdemo") > 0) + { + netgame = true; + netdemo = true; } // don't spend a lot of time in loadlevel precache = false; G_InitNew (skill, episode, map); precache = true; + starttime = I_GetTime (); usergame = false; demoplayback = true; @@ -1624,9 +2217,15 @@ void G_DoPlayDemo (void) // G_TimeDemo // void G_TimeDemo (char* name) -{ +{ + //! + // @vanilla + // + // Disable rendering the screen entirely. + // + nodrawers = M_CheckParm ("-nodraw"); - noblit = M_CheckParm ("-noblit"); + timingdemo = true; singletics = true; @@ -1651,17 +2250,24 @@ boolean G_CheckDemoStatus (void) if (timingdemo) { + float fps; + int realtics; + endtime = I_GetTime (); - I_Error ("timed %i gametics in %i realtics",gametic - , endtime-starttime); + realtics = endtime - starttime; + fps = ((float) gametic * TICRATE) / realtics; + + // Prevent recursive calls + timingdemo = false; + demoplayback = false; + + I_Error ("timed %i gametics in %i realtics (%f fps)", + gametic, realtics, fps); } if (demoplayback) { - if (singledemo) - I_Quit (); - - Z_ChangeTag (demobuffer, PU_CACHE); + W_ReleaseLumpName(defdemoname); demoplayback = false; netdemo = false; netgame = false; @@ -1671,7 +2277,12 @@ boolean G_CheckDemoStatus (void) fastparm = false; nomonsters = false; consoleplayer = 0; - D_AdvanceDemo (); + + if (singledemo) + I_Quit (); + else + D_AdvanceDemo (); + return true; } diff --git a/frosted-doom/g_game.h b/frosted-doom/g_game.h index d84916c..da0df39 100644 --- a/frosted-doom/g_game.h +++ b/frosted-doom/g_game.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Duh. // -//----------------------------------------------------------------------------- #ifndef __G_GAME__ @@ -25,7 +22,7 @@ #include "doomdef.h" #include "d_event.h" - +#include "d_ticcmd.h" // @@ -65,15 +62,19 @@ void G_SecretExitLevel (void); void G_WorldDone (void); +// Read current data from inputs and build a player movement command. + +void G_BuildTiccmd (ticcmd_t *cmd, int maketic); + void G_Ticker (void); boolean G_Responder (event_t* ev); void G_ScreenShot (void); +void G_DrawMouseSpeedBox(void); +int G_VanillaVersionCode(void); +extern int vanilla_savegame_limit; +extern int vanilla_demo_limit; #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- + diff --git a/frosted-doom/gusconf.c b/frosted-doom/gusconf.c new file mode 100644 index 0000000..70cdd87 --- /dev/null +++ b/frosted-doom/gusconf.c @@ -0,0 +1,271 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// GUS emulation code. +// +// Actually emulating a GUS is far too much work; fortunately +// GUS "emulation" already exists in the form of Timidity, which +// supports GUS patch files. This code therefore converts Doom's +// DMXGUS lump into an equivalent Timidity configuration file. +// + + +#include +#include +#include +#include + +#include "w_wad.h" +#include "z_zone.h" + +#define MAX_INSTRUMENTS 256 + +typedef struct +{ + char *patch_names[MAX_INSTRUMENTS]; + int mapping[MAX_INSTRUMENTS]; +} gus_config_t; + +char *gus_patch_path = ""; +unsigned int gus_ram_kb = 1024; + +static unsigned int MappingIndex(void) +{ + unsigned int result = gus_ram_kb / 256; + + if (result < 1) + { + return 1; + } + else if (result > 4) + { + return 4; + } + else + { + return result; + } +} + +static int SplitLine(char *line, char **fields, unsigned int max_fields) +{ + unsigned int num_fields; + char *p; + + fields[0] = line; + num_fields = 1; + + for (p = line; *p != '\0'; ++p) + { + if (*p == ',') + { + *p = '\0'; + + // Skip spaces following the comma. + do + { + ++p; + } while (*p != '\0' && isspace(*p)); + + fields[num_fields] = p; + ++num_fields; + --p; + + if (num_fields >= max_fields) + { + break; + } + } + else if (*p == '#') + { + *p = '\0'; + break; + } + } + + // Strip off trailing whitespace from the end of the line. + p = fields[num_fields - 1] + strlen(fields[num_fields - 1]); + while (p > fields[num_fields - 1] && isspace(*(p - 1))) + { + --p; + *p = '\0'; + } + + return num_fields; +} + +static void ParseLine(gus_config_t *config, char *line) +{ + char *fields[6]; + unsigned int num_fields; + unsigned int instr_id, mapped_id; + + num_fields = SplitLine(line, fields, 6); + + if (num_fields < 6) + { + return; + } + + instr_id = atoi(fields[0]); + mapped_id = atoi(fields[MappingIndex()]); + + free(config->patch_names[instr_id]); + config->patch_names[instr_id] = strdup(fields[5]); + config->mapping[instr_id] = mapped_id; +} + +static void ParseDMXConfig(char *dmxconf, gus_config_t *config) +{ + char *p, *newline; + unsigned int i; + + memset(config, 0, sizeof(gus_config_t)); + + for (i = 0; i < MAX_INSTRUMENTS; ++i) + { + config->mapping[i] = -1; + } + + p = dmxconf; + + for (;;) + { + newline = strchr(p, '\n'); + + if (newline != NULL) + { + *newline = '\0'; + } + + ParseLine(config, p); + + if (newline == NULL) + { + break; + } + else + { + p = newline + 1; + } + } +} + +static void FreeDMXConfig(gus_config_t *config) +{ + unsigned int i; + + for (i = 0; i < MAX_INSTRUMENTS; ++i) + { + free(config->patch_names[i]); + } +} + +static char *ReadDMXConfig(void) +{ + int lumpnum; + unsigned int len; + char *data; + + // TODO: This should be chosen based on gamemode == commercial: + + lumpnum = W_CheckNumForName("DMXGUS"); + + if (lumpnum < 0) + { + lumpnum = W_GetNumForName("DMXGUSC"); + } + + len = W_LumpLength(lumpnum); + data = Z_Malloc(len + 1, PU_STATIC, NULL); + W_ReadLump(lumpnum, data); + + return data; +} + +static boolean WriteTimidityConfig(char *path, gus_config_t *config) +{ + FILE *fstream; + unsigned int i; + + fstream = fopen(path, "w"); + + if (fstream == NULL) + { + return false; + } + + fprintf(fstream, "# Autogenerated Timidity config.\n\n"); + + fprintf(fstream, "dir %s\n", gus_patch_path); + + fprintf(fstream, "\nbank 0\n\n"); + + for (i = 0; i < 128; ++i) + { + if (config->mapping[i] >= 0 && config->mapping[i] < MAX_INSTRUMENTS + && config->patch_names[config->mapping[i]] != NULL) + { + fprintf(fstream, "%i %s\n", + i, config->patch_names[config->mapping[i]]); + } + } + + fprintf(fstream, "\ndrumset 0\n\n"); + + for (i = 128 + 25; i < MAX_INSTRUMENTS; ++i) + { + if (config->mapping[i] >= 0 && config->mapping[i] < MAX_INSTRUMENTS + && config->patch_names[config->mapping[i]] != NULL) + { + fprintf(fstream, "%i %s\n", + i - 128, config->patch_names[config->mapping[i]]); + } + } + + fprintf(fstream, "\n"); + + fclose(fstream); + + return true; +} + +boolean GUS_WriteConfig(char *path) +{ + boolean result; + char *dmxconf; + gus_config_t config; + + if (!strcmp(gus_patch_path, "")) + { + printf("You haven't configured gus_patch_path.\n"); + printf("gus_patch_path needs to point to the location of " + "your GUS patch set.\n" + "To get a copy of the \"standard\" GUS patches, " + "download a copy of dgguspat.zip.\n"); + + return false; + } + + dmxconf = ReadDMXConfig(); + ParseDMXConfig(dmxconf, &config); + + result = WriteTimidityConfig(path, &config); + + FreeDMXConfig(&config); + Z_Free(dmxconf); + + return result; +} + diff --git a/frosted-doom/gusconf.h b/frosted-doom/gusconf.h new file mode 100644 index 0000000..e012426 --- /dev/null +++ b/frosted-doom/gusconf.h @@ -0,0 +1,29 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// GUS emulation code. +// + +#ifndef __GUSCONF_H__ +#define __GUSCONF_H__ + +#include "doomtype.h" + +extern char *gus_patch_path; +extern unsigned int gus_ram_kb; + +boolean GUS_WriteConfig(char *path); + +#endif /* #ifndef __GUSCONF_H__ */ + diff --git a/frosted-doom/hu_lib.c b/frosted-doom/hu_lib.c index 57fb52e..47038a0 100644 --- a/frosted-doom/hu_lib.c +++ b/frosted-doom/hu_lib.c @@ -1,34 +1,28 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: heads-up text and input code // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: hu_lib.c,v 1.3 1997/01/26 07:44:58 b1 Exp $"; #include #include "doomdef.h" +#include "doomkeys.h" #include "v_video.h" -#include "m_swap.h" +#include "i_swap.h" #include "hu_lib.h" #include "r_local.h" @@ -111,7 +105,7 @@ HUlib_drawTextLine x = l->x; for (i=0;ilen;i++) { - c = toupper(l->l[i]); + c = toupper((int)l->l[i]); if (c != ' ' && c >= l->sc && c <= '_') @@ -119,7 +113,7 @@ HUlib_drawTextLine w = SHORT(l->f[c - l->sc]->width); if (x+w > SCREENWIDTH) break; - V_DrawPatchDirect(x, l->y, FG, l->f[c - l->sc]); + V_DrawPatchDirect(x, l->y, l->f[c - l->sc]); x += w; } else @@ -134,7 +128,7 @@ HUlib_drawTextLine if (drawcursor && x + SHORT(l->f['_' - l->sc]->width) <= SCREENWIDTH) { - V_DrawPatchDirect(x, l->y, FG, l->f['_' - l->sc]); + V_DrawPatchDirect(x, l->y, l->f['_' - l->sc]); } } @@ -145,7 +139,6 @@ void HUlib_eraseTextLine(hu_textline_t* l) int lh; int y; int yoffset; - //static boolean lastautomapactive = true; // Only erases when NOT in automap and the screen is reduced, // and the text must either need updating or refreshing @@ -168,7 +161,6 @@ void HUlib_eraseTextLine(hu_textline_t* l) } } - //lastautomapactive = automapactive; if (l->needsupdate) l->needsupdate--; } @@ -319,6 +311,7 @@ HUlib_keyInIText ( hu_itext_t* it, unsigned char ch ) { + ch = toupper(ch); if (ch >= ' ' && ch <= '_') HUlib_addCharToTextLine(&it->l, (char) ch); diff --git a/frosted-doom/hu_lib.h b/frosted-doom/hu_lib.h index 8b809df..8f0994e 100644 --- a/frosted-doom/hu_lib.h +++ b/frosted-doom/hu_lib.h @@ -1,22 +1,19 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: none // -//----------------------------------------------------------------------------- #ifndef __HULIB__ #define __HULIB__ @@ -24,12 +21,6 @@ // We are referring to patches. #include "r_defs.h" - -// background and foreground screen numbers -// different from other modules. -#define BG 1 -#define FG 0 - // font stuff #define HU_CHARERASE KEY_BACKSPACE @@ -189,8 +180,3 @@ void HUlib_drawIText(hu_itext_t* it); void HUlib_eraseIText(hu_itext_t* it); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/hu_stuff.c b/frosted-doom/hu_stuff.c index efb1396..b63cac7 100644 --- a/frosted-doom/hu_stuff.c +++ b/frosted-doom/hu_stuff.c @@ -1,38 +1,36 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: Heads-up displays // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: hu_stuff.c,v 1.4 1997/02/03 16:47:52 b1 Exp $"; #include #include "doomdef.h" +#include "doomkeys.h" #include "z_zone.h" -#include "m_swap.h" +#include "deh_main.h" +#include "i_swap.h" +#include "i_video.h" #include "hu_stuff.h" #include "hu_lib.h" +#include "m_controls.h" +#include "m_misc.h" #include "w_wad.h" #include "s_sound.h" @@ -47,9 +45,10 @@ rcsid[] = "$Id: hu_stuff.c,v 1.4 1997/02/03 16:47:52 b1 Exp $"; // Locally used constants, shortcuts. // #define HU_TITLE (mapnames[(gameepisode-1)*9+gamemap-1]) -#define HU_TITLE2 (mapnames2[gamemap-1]) -#define HU_TITLEP (mapnamesp[gamemap-1]) -#define HU_TITLET (mapnamest[gamemap-1]) +#define HU_TITLE2 (mapnames_commercial[gamemap-1]) +#define HU_TITLEP (mapnames_commercial[gamemap-1 + 32]) +#define HU_TITLET (mapnames_commercial[gamemap-1 + 64]) +#define HU_TITLE_CHEX (mapnames[gamemap - 1]) #define HU_TITLEHEIGHT 1 #define HU_TITLEX 0 #define HU_TITLEY (167 - SHORT(hu_font[0]->height)) @@ -62,7 +61,7 @@ rcsid[] = "$Id: hu_stuff.c,v 1.4 1997/02/03 16:47:52 b1 Exp $"; -char* chat_macros[] = +char *chat_macros[10] = { HUSTR_CHATMACRO0, HUSTR_CHATMACRO1, @@ -84,7 +83,6 @@ char* player_names[] = HUSTR_PLRRED }; - char chat_char; // remove later. static player_t* plr; patch_t* hu_font[HU_FONTSIZE]; @@ -103,7 +101,6 @@ static hu_stext_t w_message; static int message_counter; extern int showMessages; -extern boolean automapactive; static boolean headsupactive = false; @@ -166,8 +163,16 @@ char* mapnames[] = // DOOM shareware/registered/retail (Ultimate) names. "NEWLEVEL" }; -char* mapnames2[] = // DOOM 2 map names. +// List of names for levels in commercial IWADs +// (doom2.wad, plutonia.wad, tnt.wad). These are stored in a +// single large array; WADs like pl2.wad have a MAP33, and rely on +// the layout in the Vanilla executable, where it is possible to +// overflow the end of one array into the next. + +char *mapnames_commercial[] = { + // DOOM 2 map names. + HUSTR_1, HUSTR_2, HUSTR_3, @@ -201,12 +206,10 @@ char* mapnames2[] = // DOOM 2 map names. HUSTR_29, HUSTR_30, HUSTR_31, - HUSTR_32 -}; + HUSTR_32, + // Plutonia WAD map names. -char* mapnamesp[] = // Plutonia WAD map names. -{ PHUSTR_1, PHUSTR_2, PHUSTR_3, @@ -240,12 +243,10 @@ char* mapnamesp[] = // Plutonia WAD map names. PHUSTR_29, PHUSTR_30, PHUSTR_31, - PHUSTR_32 -}; + PHUSTR_32, + + // TNT WAD map names. - -char *mapnamest[] = // TNT WAD map names. -{ THUSTR_1, THUSTR_2, THUSTR_3, @@ -282,113 +283,6 @@ char *mapnamest[] = // TNT WAD map names. THUSTR_32 }; - -const char* shiftxform; - -const char french_shiftxform[] = -{ - 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, - ' ', '!', '"', '#', '$', '%', '&', - '"', // shift-' - '(', ')', '*', '+', - '?', // shift-, - '_', // shift-- - '>', // shift-. - '?', // shift-/ - '0', // shift-0 - '1', // shift-1 - '2', // shift-2 - '3', // shift-3 - '4', // shift-4 - '5', // shift-5 - '6', // shift-6 - '7', // shift-7 - '8', // shift-8 - '9', // shift-9 - '/', - '.', // shift-; - '<', - '+', // shift-= - '>', '?', '@', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - '[', // shift-[ - '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK - ']', // shift-] - '"', '_', - '\'', // shift-` - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - '{', '|', '}', '~', 127 - -}; - -const char english_shiftxform[] = -{ - - 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, - ' ', '!', '"', '#', '$', '%', '&', - '"', // shift-' - '(', ')', '*', '+', - '<', // shift-, - '_', // shift-- - '>', // shift-. - '?', // shift-/ - ')', // shift-0 - '!', // shift-1 - '@', // shift-2 - '#', // shift-3 - '$', // shift-4 - '%', // shift-5 - '^', // shift-6 - '&', // shift-7 - '*', // shift-8 - '(', // shift-9 - ':', - ':', // shift-; - '<', - '+', // shift-= - '>', '?', '@', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - '[', // shift-[ - '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK - ']', // shift-] - '"', '_', - '\'', // shift-` - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - '{', '|', '}', '~', 127 -}; - -char frenchKeyMap[128]= -{ - 0, - 1,2,3,4,5,6,7,8,9,10, - 11,12,13,14,15,16,17,18,19,20, - 21,22,23,24,25,26,27,28,29,30, - 31, - ' ','!','"','#','$','%','&','%','(',')','*','+',';','-',':','!', - '0','1','2','3','4','5','6','7','8','9',':','M','<','=','>','?', - '@','Q','B','C','D','E','F','G','H','I','J','K','L',',','N','O', - 'P','A','R','S','T','U','V','Z','X','Y','W','^','\\','$','^','_', - '@','Q','B','C','D','E','F','G','H','I','J','K','L',',','N','O', - 'P','A','R','S','T','U','V','Z','X','Y','W','^','\\','$','^',127 -}; - -char ForeignTranslation(unsigned char ch) -{ - return ch < 128 ? frenchKeyMap[ch] : ch; -} - void HU_Init(void) { @@ -396,16 +290,11 @@ void HU_Init(void) int j; char buffer[9]; - if (french) - shiftxform = french_shiftxform; - else - shiftxform = english_shiftxform; - // load the heads-up font j = HU_FONTSTART; for (i=0;i= 'a' && c <= 'z') - c = (char) shiftxform[(unsigned char) c]; rc = HUlib_keyInIText(&w_inputbuffer[i], c); if (rc && c == KEY_ENTER) { @@ -556,7 +451,7 @@ void HU_Ticker(void) || chat_dest[i] == HU_BROADCAST)) { HUlib_addMessageToSText(&w_message, - player_names[i], + DEH_String(player_names[i]), w_inputbuffer[i].l.l); message_nottobefuckedwith = true; @@ -588,7 +483,7 @@ void HU_queueChatChar(char c) { if (((head + 1) & (QUEUESIZE-1)) == tail) { - plr->message = HUSTR_MSGU; + plr->message = DEH_String(HUSTR_MSGU); } else { @@ -620,20 +515,11 @@ boolean HU_Responder(event_t *ev) static char lastmessage[HU_MAXLINELENGTH+1]; char* macromessage; boolean eatkey = false; - static boolean shiftdown = false; static boolean altdown = false; unsigned char c; int i; int numplayers; - static char destination_keys[MAXPLAYERS] = - { - HUSTR_KEYGREEN, - HUSTR_KEYINDIGO, - HUSTR_KEYBROWN, - HUSTR_KEYRED - }; - static int num_nobrainers = 0; numplayers = 0; @@ -642,7 +528,6 @@ boolean HU_Responder(event_t *ev) if (ev->data1 == KEY_RSHIFT) { - shiftdown = ev->type == ev_keydown; return false; } else if (ev->data1 == KEY_RALT || ev->data1 == KEY_LALT) @@ -656,13 +541,13 @@ boolean HU_Responder(event_t *ev) if (!chat_on) { - if (ev->data1 == HU_MSGREFRESH) + if (ev->data1 == key_message_refresh) { message_on = true; message_counter = HU_MSGTIMEOUT; eatkey = true; } - else if (netgame && ev->data1 == HU_INPUTTOGGLE) + else if (netgame && ev->data2 == key_multi_msg) { eatkey = chat_on = true; HUlib_resetIText(&w_chat); @@ -672,7 +557,7 @@ boolean HU_Responder(event_t *ev) { for (i=0; idata1 == destination_keys[i]) + if (ev->data2 == key_multi_msgplayer[i]) { if (playeringame[i] && i!=consoleplayer) { @@ -685,15 +570,15 @@ boolean HU_Responder(event_t *ev) { num_nobrainers++; if (num_nobrainers < 3) - plr->message = HUSTR_TALKTOSELF1; + plr->message = DEH_String(HUSTR_TALKTOSELF1); else if (num_nobrainers < 6) - plr->message = HUSTR_TALKTOSELF2; + plr->message = DEH_String(HUSTR_TALKTOSELF2); else if (num_nobrainers < 9) - plr->message = HUSTR_TALKTOSELF3; + plr->message = DEH_String(HUSTR_TALKTOSELF3); else if (num_nobrainers < 32) - plr->message = HUSTR_TALKTOSELF4; + plr->message = DEH_String(HUSTR_TALKTOSELF4); else - plr->message = HUSTR_TALKTOSELF5; + plr->message = DEH_String(HUSTR_TALKTOSELF5); } } } @@ -701,11 +586,10 @@ boolean HU_Responder(event_t *ev) } else { - c = ev->data1; // send a macro if (altdown) { - c = c - '0'; + c = ev->data1 - '0'; if (c > 9) return false; // fprintf(stderr, "got here\n"); @@ -719,35 +603,33 @@ boolean HU_Responder(event_t *ev) HU_queueChatChar(*macromessage++); HU_queueChatChar(KEY_ENTER); - // leave chat mode and notify that it was sent - chat_on = false; - strcpy(lastmessage, chat_macros[c]); - plr->message = lastmessage; - eatkey = true; + // leave chat mode and notify that it was sent + chat_on = false; + M_StringCopy(lastmessage, chat_macros[c], sizeof(lastmessage)); + plr->message = lastmessage; + eatkey = true; } else { - if (french) - c = ForeignTranslation(c); - if (shiftdown || (c >= 'a' && c <= 'z')) - c = shiftxform[c]; + c = ev->data2; + eatkey = HUlib_keyInIText(&w_chat, c); if (eatkey) { // static unsigned char buf[20]; // DEBUG HU_queueChatChar(c); - // sprintf(buf, "KEY: %d => %d", ev->data1, c); - // plr->message = buf; + // M_snprintf(buf, sizeof(buf), "KEY: %d => %d", ev->data1, c); + // plr->message = buf; } if (c == KEY_ENTER) { chat_on = false; - if (w_chat.l.len) - { - strcpy(lastmessage, w_chat.l.l); - plr->message = lastmessage; - } + if (w_chat.l.len) + { + M_StringCopy(lastmessage, w_chat.l.l, sizeof(lastmessage)); + plr->message = lastmessage; + } } else if (c == KEY_ESCAPE) chat_on = false; diff --git a/frosted-doom/hu_stuff.h b/frosted-doom/hu_stuff.h index 3705028..a3affc5 100644 --- a/frosted-doom/hu_stuff.h +++ b/frosted-doom/hu_stuff.h @@ -1,22 +1,19 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: Head up display // -//----------------------------------------------------------------------------- #ifndef __HU_STUFF_H__ #define __HU_STUFF_H__ @@ -35,7 +32,6 @@ #define HU_BROADCAST 5 -#define HU_MSGREFRESH KEY_ENTER #define HU_MSGX 0 #define HU_MSGY 0 #define HU_MSGWIDTH 64 // in characters @@ -57,10 +53,7 @@ void HU_Drawer(void); char HU_dequeueChatChar(void); void HU_Erase(void); +extern char *chat_macros[10]; #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- + diff --git a/frosted-doom/i_cdmus.c b/frosted-doom/i_cdmus.c new file mode 100644 index 0000000..6a9a9a6 --- /dev/null +++ b/frosted-doom/i_cdmus.c @@ -0,0 +1,243 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 1993-2008 Raven Software +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// +// SDL implementation of the Hexen CD interface. +// + +#include + +#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; inumtracks; ++i) + { + if (cd_handle->track[i].type == SDL_AUDIO_TRACK) + { + cd_Error = 0; + + // Tracks are indexed from 1. + return i + 1; + } + } + + // Don't know? + cd_Error = 1; + + return -1; +#else + return 0; +#endif +} + +int I_CDMusLastTrack(void) +{ +#ifdef ORIGCODE + if (cd_handle == NULL) + { + cd_Error = 1; + return -1; + } + + cd_Error = 0; + + return cd_handle->numtracks; +#else + return 0; +#endif +} + +int I_CDMusTrackLength(int track_num) +{ +#ifdef ORIGCODE + SDL_CDtrack *track; + + if (cd_handle == NULL || track_num < 1 || track_num > cd_handle->numtracks) + { + cd_Error = 1; + return -1; + } + + // Track number is indexed from 1. + + track = &cd_handle->track[track_num - 1]; + + // Round up to the next second + + cd_Error = 0; + + return (track->length + CD_FPS - 1) / CD_FPS; +#else + return 0; +#endif +} + diff --git a/frosted-doom/i_cdmus.h b/frosted-doom/i_cdmus.h new file mode 100644 index 0000000..31db2a6 --- /dev/null +++ b/frosted-doom/i_cdmus.h @@ -0,0 +1,41 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 1993-2008 Raven Software +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// + +// i_cdmus.h + +#ifndef __ICDMUS__ +#define __ICDMUS__ + +#define CDERR_NOTINSTALLED 10 // MSCDEX not installed +#define CDERR_NOAUDIOSUPPORT 11 // CD-ROM Doesn't support audio +#define CDERR_NOAUDIOTRACKS 12 // Current CD has no audio tracks +#define CDERR_BADDRIVE 20 // Bad drive number +#define CDERR_BADTRACK 21 // Bad track number +#define CDERR_IOCTLBUFFMEM 22 // Not enough low memory for IOCTL +#define CDERR_DEVREQBASE 100 // DevReq errors + +extern int cd_Error; + +int I_CDMusInit(void); +void I_CDMusPrintStartup(void); +int I_CDMusPlay(int track); +int I_CDMusStop(void); +int I_CDMusResume(void); +int I_CDMusSetVolume(int volume); +int I_CDMusFirstTrack(void); +int I_CDMusLastTrack(void); +int I_CDMusTrackLength(int track); + +#endif diff --git a/frosted-doom/i_endoom.c b/frosted-doom/i_endoom.c new file mode 100644 index 0000000..98b8c87 --- /dev/null +++ b/frosted-doom/i_endoom.c @@ -0,0 +1,81 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Exit text-mode ENDOOM screen. +// + +#include +#include + +#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 0) + { + break; + } + + TXT_Sleep(0); + } + + // Shut down text mode screen + + TXT_Shutdown(); +#endif +} + diff --git a/frosted-doom/i_endoom.h b/frosted-doom/i_endoom.h new file mode 100644 index 0000000..8c8ff45 --- /dev/null +++ b/frosted-doom/i_endoom.h @@ -0,0 +1,29 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Exit text-mode ENDOOM screen. +// + + +#ifndef __I_ENDOOM__ +#define __I_ENDOOM__ + +// Display the Endoom screen on shutdown. Pass a pointer to the +// ENDOOM lump. + +void I_Endoom(byte *data); + +#endif + diff --git a/frosted-doom/i_joystick.c b/frosted-doom/i_joystick.c new file mode 100644 index 0000000..755aec3 --- /dev/null +++ b/frosted-doom/i_joystick.c @@ -0,0 +1,359 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// SDL Joystick code. +// + +#ifdef ORIGCODE +#include "SDL.h" +#include "SDL_joystick.h" +#endif + +#include +#include +#include + +#include "doomtype.h" +#include "d_event.h" +#include "i_joystick.h" +#include "i_system.h" + +#include "m_config.h" +#include "m_misc.h" + +// When an axis is within the dead zone, it is set to zero. +// This is 5% of the full range: + +#define DEAD_ZONE (32768 / 3) + +#ifdef ORIGCODE +static SDL_Joystick *joystick = NULL; +#endif + +// Configuration variables: + +// Standard default.cfg Joystick enable/disable + +static int usejoystick = 0; + +// Joystick to use, as an SDL joystick index: + +static int joystick_index = -1; + +// Which joystick axis to use for horizontal movement, and whether to +// invert the direction: + +static int joystick_x_axis = 0; +static int joystick_x_invert = 0; + +// Which joystick axis to use for vertical movement, and whether to +// invert the direction: + +static int joystick_y_axis = 1; +static int joystick_y_invert = 0; + +// Which joystick axis to use for strafing? + +static int joystick_strafe_axis = -1; +static int joystick_strafe_invert = 0; + +// Virtual to physical button joystick button mapping. By default this +// is a straight mapping. +static int joystick_physical_buttons[NUM_VIRTUAL_BUTTONS] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 +}; + +void I_ShutdownJoystick(void) +{ +#ifdef ORIGCODE + if (joystick != NULL) + { + SDL_JoystickClose(joystick); + joystick = NULL; + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + } +#endif +} + +#ifdef ORIGCODE +static boolean IsValidAxis(int axis) +{ + int num_axes; + + if (axis < 0) + { + return true; + } + + if (IS_BUTTON_AXIS(axis)) + { + return true; + } + + if (IS_HAT_AXIS(axis)) + { + return HAT_AXIS_HAT(axis) < SDL_JoystickNumHats(joystick); + } + + num_axes = SDL_JoystickNumAxes(joystick); + + return axis < num_axes; +} +#endif + +void I_InitJoystick(void) +{ +#ifdef ORIGCODE + if (!usejoystick) + { + return; + } + + if (SDL_Init(SDL_INIT_JOYSTICK) < 0) + { + return; + } + + if (joystick_index < 0 || joystick_index >= SDL_NumJoysticks()) + { + printf("I_InitJoystick: Invalid joystick ID: %i\n", joystick_index); + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + return; + } + + // Open the joystick + + joystick = SDL_JoystickOpen(joystick_index); + + if (joystick == NULL) + { + printf("I_InitJoystick: Failed to open joystick #%i\n", + joystick_index); + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + return; + } + + if (!IsValidAxis(joystick_x_axis) + || !IsValidAxis(joystick_y_axis) + || !IsValidAxis(joystick_strafe_axis)) + { + printf("I_InitJoystick: Invalid joystick axis for joystick #%i " + "(run joystick setup again)\n", + joystick_index); + + SDL_JoystickClose(joystick); + joystick = NULL; + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + } + + SDL_JoystickEventState(SDL_ENABLE); + + // Initialized okay! + + printf("I_InitJoystick: %s\n", SDL_JoystickName(joystick_index)); + + I_AtExit(I_ShutdownJoystick, true); +#endif +} + +#ifdef ORIGCODE +static boolean IsAxisButton(int physbutton) +{ + if (IS_BUTTON_AXIS(joystick_x_axis)) + { + if (physbutton == BUTTON_AXIS_NEG(joystick_x_axis) + || physbutton == BUTTON_AXIS_POS(joystick_x_axis)) + { + return true; + } + } + if (IS_BUTTON_AXIS(joystick_y_axis)) + { + if (physbutton == BUTTON_AXIS_NEG(joystick_y_axis) + || physbutton == BUTTON_AXIS_POS(joystick_y_axis)) + { + return true; + } + } + if (IS_BUTTON_AXIS(joystick_strafe_axis)) + { + if (physbutton == BUTTON_AXIS_NEG(joystick_strafe_axis) + || physbutton == BUTTON_AXIS_POS(joystick_strafe_axis)) + { + return true; + } + } + + return false; +} + +// Get the state of the given virtual button. + +static int ReadButtonState(int vbutton) +{ + int physbutton; + + // Map from virtual button to physical (SDL) button. + if (vbutton < NUM_VIRTUAL_BUTTONS) + { + physbutton = joystick_physical_buttons[vbutton]; + } + else + { + physbutton = vbutton; + } + + // Never read axis buttons as buttons. + if (IsAxisButton(physbutton)) + { + return 0; + } + + return SDL_JoystickGetButton(joystick, physbutton); +} + +// Get a bitmask of all currently-pressed buttons + +static int GetButtonsState(void) +{ + int i; + int result; + + result = 0; + + for (i = 0; i < 20; ++i) + { + if (ReadButtonState(i)) + { + result |= 1 << i; + } + } + + return result; +} + +// Read the state of an axis, inverting if necessary. + +static int GetAxisState(int axis, int invert) +{ + int result; + + // Axis -1 means disabled. + + if (axis < 0) + { + return 0; + } + + // Is this a button axis, or a hat axis? + // If so, we need to handle it specially. + + result = 0; + + if (IS_BUTTON_AXIS(axis)) + { + if (SDL_JoystickGetButton(joystick, BUTTON_AXIS_NEG(axis))) + { + result -= 32767; + } + if (SDL_JoystickGetButton(joystick, BUTTON_AXIS_POS(axis))) + { + result += 32767; + } + } + else if (IS_HAT_AXIS(axis)) + { + int direction = HAT_AXIS_DIRECTION(axis); + int hatval = SDL_JoystickGetHat(joystick, HAT_AXIS_HAT(axis)); + + if (direction == HAT_AXIS_HORIZONTAL) + { + if ((hatval & SDL_HAT_LEFT) != 0) + { + result -= 32767; + } + else if ((hatval & SDL_HAT_RIGHT) != 0) + { + result += 32767; + } + } + else if (direction == HAT_AXIS_VERTICAL) + { + if ((hatval & SDL_HAT_UP) != 0) + { + result -= 32767; + } + else if ((hatval & SDL_HAT_DOWN) != 0) + { + result += 32767; + } + } + } + else + { + result = SDL_JoystickGetAxis(joystick, axis); + + if (result < DEAD_ZONE && result > -DEAD_ZONE) + { + result = 0; + } + } + + if (invert) + { + result = -result; + } + + return result; +} +#endif +void I_UpdateJoystick(void) +{ +#ifdef ORIGCODE + if (joystick != NULL) + { + event_t ev; + + ev.type = ev_joystick; + ev.data1 = GetButtonsState(); + ev.data2 = GetAxisState(joystick_x_axis, joystick_x_invert); + ev.data3 = GetAxisState(joystick_y_axis, joystick_y_invert); + ev.data4 = GetAxisState(joystick_strafe_axis, joystick_strafe_invert); + + D_PostEvent(&ev); + } +#endif +} + +void I_BindJoystickVariables(void) +{ + int i; + + M_BindVariable("use_joystick", &usejoystick); + M_BindVariable("joystick_index", &joystick_index); + M_BindVariable("joystick_x_axis", &joystick_x_axis); + M_BindVariable("joystick_y_axis", &joystick_y_axis); + M_BindVariable("joystick_strafe_axis", &joystick_strafe_axis); + M_BindVariable("joystick_x_invert", &joystick_x_invert); + M_BindVariable("joystick_y_invert", &joystick_y_invert); + M_BindVariable("joystick_strafe_invert",&joystick_strafe_invert); + + for (i = 0; i < NUM_VIRTUAL_BUTTONS; ++i) + { + char name[32]; + M_snprintf(name, sizeof(name), "joystick_physical_button%i", i); + M_BindVariable(name, &joystick_physical_buttons[i]); + } +} + diff --git a/frosted-doom/i_joystick.h b/frosted-doom/i_joystick.h new file mode 100644 index 0000000..b8815e2 --- /dev/null +++ b/frosted-doom/i_joystick.h @@ -0,0 +1,70 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// System-specific joystick interface. +// + + +#ifndef __I_JOYSTICK__ +#define __I_JOYSTICK__ + +// Number of "virtual" joystick buttons defined in configuration files. +// This needs to be at least as large as the number of different key +// bindings supported by the higher-level game code (joyb* variables). +#define NUM_VIRTUAL_BUTTONS 10 + +// If this bit is set in a configuration file axis value, the axis is +// not actually a joystick axis, but instead is a "button axis". This +// means that instead of reading an SDL joystick axis, we read the +// state of two buttons to get the axis value. This is needed for eg. +// the PS3 SIXAXIS controller, where the D-pad buttons register as +// buttons, not as two axes. +#define BUTTON_AXIS 0x10000 + +// Query whether a given axis value describes a button axis. +#define IS_BUTTON_AXIS(axis) ((axis) >= 0 && ((axis) & BUTTON_AXIS) != 0) + +// Get the individual buttons from a button axis value. +#define BUTTON_AXIS_NEG(axis) ((axis) & 0xff) +#define BUTTON_AXIS_POS(axis) (((axis) >> 8) & 0xff) + +// Create a button axis value from two button values. +#define CREATE_BUTTON_AXIS(neg, pos) (BUTTON_AXIS | (neg) | ((pos) << 8)) + +// If this bit is set in an axis value, the axis is not actually a +// joystick axis, but is a "hat" axis. This means that we read (one of) +// the hats on the joystick. +#define HAT_AXIS 0x20000 + +#define IS_HAT_AXIS(axis) ((axis) >= 0 && ((axis) & HAT_AXIS) != 0) + +// Get the hat number from a hat axis value. +#define HAT_AXIS_HAT(axis) ((axis) & 0xff) +// Which axis of the hat? (horizonal or vertical) +#define HAT_AXIS_DIRECTION(axis) (((axis) >> 8) & 0xff) + +#define CREATE_HAT_AXIS(hat, direction) \ + (HAT_AXIS | (hat) | ((direction) << 8)) + +#define HAT_AXIS_HORIZONTAL 1 +#define HAT_AXIS_VERTICAL 2 + +void I_InitJoystick(void); +void I_ShutdownJoystick(void); +void I_UpdateJoystick(void); + +void I_BindJoystickVariables(void); + +#endif /* #ifndef __I_JOYSTICK__ */ + diff --git a/frosted-doom/i_main.c b/frosted-doom/i_main.c index e189e78..bb481eb 100644 --- a/frosted-doom/i_main.c +++ b/frosted-doom/i_main.c @@ -1,45 +1,50 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Main program, simply calls D_DoomMain high level loop. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: i_main.c,v 1.4 1997/02/03 22:45:10 b1 Exp $"; +#include "config.h" +#include - -#include "doomdef.h" - +#include "doomtype.h" +#include "i_system.h" #include "m_argv.h" -#include "d_main.h" -int -main -( int argc, - char** argv ) -{ - myargc = argc; - myargv = argv; - - D_DoomMain (); +// +// D_DoomMain() +// Not a globally visible function, just included for source reference, +// calls all startup code, parses command line options. +// + +void D_DoomMain (void); + +int main(int argc, char **argv) +{ + // save arguments + + myargc = argc; + myargv = argv; + + M_FindResponseFile(); + + // start doom + printf("Starting D_DoomMain\r\n"); + D_DoomMain (); return 0; -} +} + diff --git a/frosted-doom/i_net.c b/frosted-doom/i_net.c deleted file mode 100644 index e8cb017..0000000 --- a/frosted-doom/i_net.c +++ /dev/null @@ -1,332 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ -// -// DESCRIPTION: -// -//----------------------------------------------------------------------------- - -static const char -rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $"; - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#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 ; inumnodes ; 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 ... - i = M_CheckParm ("-net"); - if (!i) - { - // single player game - netgame = false; - doomcom->id = DOOMCOM_ID; - doomcom->numplayers = doomcom->numnodes = 1; - doomcom->deathmatch = false; - doomcom->consoleplayer = 0; - return; - } - - netsend = PacketSend; - netget = PacketGet; - netgame = true; - - // parse player number and host list - doomcom->consoleplayer = myargv[i+1][0]-'1'; - - doomcom->numnodes = 1; // this node for sure - - i++; - while (++i < myargc && myargv[i][0] != '-') - { - sendaddress[doomcom->numnodes].sin_family = AF_INET; - sendaddress[doomcom->numnodes].sin_port = htons(DOOMPORT); - if (myargv[i][0] == '.') - { - sendaddress[doomcom->numnodes].sin_addr.s_addr - = inet_addr (myargv[i]+1); - } - else - { - hostentry = gethostbyname (myargv[i]); - if (!hostentry) - I_Error ("gethostbyname: couldn't find %s", myargv[i]); - sendaddress[doomcom->numnodes].sin_addr.s_addr - = *(int *)hostentry->h_addr_list[0]; - } - doomcom->numnodes++; - } - - doomcom->id = DOOMCOM_ID; - doomcom->numplayers = doomcom->numnodes; - - // build message to receive - insocket = UDPsocket (); - BindToLocalPort (insocket,htons(DOOMPORT)); - //XXX ioctl (insocket, FIONBIO, &trueval); - fcntl (insocket,F_SETFL, O_NONBLOCK); - - sendsocket = UDPsocket (); -} - - -void I_NetCmd (void) -{ - if (doomcom->command == CMD_SEND) - { - netsend (); - } - else if (doomcom->command == CMD_GET) - { - netget (); - } - else - I_Error ("Bad net cmd: %i\n",doomcom->command); -} - diff --git a/frosted-doom/i_net.h b/frosted-doom/i_net.h deleted file mode 100644 index 6345447..0000000 --- a/frosted-doom/i_net.h +++ /dev/null @@ -1,45 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// DESCRIPTION: -// System specific network interface stuff. -// -//----------------------------------------------------------------------------- - - -#ifndef __I_NET__ -#define __I_NET__ - - -#ifdef __GNUG__ -#pragma interface -#endif - - - -// Called by D_DoomMain. - - -void I_InitNetwork (void); -void I_NetCmd (void); - - -#endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/i_oplmusic.c b/frosted-doom/i_oplmusic.c new file mode 100644 index 0000000..a1e9050 --- /dev/null +++ b/frosted-doom/i_oplmusic.c @@ -0,0 +1,1616 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// System interface for music. +// + + +#include +#include +#include + +#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; iindex, 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; inext) + { + 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; idata.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; idata.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; iiter, &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; ichannels[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 4 && !memcmp(mem, "MThd", 4); +} + +static boolean ConvertMus(byte *musdata, int len, char *filename) +{ + MEMFILE *instream; + MEMFILE *outstream; + void *outbuf; + size_t outbuf_len; + int result; + + instream = mem_fopen_read(musdata, len); + outstream = mem_fopen_write(); + + result = mus2mid(instream, outstream); + + if (result == 0) + { + mem_get_buf(outstream, &outbuf, &outbuf_len); + + M_WriteFile(filename, outbuf, outbuf_len); + } + + mem_fclose(instream); + mem_fclose(outstream); + + return result; +} + +static void *I_OPL_RegisterSong(void *data, int len) +{ + midi_file_t *result; + char *filename; + + if (!music_initialized) + { + return NULL; + } + + // MUS files begin with "MUS" + // Reject anything which doesnt have this signature + + filename = M_TempFile("doom.mid"); + + if (IsMid(data, len) && len < MAXMIDLENGTH) + { + M_WriteFile(filename, data, len); + } + else + { + // Assume a MUS file and try to convert + + ConvertMus(data, len, filename); + } + + result = MIDI_LoadFile(filename); + + if (result == NULL) + { + fprintf(stderr, "I_OPL_RegisterSong: Failed to load MID.\n"); + } + + // remove file now + + remove(filename); + free(filename); + + return result; +} + +// Is the song playing? + +static boolean I_OPL_MusicIsPlaying(void) +{ + if (!music_initialized) + { + return false; + } + + return num_tracks > 0; +} + +// Shutdown music + +static void I_OPL_ShutdownMusic(void) +{ + if (music_initialized) + { + // Stop currently-playing track, if there is one: + + I_OPL_StopSong(); + + OPL_Shutdown(); + + // Release GENMIDI lump + + W_ReleaseLumpName("GENMIDI"); + + music_initialized = false; + } +} + +// Initialize music subsystem + +static boolean I_OPL_InitMusic(void) +{ + OPL_SetSampleRate(snd_samplerate); + + if (!OPL_Init(opl_io_port)) + { + printf("Dude. The Adlib isn't responding.\n"); + return false; + } + + // Load instruments from GENMIDI lump: + + if (!LoadInstrumentTable()) + { + OPL_Shutdown(); + return false; + } + + InitVoices(); + + tracks = NULL; + num_tracks = 0; + music_initialized = true; + + return true; +} + +static snddevice_t music_opl_devices[] = +{ + SNDDEVICE_ADLIB, + SNDDEVICE_SB, +}; + +music_module_t music_opl_module = +{ + music_opl_devices, + arrlen(music_opl_devices), + I_OPL_InitMusic, + I_OPL_ShutdownMusic, + I_OPL_SetMusicVolume, + I_OPL_PauseSong, + I_OPL_ResumeSong, + I_OPL_RegisterSong, + I_OPL_UnRegisterSong, + I_OPL_PlaySong, + I_OPL_StopSong, + I_OPL_MusicIsPlaying, + NULL, // Poll +}; + +//---------------------------------------------------------------------- +// +// Development / debug message generation, to help developing GENMIDI +// lumps. +// +//---------------------------------------------------------------------- + +static int NumActiveChannels(void) +{ + int i; + + for (i = MIDI_CHANNELS_PER_TRACK - 1; i >= 0; --i) + { + if (tracks[0].channels[i].instrument != &main_instrs[0]) + { + return i + 1; + } + } + + return 0; +} + +static int ChannelInUse(opl_channel_data_t *channel) +{ + opl_voice_t *voice; + + for (voice = voice_alloced_list; voice != NULL; voice = voice->next) + { + if (voice->channel == channel) + { + return 1; + } + } + + return 0; +} + +void I_OPL_DevMessages(char *result, size_t result_len) +{ + char tmp[80]; + int instr_num; + int lines; + int i; + + if (num_tracks == 0) + { + M_snprintf(result, result_len, "No OPL track!"); + return; + } + + M_snprintf(result, result_len, "Tracks:\n"); + lines = 1; + + for (i = 0; i < NumActiveChannels(); ++i) + { + if (tracks[0].channels[i].instrument == NULL) + { + continue; + } + + instr_num = tracks[0].channels[i].instrument - main_instrs; + + M_snprintf(tmp, sizeof(tmp), + "chan %i: %c i#%i (%s)\n", + i, + ChannelInUse(&tracks[0].channels[i]) ? '\'' : ' ', + instr_num + 1, + main_instr_names[instr_num]); + M_StringConcat(result, tmp, result_len); + + ++lines; + } + + M_snprintf(tmp, sizeof(tmp), "\nLast percussion:\n"); + M_StringConcat(result, tmp, result_len); + lines += 2; + + i = (last_perc_count + PERCUSSION_LOG_LEN - 1) % PERCUSSION_LOG_LEN; + + do { + if (last_perc[i] == 0) + { + break; + } + + M_snprintf(tmp, sizeof(tmp), + "%cp#%i (%s)\n", + i == 0 ? '\'' : ' ', + last_perc[i], + percussion_names[last_perc[i] - 35]); + M_StringConcat(result, tmp, result_len); + ++lines; + + i = (i + PERCUSSION_LOG_LEN - 1) % PERCUSSION_LOG_LEN; + } while (lines < 25 && i != last_perc_count); +} + diff --git a/frosted-doom/i_pcsound.c b/frosted-doom/i_pcsound.c new file mode 100644 index 0000000..a7a8381 --- /dev/null +++ b/frosted-doom/i_pcsound.c @@ -0,0 +1,330 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// System interface for PC speaker sound. +// + +#include "SDL.h" +#include + +#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; iname, disabled_sounds[i])) + { + return true; + } + } + + return false; +} + +static int I_PCS_StartSound(sfxinfo_t *sfxinfo, + int channel, + int vol, + int sep) +{ + int result; + + if (!pcs_initialized) + { + return -1; + } + + if (IsDisabledSound(sfxinfo)) + { + return -1; + } + + if (SDL_LockMutex(sound_lock) < 0) + { + return -1; + } + + result = CachePCSLump(sfxinfo); + + if (result) + { + current_sound_handle = channel; + } + + SDL_UnlockMutex(sound_lock); + + if (result) + { + return channel; + } + else + { + return -1; + } +} + +static void I_PCS_StopSound(int handle) +{ + if (!pcs_initialized) + { + return; + } + + if (SDL_LockMutex(sound_lock) < 0) + { + return; + } + + // If this is the channel currently playing, immediately end it. + + if (current_sound_handle == handle) + { + current_sound_remaining = 0; + } + + SDL_UnlockMutex(sound_lock); +} + +// +// Retrieve the raw data lump index +// for a given SFX name. +// + +static int I_PCS_GetSfxLumpNum(sfxinfo_t* sfx) +{ + char namebuf[9]; + + if (use_sfx_prefix) + { + M_snprintf(namebuf, sizeof(namebuf), "dp%s", DEH_String(sfx->name)); + } + else + { + M_StringCopy(namebuf, DEH_String(sfx->name), sizeof(namebuf)); + } + + return W_GetNumForName(namebuf); +} + + +static boolean I_PCS_SoundIsPlaying(int handle) +{ + if (!pcs_initialized) + { + return false; + } + + if (handle != current_sound_handle) + { + return false; + } + + return current_sound_lump != NULL && current_sound_remaining > 0; +} + +static boolean I_PCS_InitSound(boolean _use_sfx_prefix) +{ + use_sfx_prefix = _use_sfx_prefix; + + // Use the sample rate from the configuration file + + PCSound_SetSampleRate(snd_samplerate); + + // Initialize the PC speaker subsystem. + + pcs_initialized = PCSound_Init(PCSCallbackFunc); + + if (pcs_initialized) + { + sound_lock = SDL_CreateMutex(); + } + + return pcs_initialized; +} + +static void I_PCS_ShutdownSound(void) +{ + if (pcs_initialized) + { + PCSound_Shutdown(); + } +} + +static void I_PCS_UpdateSound(void) +{ + // no-op. +} + +void I_PCS_UpdateSoundParams(int channel, int vol, int sep) +{ + // no-op. +} + +static snddevice_t sound_pcsound_devices[] = +{ + SNDDEVICE_PCSPEAKER, +}; + +sound_module_t sound_pcsound_module = +{ + sound_pcsound_devices, + arrlen(sound_pcsound_devices), + I_PCS_InitSound, + I_PCS_ShutdownSound, + I_PCS_GetSfxLumpNum, + I_PCS_UpdateSound, + I_PCS_UpdateSoundParams, + I_PCS_StartSound, + I_PCS_StopSound, + I_PCS_SoundIsPlaying, +}; + diff --git a/frosted-doom/i_scale.c b/frosted-doom/i_scale.c new file mode 100644 index 0000000..f88c694 --- /dev/null +++ b/frosted-doom/i_scale.c @@ -0,0 +1,1452 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Screen scale-up code: +// 1x,2x,3x,4x pixel doubling +// Aspect ratio-correcting stretch functions +// + +#include +#include +#include + +#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 240) + + for (y=0; y 480) + + for (y=0; y 720) + + for (y=0; y 960) + + for (y=0; y 1200) + + for (y=0; y 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 multiples of 320x240) + +extern screen_mode_t mode_stretch_1x; +extern screen_mode_t mode_stretch_2x; +extern screen_mode_t mode_stretch_3x; +extern screen_mode_t mode_stretch_4x; +extern screen_mode_t mode_stretch_5x; + +// Horizontally squashed modes (320x200 -> multiples of 256x200) + +extern screen_mode_t mode_squash_1x; +extern screen_mode_t mode_squash_2x; +extern screen_mode_t mode_squash_3x; +extern screen_mode_t mode_squash_4x; +extern screen_mode_t mode_squash_5x; + +#endif /* #ifndef __I_SCALE__ */ + diff --git a/frosted-doom/i_sdlmusic.c b/frosted-doom/i_sdlmusic.c new file mode 100644 index 0000000..cca4132 --- /dev/null +++ b/frosted-doom/i_sdlmusic.c @@ -0,0 +1,1322 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// System interface for music. +// + + +#include +#include +#include +#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 + // + // Read all MIDI files from loaded WAD files, dump an example substitution + // music config file to the specified filename and quit. + // + + i = M_CheckParmWithArgs("-dumpsubstconfig", 1); + + if (i > 0) + { + DumpSubstituteConfig(myargv[i + 1]); + } + + // If SDL_mixer is not initialized, we have to initialize it + // and have the responsibility to shut it down later on. + + if (SDLIsInitialized()) + { + music_initialized = true; + } + else + { + if (SDL_Init(SDL_INIT_AUDIO) < 0) + { + fprintf(stderr, "Unable to set up sound.\n"); + } + else if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, 1024) < 0) + { + fprintf(stderr, "Error initializing SDL_mixer: %s\n", + Mix_GetError()); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + } + else + { + SDL_PauseAudio(0); + + sdl_was_initialized = true; + music_initialized = true; + } + } + + // Once initialization is complete, the temporary Timidity config + // file can be removed. + + RemoveTimidityConfig(); + + // If snd_musiccmd is set, we need to call Mix_SetMusicCMD to + // configure an external music playback program. + + if (strlen(snd_musiccmd) > 0) + { + Mix_SetMusicCMD(snd_musiccmd); + } + + // Register an effect function to track the music position. + Mix_RegisterEffect(MIX_CHANNEL_POST, TrackPositionCallback, NULL, NULL); + + // If we're in GENMIDI mode, try to load sound packs. + if (snd_musicdevice == SNDDEVICE_GENMIDI) + { + LoadSubstituteConfigs(); + } + + return music_initialized; +} + +// +// SDL_mixer's native MIDI music playing does not pause properly. +// As a workaround, set the volume to 0 when paused. +// + +static void UpdateMusicVolume(void) +{ + int vol; + + if (musicpaused) + { + vol = 0; + } + else + { + vol = (current_music_volume * MIX_MAX_VOLUME) / 127; + } + + Mix_VolumeMusic(vol); +} + +// Set music volume (0 - 127) + +static void I_SDL_SetMusicVolume(int volume) +{ + // Internal state variable. + current_music_volume = volume; + + UpdateMusicVolume(); +} + +// Start playing a mid + +static void I_SDL_PlaySong(void *handle, boolean looping) +{ + int loops; + + if (!music_initialized) + { + return; + } + + if (handle == NULL) + { + return; + } + + current_track_music = (Mix_Music *) handle; + current_track_loop = looping; + + if (looping) + { + loops = -1; + } + else + { + loops = 1; + } + + // Don't loop when playing substitute music, as we do it + // ourselves instead. + if (playing_substitute && file_metadata.valid) + { + loops = 1; + SDL_LockAudio(); + current_track_pos = 0; // start of track + SDL_UnlockAudio(); + } + + Mix_PlayMusic(current_track_music, loops); +} + +static void I_SDL_PauseSong(void) +{ + if (!music_initialized) + { + return; + } + + musicpaused = true; + + UpdateMusicVolume(); +} + +static void I_SDL_ResumeSong(void) +{ + if (!music_initialized) + { + return; + } + + musicpaused = false; + + UpdateMusicVolume(); +} + +static void I_SDL_StopSong(void) +{ + if (!music_initialized) + { + return; + } + + Mix_HaltMusic(); + playing_substitute = false; + current_track_music = NULL; +} + +static void I_SDL_UnRegisterSong(void *handle) +{ + Mix_Music *music = (Mix_Music *) handle; + + if (!music_initialized) + { + return; + } + + if (handle == NULL) + { + return; + } + + Mix_FreeMusic(music); +} + +// Determine whether memory block is a .mid file + +static boolean IsMid(byte *mem, int len) +{ + return len > 4 && !memcmp(mem, "MThd", 4); +} + +static boolean ConvertMus(byte *musdata, int len, char *filename) +{ + MEMFILE *instream; + MEMFILE *outstream; + void *outbuf; + size_t outbuf_len; + int result; + + instream = mem_fopen_read(musdata, len); + outstream = mem_fopen_write(); + + result = mus2mid(instream, outstream); + + if (result == 0) + { + mem_get_buf(outstream, &outbuf, &outbuf_len); + + M_WriteFile(filename, outbuf, outbuf_len); + } + + mem_fclose(instream); + mem_fclose(outstream); + + return result; +} + +static void *I_SDL_RegisterSong(void *data, int len) +{ + char *filename; + Mix_Music *music; + + if (!music_initialized) + { + return NULL; + } + + playing_substitute = false; + + // See if we're substituting this MUS for a high-quality replacement. + filename = GetSubstituteMusicFile(data, len); + + if (filename != NULL) + { + music = Mix_LoadMUS(filename); + + if (music == NULL) + { + // Fall through and play MIDI normally, but print an error + // message. + fprintf(stderr, "Failed to load substitute music file: %s: %s\n", + filename, Mix_GetError()); + } + else + { + // Read loop point metadata from the file so that we know where + // to loop the music. + playing_substitute = true; + ReadLoopPoints(filename, &file_metadata); + return music; + } + } + + // MUS files begin with "MUS" + // Reject anything which doesnt have this signature + + filename = M_TempFile("doom.mid"); + + if (IsMid(data, len) && len < MAXMIDLENGTH) + { + M_WriteFile(filename, data, len); + } + else + { + // Assume a MUS file and try to convert + + ConvertMus(data, len, filename); + } + + // Load the MIDI. In an ideal world we'd be using Mix_LoadMUS_RW() + // by now, but Mix_SetMusicCMD() only works with Mix_LoadMUS(), so + // we have to generate a temporary file. + + music = Mix_LoadMUS(filename); + + if (music == NULL) + { + // Failed to load + + fprintf(stderr, "Error loading midi: %s\n", Mix_GetError()); + } + + // Remove the temporary MIDI file; however, when using an external + // MIDI program we can't delete the file. Otherwise, the program + // won't find the file to play. This means we leave a mess on + // disk :( + + if (strlen(snd_musiccmd) == 0) + { + remove(filename); + } + + free(filename); + + return music; +} + +// Is the song playing? +static boolean I_SDL_MusicIsPlaying(void) +{ + if (!music_initialized) + { + return false; + } + + return Mix_PlayingMusic(); +} + +// Get position in substitute music track, in seconds since start of track. +static double GetMusicPosition(void) +{ + unsigned int music_pos; + int freq; + + Mix_QuerySpec(&freq, NULL, NULL); + + SDL_LockAudio(); + music_pos = current_track_pos; + SDL_UnlockAudio(); + + return (double) music_pos / freq; +} + +static void RestartCurrentTrack(void) +{ + double start = (double) file_metadata.start_time + / file_metadata.samplerate_hz; + + // If the track is playing on loop then reset to the start point. + // Otherwise we need to stop the track. + if (current_track_loop) + { + // If the track finished we need to restart it. + if (current_track_music != NULL) + { + Mix_PlayMusic(current_track_music, 1); + } + + Mix_SetMusicPosition(start); + SDL_LockAudio(); + current_track_pos = file_metadata.start_time; + SDL_UnlockAudio(); + } + else + { + Mix_HaltMusic(); + current_track_music = NULL; + playing_substitute = false; + } +} + +// Poll music position; if we have passed the loop point end position +// then we need to go back. +static void I_SDL_PollMusic(void) +{ + if (playing_substitute && file_metadata.valid) + { + double end = (double) file_metadata.end_time + / file_metadata.samplerate_hz; + + // If we have reached the loop end point then we have to take action. + if (file_metadata.end_time >= 0 && GetMusicPosition() >= end) + { + RestartCurrentTrack(); + } + + // Have we reached the actual end of track (not loop end)? + if (!Mix_PlayingMusic() && current_track_loop) + { + RestartCurrentTrack(); + } + } +} + +static snddevice_t music_sdl_devices[] = +{ + SNDDEVICE_PAS, + SNDDEVICE_GUS, + SNDDEVICE_WAVEBLASTER, + SNDDEVICE_SOUNDCANVAS, + SNDDEVICE_GENMIDI, + SNDDEVICE_AWE32, +}; + +music_module_t music_sdl_module = +{ + music_sdl_devices, + arrlen(music_sdl_devices), + I_SDL_InitMusic, + I_SDL_ShutdownMusic, + I_SDL_SetMusicVolume, + I_SDL_PauseSong, + I_SDL_ResumeSong, + I_SDL_RegisterSong, + I_SDL_UnRegisterSong, + I_SDL_PlaySong, + I_SDL_StopSong, + I_SDL_MusicIsPlaying, + I_SDL_PollMusic, +}; + diff --git a/frosted-doom/i_sdlsound.c b/frosted-doom/i_sdlsound.c new file mode 100644 index 0000000..7089378 --- /dev/null +++ b/frosted-doom/i_sdlsound.c @@ -0,0 +1,1092 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// Copyright(C) 2008 David Flater +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// System interface for sound. +// + +#include "config.h" + +#include +#include +#include +#include +#include "SDL.h" +#include "SDL_mixer.h" + +#ifdef HAVE_LIBSAMPLERATE +#include +#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; iabuf; + + // Convert the result back into 16-bit integers. + + for (i=0; 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> 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; ilumpnum; + 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; idriver_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 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; imajor, + 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, +}; + diff --git a/frosted-doom/i_sound.c b/frosted-doom/i_sound.c index a8ca6ba..71947d2 100644 --- a/frosted-doom/i_sound.c +++ b/frosted-doom/i_sound.c @@ -1,985 +1,482 @@ -// 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: none // -// DESCRIPTION: -// System interface for sound. -// -//----------------------------------------------------------------------------- - -static const char -rcsid[] = "$Id: i_unix.c,v 1.5 1997/02/03 22:45:10 b1 Exp $"; #include #include -#include -#include -#include - -#include -#include - -#ifndef LINUX -#include +#ifdef ORIGCODE +#include "SDL_mixer.h" #endif -#include -#include -#include +#include "config.h" +#include "doomfeatures.h" +#include "doomtype.h" -// Linux voxware output. -#include - -// Timer stuff. Experimental. -#include -#include - -#include "z_zone.h" - -#include "i_system.h" +#ifdef ORIGCODE +#include "gusconf.h" +#endif #include "i_sound.h" +#include "i_video.h" #include "m_argv.h" -#include "m_misc.h" -#include "w_wad.h" +#include "m_config.h" -#include "doomdef.h" +// Sound sample rate to use for digital output (Hz) -// UNIX hack, to be removed. -#ifdef SNDSERV -// Separate sound server process. -FILE* sndserver=0; -char* sndserver_filename = "./sndserver "; -#elif SNDINTR +int snd_samplerate = 44100; -// Update all 30 millisecs, approx. 30fps synchronized. -// Linux resolution is allegedly 10 millisecs, -// scale is microseconds. -#define SOUND_INTERVAL 500 +// Maximum number of bytes to dedicate to allocated sound effects. +// (Default: 64MB) -// Get the interrupt. Set duration in millisecs. -int I_SoundSetTimer( int duration_of_tick ); -void I_SoundDelTimer( void ); -#else -// None? +int snd_cachesize = 64 * 1024 * 1024; + +// Config variable that controls the sound buffer size. +// We default to 28ms (1000 / 35fps = 1 buffer per tic). + +int snd_maxslicetime_ms = 28; + +// External command to invoke to play back music. + +char *snd_musiccmd = ""; + +// Low-level sound and music modules we are using + +static sound_module_t *sound_module; +static music_module_t *music_module; + +int snd_musicdevice = SNDDEVICE_SB; +int snd_sfxdevice = SNDDEVICE_SB; + +// Sound modules + +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; + +// For OPL module: + +extern int opl_io_port; + +// For native music module: + +extern char *timidity_cfg_path; + +// 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 +// Compiled-in sound modules: -// A quick hack to establish a protocol between -// synchronous mix buffer updates and asynchronous -// audio writes. Probably redundant with gametic. -static int flag = 0; - -// 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. - - -// 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) - -#define SAMPLERATE 11025 // Hz -#define SAMPLESIZE 2 // 16bit - -// The actual lengths of all sound effects. -int lengths[NUMSFX]; - -// The actual output device. -int audio_fd; - -// 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]; - - -// The channel step amount... -unsigned int channelstep[NUM_CHANNELS]; -// ... and a 0.16 bit remainder of last step. -unsigned int channelstepremainder[NUM_CHANNELS]; - - -// The channel data pointers, start and end. -unsigned char* channels[NUM_CHANNELS]; -unsigned char* channelsend[NUM_CHANNELS]; - - -// 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]; - -// The sound in channel handles, -// determined on registration, -// might be used to unregister/stop/modify, -// currently unused. -int channelhandles[NUM_CHANNELS]; - -// SFX id of the playing sound effect. -// Used to catch duplicates (like chainsaw). -int channelids[NUM_CHANNELS]; - -// Pitch to stepping lookup, unused. -int steptable[256]; - -// Volume lookups. -int vol_lookup[128*256]; - -// Hardware left and right channel volume lookup. -int* channelleftvol_lookup[NUM_CHANNELS]; -int* channelrightvol_lookup[NUM_CHANNELS]; - - - - -// -// 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); - } -} - - - - - -// -// This function loads the sound data from the WAD lump, -// for single sound. -// -void* -getsfx -( char* sfxname, - int* len ) +static sound_module_t *sound_modules[] = { - 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> 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; -} - - - - - -// -// 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; iname); - return W_GetNumForName(namebuf); -} - -// -// 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 ) -{ - - // 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; +#ifdef FEATURE_SOUND + &sound_sdl_module, + &sound_pcsound_module, #endif -} + NULL, +}; +// Compiled-in music modules: - -void I_StopSound (int handle) +static music_module_t *music_modules[] = { - // 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; -} - - -int I_SoundIsPlaying(int handle) -{ - // Ouch. - return gametic < handle; -} - - - - -// -// 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 ) -{ -#ifdef SNDINTR - // Debug. Count buffer misses with interrupt. - static int misses = 0; +#ifdef FEATURE_SOUND + &music_sdl_module, + &music_opl_module, #endif + NULL, +}; - - // 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; +// Check if a sound device is in the given list of devices - // Mixing channel index. - int chan; - - // Left and right channel - // are in global mixbuffer, alternating. - leftout = mixbuffer; - rightout = mixbuffer+1; - step = 2; +static boolean SndDeviceInList(snddevice_t device, snddevice_t *list, + int len) +{ + int i; - // 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) + for (i=0; i> 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; + if (device == list[i]) + { + return true; + } } -#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 + return false; } +// Find and initialize a sound_module_t appropriate for the setting +// in snd_sfxdevice. + +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 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) -{ - // Write it to DSP device. - write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL); +// Initializes sound stuff, including volume +// Sets channels, SFX and music volume, +// allocates channel buffer, sets S_sfx lookup. +// + +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. + // + + nosfx = M_CheckParm("-nosfx") > 0; + + //! + // @vanilla + // + // Disable music. + // + + nomusic = M_CheckParm("-nomusic") > 0; + + // Initialize the sound and music subsystems. + + 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(); + } + } } - - -void -I_UpdateSoundParams -( int handle, - int vol, - int sep, - int pitch) -{ - // 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; -} - - - - 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; - +{ + if (sound_module != NULL) + { + sound_module->Shutdown(); + } - // 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; + if (music_module != NULL) + { + music_module->Shutdown(); + } } - - - - - -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 ; iGetSfxLumpNum(sfxinfo); + } else { - // Previously loaded already? - S_sfx[i].data = S_sfx[i].link->data; - lengths[i] = lengths[(S_sfx[i].link - S_sfx)/sizeof(sfxinfo_t)]; + return 0; } - } +} - 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"); - +void I_UpdateSound(void) +{ + if (sound_module != NULL) + { + sound_module->Update(); + } + + 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_UpdateSoundParams(int channel, int vol, int sep) +{ + if (sound_module != NULL) + { + CheckVolumeSeparation(&vol, &sep); + sound_module->UpdateSoundParams(channel, vol, sep); + } +} + +int I_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep) +{ + if (sound_module != NULL) + { + CheckVolumeSeparation(&vol, &sep); + return sound_module->StartSound(sfxinfo, channel, vol, sep); + } + else + { + return 0; + } +} + +void I_StopSound(int channel) +{ + if (sound_module != NULL) + { + sound_module->StopSound(channel); + } +} + +boolean I_SoundIsPlaying(int channel) +{ + if (sound_module != NULL) + { + return sound_module->SoundIsPlaying(channel); + } + else + { + return false; + } +} + +void I_PrecacheSounds(sfxinfo_t *sounds, int num_sounds) +{ + if (sound_module != NULL && sound_module->CacheSounds != NULL) + { + sound_module->CacheSounds(sounds, num_sounds); + } +} + +void I_InitMusic(void) +{ +} + +void I_ShutdownMusic(void) +{ + +} + +void I_SetMusicVolume(int volume) +{ + if (music_module != NULL) + { + music_module->SetMusicVolume(volume); + } +} + +void I_PauseSong(void) +{ + if (music_module != NULL) + { + music_module->PauseMusic(); + } +} + +void I_ResumeSong(void) +{ + if (music_module != NULL) + { + music_module->ResumeMusic(); + } +} + +void *I_RegisterSong(void *data, int len) +{ + if (music_module != NULL) + { + return music_module->RegisterSong(data, len); + } + else + { + return NULL; + } +} + +void I_UnRegisterSong(void *handle) +{ + if (music_module != NULL) + { + music_module->UnRegisterSong(handle); + } +} + +void I_PlaySong(void *handle, boolean looping) +{ + if (music_module != NULL) + { + music_module->PlaySong(handle, looping); + } +} + +void I_StopSong(void) +{ + if (music_module != NULL) + { + music_module->StopSong(); + } +} + +boolean I_MusicIsPlaying(void) +{ + if (music_module != NULL) + { + return music_module->MusicIsPlaying(); + } + else + { + return false; + } +} + +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. + +#ifdef __MACOSX__ + { + const SDL_version *v = Mix_Linked_Version(); + + if (SDL_VERSIONNUM(v->major, v->minor, v->patch) + < SDL_VERSIONNUM(1, 2, 11)) + { + snd_musicdevice = SNDDEVICE_NONE; + } + } +#endif #endif } - - - -// -// 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) -{ - // UNUSED. - handle = looping = 0; - musicdies = gametic + TICRATE*30; -} - -void I_PauseSong (int handle) -{ - // UNUSED. - handle = 0; -} - -void I_ResumeSong (int handle) -{ - // UNUSED. - handle = 0; -} - -void I_StopSong(int handle) -{ - // UNUSED. - handle = 0; - - looping = 0; - musicdies = 0; -} - -void I_UnRegisterSong(int handle) -{ - // UNUSED. - handle = 0; -} - -int I_RegisterSong(void* data) -{ - // UNUSED. - data = NULL; - - return 1; -} - -// Is the song playing? -int I_QrySongPlaying(int handle) -{ - // UNUSED. - handle = 0; - return looping || musicdies > gametic; -} - - - -// -// 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; -#endif - - -// 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; -} - -// 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; -#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"); -} diff --git a/frosted-doom/i_sound.h b/frosted-doom/i_sound.h index bbfabac..e429e96 100644 --- a/frosted-doom/i_sound.h +++ b/frosted-doom/i_sound.h @@ -1,122 +1,238 @@ -// 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" - -// UNIX hack, to be removed. -#ifdef SNDSERV -#include -extern FILE* sndserver; -extern char* sndserver_filename; -#endif - -#include "doomstat.h" -#include "sounds.h" +#include "doomtype.h" +// +// SoundFX struct. +// +typedef struct sfxinfo_struct sfxinfo_t; -// Init at program start... -void I_InitSound(); +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. -// ... update sound buffer and audio device at runtime... -void I_UpdateSound(void); -void I_SubmitSound(void); + char name[9]; -// ... shut down and relase at program termination. + // Sfx priority + int priority; + + // referenced sound if a link + sfxinfo_t *link; + + // 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; +}; + +// +// 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 + 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; + +// Interface for sound modules + +typedef struct +{ + // List of sound devices that this sound module is used for. + + snddevice_t *sound_devices; + int num_sound_devices; + + // Initialise sound module + // Returns true if successfully initialised + + 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 -// -// SFX I/O -// +typedef struct +{ + // List of sound devices that this music module is used for. -// Initialize channels? -void I_SetChannels(); + snddevice_t *sound_devices; + int num_sound_devices; -// Get raw data lump index for sound descriptor. -int I_GetSfxLumpNum (sfxinfo_t* sfxinfo ); + // Initialise the music subsystem + boolean (*Init)(void); -// Starts a sound in a particular sound channel. -int -I_StartSound -( int id, - int vol, - int sep, - int pitch, - int priority ); + // Shutdown the music subsystem + void (*Shutdown)(void); -// Stops a sound channel. -void I_StopSound(int handle); + // Set music volume - range 0-127 -// 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); + void (*SetMusicVolume)(int volume); -// Updates the volume, separation, -// and pitch of a sound channel. -void -I_UpdateSoundParams -( int handle, - int vol, - int sep, - int pitch ); + // Pause music + void (*PauseMusic)(void); + + // Un-pause music + + void (*ResumeMusic)(void); + + // Register a song handle from data + // Returns a handle that can be used to play the song + + void *(*RegisterSong)(void *data, int len); + + // Un-register (free) song data + + void (*UnRegisterSong)(void *handle); + + // Play the song + + void (*PlaySong)(void *handle, boolean looping); + + // Stop playing the current song. + + void (*StopSong)(void); + + // Query if music is playing. + + boolean (*MusicIsPlaying)(void); + + // Invoked periodically to poll. + + void (*Poll)(void); +} music_module_t; -// -// MUSIC I/O -// void I_InitMusic(void); void I_ShutdownMusic(void); -// Volume. void I_SetMusicVolume(int volume); -// PAUSE game handling. -void I_PauseSong(int handle); -void I_ResumeSong(int handle); -// Registers a song handle to song data. -int I_RegisterSong(void *data); -// Called by anything that wishes to start music. -// plays a song, and when the song is done, -// starts playing it again in an endless loop. -// Horrible thing to do, considering. -void -I_PlaySong -( int handle, - int looping ); -// Stops a song over 3 seconds. -void I_StopSong(int handle); -// See above (register), then think backwards -void I_UnRegisterSong(int handle); +void I_PauseSong(void); +void I_ResumeSong(void); +void *I_RegisterSong(void *data, int len); +void I_UnRegisterSong(void *handle); +void I_PlaySong(void *handle, boolean looping); +void I_StopSong(void); +boolean I_MusicIsPlaying(void); +extern int snd_sfxdevice; +extern int snd_musicdevice; +extern int snd_samplerate; +extern int snd_cachesize; +extern int snd_maxslicetime_ms; +extern char *snd_musiccmd; +void I_BindSoundVariables(void); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- + diff --git a/frosted-doom/i_swap.h b/frosted-doom/i_swap.h new file mode 100644 index 0000000..d1fd754 --- /dev/null +++ b/frosted-doom/i_swap.h @@ -0,0 +1,54 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Endianess handling, swapping 16bit and 32bit. +// + + +#ifndef __I_SWAP__ +#define __I_SWAP__ + +#ifdef ORIGCODE +#include "SDL_endian.h" + +// Endianess handling. +// WAD files are stored little endian. + +// Just use SDL's endianness swapping functions. + +// These are deliberately cast to signed values; this is the behaviour +// of the macros in the original source and some code relies on it. + +#define SHORT(x) ((signed short) SDL_SwapLE16(x)) +#define LONG(x) ((signed int) SDL_SwapLE32(x)) + +// Defines for checking the endianness of the system. + +#if SDL_BYTEORDER == SYS_LIL_ENDIAN +#define SYS_LITTLE_ENDIAN +#elif SDL_BYTEORDER == SYS_BIG_ENDIAN +#define SYS_BIG_ENDIAN +#endif + +#else + +#define SHORT(x) ((signed short) (x)) +#define LONG(x) ((signed int) (x)) + +#define SYS_LITTLE_ENDIAN + +#endif +#endif + diff --git a/frosted-doom/i_system.c b/frosted-doom/i_system.c index cb16aa3..5d00091 100644 --- a/frosted-doom/i_system.c +++ b/frosted-doom/i_system.c @@ -1,182 +1,574 @@ -// 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 #include #include #include -#include + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else #include - -#include "doomdef.h" -#include "m_misc.h" -#include "i_video.h" -#include "i_sound.h" - -#include "d_net.h" -#include "g_game.h" - -#ifdef __GNUG__ -#pragma implementation "i_system.h" #endif + +#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_joystick.h" +#include "i_sound.h" +#include "i_timer.h" +#include "i_video.h" + #include "i_system.h" +#include "w_wad.h" +#include "z_zone.h" + +#ifdef __MACOSX__ +#include +#endif + +#define DEFAULT_RAM 6 /* MiB */ +#define MIN_RAM 6 /* MiB */ +typedef struct atexit_listentry_s atexit_listentry_t; -int mb_used = 6; - - -void -I_Tactile -( int on, - int off, - int total ) +struct atexit_listentry_s { - // UNUSED. - on = off = total = 0; + atexit_func_t func; + boolean run_on_error; + atexit_listentry_t *next; +}; + +static atexit_listentry_t *exit_funcs = NULL; + +void I_AtExit(atexit_func_t func, boolean run_on_error) +{ + 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 + // + // 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; ifunc(); + entry = entry->next; + } + +#if ORIGCODE + SDL_Quit(); + exit(0); -} - -void I_WaitVBL(int count) -{ -#ifdef SGI - sginap(1); -#else -#ifdef SUN - sleep(0); -#else - usleep (count * (1000000/70) ); -#endif #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); + va_start(argptr, error); + //fprintf(stderr, "\nError: "); + vfprintf(stderr, error, argptr); + fprintf(stderr, "\n\n"); + va_end(argptr); + fflush(stderr); - 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 + // + // 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; +} + diff --git a/frosted-doom/i_system.h b/frosted-doom/i_system.h index 8954140..b65daff 100644 --- a/frosted-doom/i_system.h +++ b/frosted-doom/i_system.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // System specific interface stuff. // -//----------------------------------------------------------------------------- #ifndef __I_SYSTEM__ @@ -26,10 +23,8 @@ #include "d_ticcmd.h" #include "d_event.h" -#ifdef __GNUG__ -#pragma interface -#endif +typedef void (*atexit_func_t)(void); // Called by DoomMain. void I_Init (void); @@ -39,29 +34,8 @@ void I_Init (void); // for the zone management. byte* I_ZoneBase (int *size); +boolean I_ConsoleStdout(void); -// Called by D_DoomLoop, -// returns current time in tics. -int I_GetTime (void); - - -// -// Called by D_DoomLoop, -// called before processing any tics in a frame -// (just after displaying a frame). -// Time consuming syncronous operations -// are performed here (joystick reading). -// Can call D_PostEvent. -// -void I_StartFrame (void); - - -// -// Called by D_DoomLoop, -// called before processing each tic in a frame. -// Quick syncronous operations are performed here. -// Can call D_PostEvent. -void I_StartTic (void); // Asynchronous interrupt functions should maintain private queues // that are read by the synchronous functions @@ -78,20 +52,33 @@ ticcmd_t* I_BaseTiccmd (void); // Clean exit, displays sell blurb. void I_Quit (void); - -// Allocates from low memory under dos, -// just mallocs under unix -byte* I_AllocLow (int length); +void I_Error (char *error, ...); void I_Tactile (int on, int off, int total); +boolean I_GetMemoryValue(unsigned int offset, void *value, int size); -void I_Error (char *error, ...); +// Schedule a function to be called when the program exits. +// If run_if_error is true, the function is called if the exit +// is due to an error (I_Error) +void I_AtExit(atexit_func_t func, boolean run_if_error); + +// Add all system-specific config file variable bindings. + +void I_BindVariables(void); + +// Print startup banner copyright message. + +void I_PrintStartupBanner(char *gamedescription); + +// Print a centered text banner displaying the given string. + +void I_PrintBanner(char *text); + +// Print a dividing line for startup banners. + +void I_PrintDivider(void); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- + diff --git a/frosted-doom/i_timer.c b/frosted-doom/i_timer.c new file mode 100644 index 0000000..081b38e --- /dev/null +++ b/frosted-doom/i_timer.c @@ -0,0 +1,93 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Timer functions. +// + +#include "i_timer.h" +#include "doomtype.h" + +#include +#include +#include + +// +// I_GetTime +// returns time in 1/35th second tics +// + +static uint32_t basetime = 0; + +int I_GetTicks(void) +{ + struct timeval tp; + struct timezone tzp; + + gettimeofday(&tp, &tzp); + return (tp.tv_sec * 1000) + (tp.tv_usec / 1000); /* return milliseconds */ +} + +int I_GetTime (void) +{ + uint32_t ticks; + + ticks = I_GetTicks(); + + if (basetime == 0) + basetime = ticks; + + ticks -= basetime; + + return (ticks * TICRATE) / 1000; +} + + +// +// Same as I_GetTime, but returns time in milliseconds +// + +int I_GetTimeMS(void) +{ + uint32_t ticks; + + ticks = I_GetTicks(); + + if (basetime == 0) + basetime = ticks; + + return ticks - basetime; +} + +// Sleep for a specified number of ms + +void I_Sleep(int ms) +{ + //SDL_Delay(ms); + usleep (ms * 1000); +} + +void I_WaitVBL(int count) +{ + //I_Sleep((count * 1000) / 70); +} + + +void I_InitTimer(void) +{ + // initialize timer + + //SDL_Init(SDL_INIT_TIMER); +} + diff --git a/frosted-doom/i_timer.h b/frosted-doom/i_timer.h new file mode 100644 index 0000000..9b3dbb8 --- /dev/null +++ b/frosted-doom/i_timer.h @@ -0,0 +1,42 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// System-specific timer interface +// + + +#ifndef __I_TIMER__ +#define __I_TIMER__ + +#define TICRATE 35 + +// Called by D_DoomLoop, +// returns current time in tics. +int I_GetTime (void); + +// returns current time in ms +int I_GetTimeMS (void); + +// Pause for a specified number of ms +void I_Sleep(int ms); + +// Initialize timer +void I_InitTimer(void); + +// Wait for vertical retrace or pause a bit. +void I_WaitVBL(int count); + +#endif + diff --git a/frosted-doom/i_video.c b/frosted-doom/i_video.c index 31af77b..def458b 100644 --- a/frosted-doom/i_video.c +++ b/frosted-doom/i_video.c @@ -1,178 +1,560 @@ -// 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 -#include -#include -#include +#include +#include +#include -#include -#include -#include - -#include -// 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++? +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include #endif -#include -#include -#include -#include +#include "icon.c" -#include -#include -#include - -#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 - -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) +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 +}; - int rc; - switch(rc = XKeycodeToKeysym(X_display, X_event.xkey.keycode, 0)) +#define LOADING_DISK_W 16 +#define LOADING_DISK_H 16 + +// Non aspect ratio-corrected modes (direct multiples of 320x200) + +static screen_mode_t *screen_modes[] = { + &mode_scale_1x, + &mode_scale_2x, + &mode_scale_3x, + &mode_scale_4x, + &mode_scale_5x, +}; + +// Aspect ratio corrected modes (4:3 ratio) + +static screen_mode_t *screen_modes_corrected[] = { + + // Vertically stretched modes (320x200 -> 320x240 and multiples) + + &mode_stretch_1x, + &mode_stretch_2x, + &mode_stretch_3x, + &mode_stretch_4x, + &mode_stretch_5x, + + // Horizontally squashed modes (320x200 -> 256x200 and multiples) + + &mode_squash_1x, + &mode_squash_2x, + &mode_squash_3x, + &mode_squash_4x, + &mode_squash_5x, +}; + +// SDL video driver name + +char *video_driver = ""; + +// Window position: + +static char *window_position = ""; + +// SDL surface for the screen. + +static SDL_Surface *screen; + +// Window title + +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; + +// palette + +static SDL_Color palette[256]; +static boolean palette_to_set; + +// display has been set up? + +static boolean initialized = false; + +// disable mouse? + +static boolean nomouse = false; +int usemouse = 1; + +// Bit mask of mouse button state. + +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 +// +// This emulates some of the behavior of DOS mouse drivers by increasing +// the speed when the mouse is moved fast. +// +// 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 the window doesn't have focus, never grab it + + if (!window_focused) + return false; + + // always grab the mouse when full screen (dont want to + // see the mouse pointer) + + 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 + + if (grabmouse_callback != NULL) { - 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; + return grabmouse_callback(); + } + else + { + return true; + } +} - case XK_Pause: rc = KEY_PAUSE; break; +void I_SetGrabMouseCallback(grabmouse_callback_t func) +{ + grabmouse_callback = func; +} - case XK_KP_Equal: - case XK_equal: rc = KEY_EQUALS; break; +// Set the variable controlling FPS dots. - case XK_KP_Subtract: - case XK_minus: rc = KEY_MINUS; break; +void I_DisplayFPSDots(boolean dots_on) +{ + display_fps_dots = dots_on; +} - 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; +// Update the value of window_focused when we get a focus event +// +// 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; + + state = SDL_GetAppState(); + + // We should have input (keyboard) focus and be visible + // (not minimized) + + window_focused = (state & SDL_APPINPUTFOCUS) && (state & SDL_APPACTIVE); + + // Should the screen be grabbed? + + 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 + { + SDL_SetCursor(cursors[0]); + } +#else + SDL_ShowCursor(show); +#endif + + // When the cursor is hidden, grab the input. + + if (!screensaver_mode) + { + SDL_WM_GrabInput(!show); + } +} + +void I_EnableLoadingDisk(void) +{ + patch_t *disk; + byte *tmpbuf; + char *disk_name; + int y; + char buf[20]; + + SDL_VideoDriverName(buf, 15); + + 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; } - return rc; + if (M_CheckParm("-cdrom") > 0) + disk_name = DEH_String("STCDROM"); + else + disk_name = DEH_String("STDISK"); + disk = W_CacheLumpName(disk_name, PU_STATIC); + + // 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); + + 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; ysym) + { + 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 + + case SDLK_MINUS: return KEY_MINUS; + + 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 + 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); + } } void I_ShutdownGraphics(void) { - // Detach from X server - if (!XShmDetach(X_display, &X_shminfo)) - I_Error("XShmDetach() failed in I_ShutdownGraphics()"); + if (initialized) + { + SetShowCursor(true); - // Release shared memory. - shmdt(X_shminfo.shmaddr); - shmctl(X_shminfo.shmid, IPC_RMID, 0); + SDL_QuitSubSystem(SDL_INIT_VIDEO); - // Paranoia. - image->data = NULL; + initialized = false; + } } @@ -186,121 +568,314 @@ void I_StartFrame (void) } -static int lastmousex = 0; -static int lastmousey = 0; -boolean mousemoved = false; -boolean shmFinished; +static void UpdateMouseButtonState(unsigned int button, boolean on) +{ + event_t event; + + if (button < SDL_BUTTON_LEFT || button > MAX_MOUSE_BUTTONS) + { + return; + } + + // Note: button "0" is left, button "1" is right, + // button "2" is middle for Doom. This is different + // to how SDL sees things. + + 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; + } + + // Turn bit representing this button on or off. + + if (on) + { + mouse_button_state |= (1 << button); + } + else + { + mouse_button_state &= ~(1 << button); + } + + // Post an event with the new button state. + + event.type = ev_mouse; + event.data1 = mouse_button_state; + event.data2 = event.data3 = 0; + D_PostEvent(&event); +} + +static int AccelerateMouse(int val) +{ + if (val < 0) + return -AccelerateMouse(-val); + + if (val > mouse_threshold) + { + return (int)((val - mouse_threshold) * mouse_acceleration + mouse_threshold); + } + else + { + return val; + } +} + +// 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 + { + // Unicode value, from key layout. + + return tolower(event->key.keysym.unicode); + } +} + +static void UpdateShiftStatus(SDL_Event *event) +{ + int change; + + if (event->type == SDL_KEYDOWN) + { + change = 1; + } + else if (event->type == SDL_KEYUP) + { + change = -1; + } + else + { + 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; + // possibly not needed + + SDL_PumpEvents(); + // put event-grabbing stuff in here - XNextEvent(X_display, &X_event); - switch (X_event.type) + + while (SDL_PollEvent(&sdlevent)) { - 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; + // ignore mouse events when the window is not focused - 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; + 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; + } } - } -Cursor -createnullcursor -( Display* display, - Window root ) -{ - Pixmap cursormask; - XGCValues xgc; - GC gc; - XColor dummycolour; - Cursor cursor; +// Warp the mouse back to the middle of the screen - 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 void CenterMouse(void) +{ + // 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 +} + +// +// 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. + +static void I_ReadMouse(void) +{ + 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) + { + 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); + } + + if (MouseShouldBeGrabbed()) + { + CenterMouse(); + } } // @@ -308,33 +883,19 @@ createnullcursor // void I_StartTic (void) { - - 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 (!initialized) { - if (!--doPointerWarp) - { - XWarpPointer( X_display, - None, - X_mainWindow, - 0, 0, - 0, 0, - X_width/2, X_height/2); - - doPointerWarp = POINTER_WARP_COUNTDOWN; - } + return; } - mousemoved = false; + I_GetEvent(); + if (usemouse && !nomouse) + { + I_ReadMouse(); + } + + I_UpdateJoystick(); } @@ -346,178 +907,236 @@ 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 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 (devparm) - { + if (display_fps_dots) + { i = I_GetTime(); tics = i - lasttic; lasttic = i; if (tics > 20) tics = 20; - for (i=0 ; idata[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; - } + // 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; + } } - else if (multiply == 3) + + // 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) { - unsigned int *olineptrs[3]; - unsigned int *ilineptr; - int x, y, i; - unsigned int fouropixels[3]; - unsigned int fouripixels; + SDL_Rect dst_rect; - ilineptr = (unsigned int *) (screens[0]); - for (i=0 ; i<3 ; i++) - olineptrs[i] = (unsigned int *) &image->data[i*X_width]; + // Center the buffer within the full screen space. - 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); + 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); } @@ -526,524 +1145,1068 @@ void I_FinishUpdate (void) // void I_ReadScreen (byte* scr) { - memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT); + memcpy(scr, I_VideoBuffer, SCREENWIDTH*SCREENHEIGHT); } -// -// Palette stuff. -// -static XColor colors[256]; - -void UploadNewPalette(Colormap cmap, byte *palette) -{ - - register int i; - register int c; - static boolean firstcall = true; - -#ifdef __cplusplus - if (X_visualinfo.c_class == PseudoColor && X_visualinfo.depth == 8) -#else - if (X_visualinfo.class == PseudoColor && X_visualinfo.depth == 8) -#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); - - } -} - // // I_SetPalette // -void I_SetPalette (byte* palette) +void I_SetPalette (byte *doompalette) { - UploadNewPalette(X_cmap, palette); + 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. -// -// This function is probably redundant, -// if XShmDetach works properly. -// ddt never detached the XShm memory, -// thus there might have been stale -// handles accumulating. -// -void grabsharedmemory(int size) +int I_GetPaletteIndex(int r, int g, int b) { + int best, best_diff, diff; + int i; - 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) + best = 0; best_diff = INT_MAX; + + for (i = 0; i < 256; ++i) { - 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); - } + 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; idata = X_shminfo.shmaddr = shmat(id, 0, 0); - - fprintf(stderr, "shared memory id=%d, addr=0x%x\n", id, - (int) (image->data)); +} + +// 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; iwidth > 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 + // + // Specify the screen width, in pixels. + // + + i = M_CheckParmWithArgs("-width", 1); + + if (i > 0) + { + screen_width = atoi(myargv[i + 1]); + } + + //! + // @category video + // @arg + // + // Specify the screen height, in pixels. + // + + i = M_CheckParmWithArgs("-height", 1); + + if (i > 0) + { + screen_height = atoi(myargv[i + 1]); + } + + //! + // @category video + // @arg + // + // 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 [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; - 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; + // Pass through the XSCREENSAVER_WINDOW environment variable to + // SDL_WINDOWID, to embed the SDL window into the Xscreensaver + // window. - if (!firsttime) - return; - firsttime = 0; + env = getenv("XSCREENSAVER_WINDOW"); - 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 + if (env != NULL) { - // 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"); + char winenv[30]; + int winid; + + sscanf(env, "0x%x", &winid); + M_snprintf(winenv, sizeof(winenv), "SDL_WINDOWID=%i", winid); + + putenv(winenv); } - // open the display - X_display = XOpenDisplay(displayname); - if (!X_display) + SetSDLVideoDriver(); + SetWindowPositionVars(); + + if (SDL_Init(SDL_INIT_VIDEO) < 0) { - if (displayname) - I_Error("Could not open display [%s]", displayname); - else - I_Error("Could not open display (DISPLAY=[%s])", getenv("DISPLAY")); + I_Error("Failed to initialize video: %s", SDL_GetError()); } - // 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; + // Set up title and icon. Windows cares about the ordering; this + // has to be done before the call to SDL_SetVideoMode. - // check for the MITSHM extension - doShm = XShmQueryExtension(X_display); + I_InitWindowTitle(); +#if !SDL_VERSION_ATLEAST(1, 3, 0) + I_InitWindowIcon(); +#endif - // even if it's available, make sure it's a local connection - if (doShm) + // Warning to OS X users... though they might never see it :( +#ifdef __MACOSX__ + if (fullscreen) { - 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; - } + 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 - fprintf(stderr, "Using MITSHM extension\n"); + // + // Enter into graphics mode. + // + // When in screensaver mode, run full screen and auto detect + // screen dimensions (don't change video mode) + // - // 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) + if (screensaver_mode) { - 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()"); - + SetVideoMode(NULL, 0, 0); } else { - image = XCreateImage( X_display, - X_visual, - 8, - ZPixmap, - 0, - (char*)malloc(X_width * X_height), - X_width, X_height, - 8, - X_width ); + 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); } - if (multiply == 1) - screens[0] = (unsigned char *) (image->data); + // 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 - screens[0] = (unsigned char *) malloc (SCREENWIDTH * SCREENHEIGHT); - -} - - -unsigned exptable[256]; - -void InitExpand (void) -{ - int i; - - for (i=0 ; i<256 ; i++) - exptable[i] = i | (i<<8) | (i<<16) | (i<<24); -} - -double exptable2[256*256]; - -void InitExpand2 (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; - } + I_VideoBuffer = (unsigned char *) Z_Malloc (SCREENWIDTH * SCREENHEIGHT, + PU_STATIC, NULL); } - printf ("done.\n"); + + 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); } -int inited; +// Bind all variables controlling video options into the configuration +// file system. -void -Expand4 -( unsigned* lineptr, - double* xline ) +void I_BindVideoVariables(void) { - double dpixel; - unsigned x; - unsigned y; - unsigned fourpixels; - unsigned step; - double* exp; - - exp = exptable2; - if (!inited) + 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) { - inited = 1; - InitExpand2 (); + 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; + } } - - - step = 3*SCREENWIDTH/2; - - y = SCREENHEIGHT-1; - do - { - x = SCREENWIDTH; +#endif - 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; + // Disable fullscreen by default on OS X, as there is an SDL bug + // where some old versions of OS X (<= Snow Leopard) crash. - 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--); +#ifdef __MACOSX__ + fullscreen = 0; + screen_width = 800; + screen_height = 600; +#endif } - - diff --git a/frosted-doom/i_video.h b/frosted-doom/i_video.h index ba8569b..3c7db19 100644 --- a/frosted-doom/i_video.h +++ b/frosted-doom/i_video.h @@ -1,63 +1,158 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // System specific interface stuff. // -//----------------------------------------------------------------------------- #ifndef __I_VIDEO__ #define __I_VIDEO__ - #include "doomtype.h" -#ifdef __GNUG__ -#pragma interface -#endif +// Screen width and height. +#define SCREENWIDTH 320 +#define SCREENHEIGHT 200 + +// Screen width used for "squash" scale functions + +#define SCREENWIDTH_4_3 256 + +// Screen height used for "stretch" scale functions. + +#define SCREENHEIGHT_4_3 240 + +#define MAX_MOUSE_BUTTONS 8 + +typedef struct +{ + // Screen width and height + + int width; + int height; + + // Initialisation function to call when using this mode. + // Called with a pointer to the Doom palette. + // + // If NULL, no init function is called. + + void (*InitMode)(byte *palette); + + // Function to call to draw the screen from the source buffer. + // Return true if draw was successful. + + boolean (*DrawScreen)(int x1, int y1, int x2, int y2); + + // If true, this is a "poor quality" mode. The autoadjust + // code should always attempt to use a different mode to this + // mode in fullscreen. + // + // Some notes about what "poor quality" means in this context: + // + // The aspect ratio correction works by scaling up to the larger + // screen size and then drawing pixels on the edges between the + // "virtual" pixels so that an authentic blocky look-and-feel is + // achieved. + // + // For a mode like 640x480, you can imagine the grid of the + // "original" pixels spaced out, with extra "blurry" pixels added + // in the space between them to fill it out. However, when you're + // running at a resolution like 320x240, this is not the case. In + // the small screen case, every single pixel has to be a blurry + // interpolation of two pixels from the original image. + // + // If you run in 320x240 and put your face up close to the screen + // you can see this: it's particularly visible in the small yellow + // status bar numbers for example. Overall it still looks "okay" + // but there's an obvious - albeit small - deterioration in + // quality. + // + // Once you get to 640x480, all the original pixels are there at + // least once and it's okay (the higher the resolution, the more + // accurate it is). When I first wrote the code I was expecting + // that even higher resolutions would be needed before it would + // look acceptable, but it turned out to be okay even at 640x480. + + boolean poor_quality; +} screen_mode_t; + +typedef boolean (*grabmouse_callback_t)(void); // Called by D_DoomMain, // determines the hardware configuration // and sets up the video mode void I_InitGraphics (void); +void I_GraphicsCheckCommandLine(void); void I_ShutdownGraphics(void); // Takes full 8 bit values. void I_SetPalette (byte* palette); +int I_GetPaletteIndex(int r, int g, int b); void I_UpdateNoBlit (void); void I_FinishUpdate (void); -// Wait for vertical retrace or pause a bit. -void I_WaitVBL(int count); - void I_ReadScreen (byte* scr); void I_BeginRead (void); -void I_EndRead (void); +void I_SetWindowTitle(char *title); +void I_CheckIsScreensaver(void); +void I_SetGrabMouseCallback(grabmouse_callback_t func); + +void I_DisplayFPSDots(boolean dots_on); +void I_BindVideoVariables(void); + +void I_InitWindowTitle(void); +void I_InitWindowIcon(void); + +// Called before processing any tics in a frame (just after displaying a frame). +// Time consuming syncronous operations are performed here (joystick reading). + +void I_StartFrame (void); + +// Called before processing each tic in a frame. +// Quick syncronous operations are performed here. + +void I_StartTic (void); + +// Enable the loading disk image displayed when reading from disk. + +void I_EnableLoadingDisk(void); + +extern char *video_driver; +extern boolean screenvisible; + +extern float mouse_acceleration; +extern int mouse_threshold; +extern int vanilla_keyboard_mapping; +extern boolean screensaver_mode; +extern int usegamma; +extern byte *I_VideoBuffer; + +extern int screen_width; +extern int screen_height; +extern int screen_bpp; +extern int fullscreen; +extern int aspect_ratio_correct; + +extern int show_diskicon; +extern int diskicon_readbytes; #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/i_video_SDL.c b/frosted-doom/i_video_SDL.c deleted file mode 100644 index 9d3ebb2..0000000 --- a/frosted-doom/i_video_SDL.c +++ /dev/null @@ -1,756 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ -// -// DESCRIPTION: -// DOOM graphics stuff for X11, UNIX. -// -//----------------------------------------------------------------------------- - -static const char -rcsid[] = "$Id: i_x.c,v 1.6 1997/02/03 22:45:10 b1 Exp $"; - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include - -#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 ; ipixels; - - y = SCREENHEIGHT; - while (y--) - { - memcpy(line_out, line_in, rgbsurf->w); - line_in += SCREENWIDTH; - line_out += rgbsurf->pitch; - } - } - - /* LOCK SCREEN */ - if (SDL_MUSTLOCK(screen)) { - if (SDL_LockSurface(screen) < 0) { - return; - } - } - - /* BLIT to SCREEN */ - SDL_BlitSurface(rgbsurf, NULL, screen, NULL); // blit it to the screen - - /* UNLOCK SCREEN */ - if ( SDL_MUSTLOCK(screen) ) { - SDL_UnlockSurface(screen); - } - - SDL_UpdateWindowSurface(window); - -} - - -// -// I_ReadScreen -// -void I_ReadScreen (byte* scr) -{ - printf("I_ReadScreen\n"); - memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT); - //memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT); -} - - -// -// I_SetPalette -// -void I_SetPalette (byte* palette) -{ - SDL_Color colors[256]; - - printf("I_SetPalette\n"); - - for (int i=0; i<256; ++i ) { - colors[i].r = gammatable[usegamma][*palette++]; - colors[i].g = gammatable[usegamma][*palette++]; - colors[i].b = gammatable[usegamma][*palette++]; - } - - if(rgbsurf->format->BitsPerPixel!=8){ - printf("Not an 8-bit surface.\n"); - return; - } - - int j = SDL_SetPaletteColors(rgbsurf->format->palette, colors, 0, 256); - printf("SDL_SetPaletteColors: %i\n", j); -} - -void I_InitGraphics(void) -{ - uint32_t video_flags = 0; - - //video_flags = (SDL_SWSURFACE|SDL_HWPALETTE); - if (M_CheckParm("-fullscreen")) - video_flags |= SDL_WINDOW_FULLSCREEN; - - X_width = SCREENWIDTH; - X_height = SCREENHEIGHT; - - printf("I_InitGraphics: w x h: %d x %d\n", X_width, X_height); - - // Initialize SDL. - if (SDL_Init(SDL_INIT_VIDEO) < 0) - { - printf("SDL_Init failed\n"); - return; - } - - // Create the window where we will draw. - window = SDL_CreateWindow("fDOOM v1.0", - SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - X_width, X_height, - video_flags); - - screen = SDL_GetWindowSurface(window); - rgbsurf = SDL_CreateRGBSurface(0,X_width,X_height,8,0,0,0,0); - - screens[0] = (unsigned char *)screen->pixels; - - /* Blit shit to the screen */ - // image = SDL_LoadBMP("box.bmp"); // loads image - // SDL_BlitSurface(image, NULL, screen, NULL); // blit it to the screen - // SDL_FreeSurface(image); - // SDL_UpdateWindowSurface(window); - - signal(SIGINT, (void (*)(int)) I_Quit); - - return; - - /* - char* displayname; - char* d; - int n; - int pnum; - int x=0; - int y=0; - - // warning: char format, different type arg - char xsign=' '; - char ysign=' '; - - int oktodraw; - unsigned long attribmask; - XSetWindowAttributes attribs; - XGCValues xgcvalues; - int valuemask; - static int firsttime=1; - - if (!firsttime) - return; - firsttime = 0; - - signal(SIGINT, (void (*)(int)) I_Quit); - - if (M_CheckParm("-2")) - multiply = 2; - - if (M_CheckParm("-3")) - multiply = 3; - - if (M_CheckParm("-4")) - multiply = 4; - - X_width = SCREENWIDTH * multiply; - X_height = SCREENHEIGHT * multiply; - - // check for command-line display name - if ( (pnum=M_CheckParm("-disp")) ) // suggest parentheses around assignment - displayname = myargv[pnum+1]; - else - displayname = 0; - - // check if the user wants to grab the mouse (quite unnice) - grabMouse = !!M_CheckParm("-grabmouse"); - - // check for command-line geometry - if ( (pnum=M_CheckParm("-geom")) ) // suggest parentheses around assignment - { - // warning: char format, different type arg 3,5 - n = sscanf(myargv[pnum+1], "%c%d%c%d", &xsign, &x, &ysign, &y); - - if (n==2) - x = y = 0; - else if (n==6) - { - if (xsign == '-') - x = -x; - if (ysign == '-') - y = -y; - } - else - I_Error("bad -geom parameter"); - } - - // open the display - X_display = XOpenDisplay(displayname); - if (!X_display) - { - if (displayname) - I_Error("Could not open display [%s]", displayname); - else - I_Error("Could not open display (DISPLAY=[%s])", getenv("DISPLAY")); - } - - // use the default visual - X_screen = DefaultScreen(X_display); - if (!XMatchVisualInfo(X_display, X_screen, 8, PseudoColor, &X_visualinfo)) - I_Error("xdoom currently only supports 256-color PseudoColor screens"); - X_visual = X_visualinfo.visual; - - // check for the MITSHM extension - doShm = XShmQueryExtension(X_display); - - // even if it's available, make sure it's a local connection - if (doShm) - { - if (!displayname) displayname = (char *) getenv("DISPLAY"); - if (displayname) - { - d = displayname; - while (*d && (*d != ':')) d++; - if (*d) *d = 0; - if (!(!strcasecmp(displayname, "unix") || !*displayname)) doShm = false; - } - } - - fprintf(stderr, "Using MITSHM extension\n"); - - // create the colormap - X_cmap = XCreateColormap(X_display, RootWindow(X_display, - X_screen), X_visual, AllocAll); - - // setup attributes for main window - attribmask = CWEventMask | CWColormap | CWBorderPixel; - attribs.event_mask = - KeyPressMask - | KeyReleaseMask - // | PointerMotionMask | ButtonPressMask | ButtonReleaseMask - | ExposureMask; - - attribs.colormap = X_cmap; - attribs.border_pixel = 0; - - // create the main window - X_mainWindow = XCreateWindow( X_display, - RootWindow(X_display, X_screen), - x, y, - X_width, X_height, - 0, // borderwidth - 8, // depth - InputOutput, - X_visual, - attribmask, - &attribs ); - - XDefineCursor(X_display, X_mainWindow, - createnullcursor( X_display, X_mainWindow ) ); - - // create the GC - valuemask = GCGraphicsExposures; - xgcvalues.graphics_exposures = False; - X_gc = XCreateGC( X_display, - X_mainWindow, - valuemask, - &xgcvalues ); - - // map the window - XMapWindow(X_display, X_mainWindow); - - // wait until it is OK to draw - oktodraw = 0; - while (!oktodraw) - { - XNextEvent(X_display, &X_event); - if (X_event.type == Expose - && !X_event.xexpose.count) - { - oktodraw = 1; - } - } - - // grabs the pointer so it is restricted to this window - if (grabMouse) - XGrabPointer(X_display, X_mainWindow, True, - ButtonPressMask|ButtonReleaseMask|PointerMotionMask, - GrabModeAsync, GrabModeAsync, - X_mainWindow, None, CurrentTime); - - if (doShm) - { - - X_shmeventtype = XShmGetEventBase(X_display) + ShmCompletion; - - // create the image - image = XShmCreateImage( X_display, - X_visual, - 8, - ZPixmap, - 0, - &X_shminfo, - X_width, - X_height ); - - grabsharedmemory(image->bytes_per_line * image->height); - - - // UNUSED - // create the shared memory segment - // X_shminfo.shmid = shmget (IPC_PRIVATE, - // image->bytes_per_line * image->height, IPC_CREAT | 0777); - // if (X_shminfo.shmid < 0) - // { - // perror(""); - // I_Error("shmget() failed in InitGraphics()"); - // } - // fprintf(stderr, "shared memory id=%d\n", X_shminfo.shmid); - // attach to the shared memory segment - // image->data = X_shminfo.shmaddr = shmat(X_shminfo.shmid, 0, 0); - - - if (!image->data) - { - perror(""); - I_Error("shmat() failed in InitGraphics()"); - } - - // get the X server to attach to it - if (!XShmAttach(X_display, &X_shminfo)) - I_Error("XShmAttach() failed in InitGraphics()"); - - } - else - { - image = XCreateImage( X_display, - X_visual, - 8, - ZPixmap, - 0, - (char*)malloc(X_width * X_height), - X_width, X_height, - 8, - X_width ); - - } - - if (multiply == 1) - screens[0] = (unsigned char *) (image->data); - else - screens[0] = (unsigned char *) malloc (SCREENWIDTH * SCREENHEIGHT); - - */ -} - - -void InitExpand (void) -{ - /* - int i; - - for (i=0 ; i<256 ; i++) - exptable[i] = i | (i<<8) | (i<<16) | (i<<24); - */ -} - - -void InitExpand2 (void) -{ - return; - /* - int i; - int j; - // UNUSED unsigned iexp, jexp; - double* exp; - union - { - double d; - unsigned u[2]; - } pixel; - - printf ("building exptable2...\n"); - exp = exptable2; - for (i=0 ; i<256 ; i++) - { - pixel.u[0] = i | (i<<8) | (i<<16) | (i<<24); - for (j=0 ; j<256 ; j++) - { - pixel.u[1] = j | (j<<8) | (j<<16) | (j<<24); - *exp++ = pixel.d; - } - } - printf ("done.\n"); - */ -} - -int inited; - -void -Expand4 -( unsigned* lineptr, - double* xline ) -{ - return; - /* - double dpixel; - unsigned x; - unsigned y; - unsigned fourpixels; - unsigned step; - double* exp; - - exp = exptable2; - if (!inited) - { - inited = 1; - InitExpand2 (); - } - - - step = 3*SCREENWIDTH/2; - - y = SCREENHEIGHT-1; - do - { - x = SCREENWIDTH; - - do - { - fourpixels = lineptr[0]; - - dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) ); - xline[0] = dpixel; - xline[160] = dpixel; - xline[320] = dpixel; - xline[480] = dpixel; - - dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) ); - xline[1] = dpixel; - xline[161] = dpixel; - xline[321] = dpixel; - xline[481] = dpixel; - - fourpixels = lineptr[1]; - - dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) ); - xline[2] = dpixel; - xline[162] = dpixel; - xline[322] = dpixel; - xline[482] = dpixel; - - dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) ); - xline[3] = dpixel; - xline[163] = dpixel; - xline[323] = dpixel; - xline[483] = dpixel; - - fourpixels = lineptr[2]; - - dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) ); - xline[4] = dpixel; - xline[164] = dpixel; - xline[324] = dpixel; - xline[484] = dpixel; - - dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) ); - xline[5] = dpixel; - xline[165] = dpixel; - xline[325] = dpixel; - xline[485] = dpixel; - - fourpixels = lineptr[3]; - - dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) ); - xline[6] = dpixel; - xline[166] = dpixel; - xline[326] = dpixel; - xline[486] = dpixel; - - dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) ); - xline[7] = dpixel; - xline[167] = dpixel; - xline[327] = dpixel; - xline[487] = dpixel; - - lineptr+=4; - xline+=8; - } while (x-=16); - xline += step; - } while (y--); - */ -} - - diff --git a/frosted-doom/i_video_dummy.c b/frosted-doom/i_video_dummy.c deleted file mode 100644 index 8981e2c..0000000 --- a/frosted-doom/i_video_dummy.c +++ /dev/null @@ -1,919 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ -// -// DESCRIPTION: -// DOOM graphics stuff for X11, UNIX. -// -//----------------------------------------------------------------------------- - -static const char -rcsid[] = "$Id: i_x.c,v 1.6 1997/02/03 22:45:10 b1 Exp $"; - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#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 ; idata[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--); - */ -} - - diff --git a/frosted-doom/i_video_fbdev.c b/frosted-doom/i_video_fbdev.c index a18dd45..e4adc47 100644 --- a/frosted-doom/i_video_fbdev.c +++ b/frosted-doom/i_video_fbdev.c @@ -5,25 +5,38 @@ // // Copyright (C) 1993-1996 by id Software, Inc. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // $Log:$ // // DESCRIPTION: -// DOOM graphics stuff for fbdev on Frosted +// DOOM graphics stuff for X11, UNIX. // //----------------------------------------------------------------------------- static const char rcsid[] = "$Id: i_x.c,v 1.6 1997/02/03 22:45:10 b1 Exp $"; +#include "config.h" +#include "v_video.h" +#include "m_argv.h" +#include "d_event.h" +#include "d_main.h" +#include "i_video.h" +#include "z_zone.h" + +#include "tables.h" +#include "doomkeys.h" + +#include #include #include #include @@ -34,18 +47,6 @@ rcsid[] = "$Id: i_x.c,v 1.6 1997/02/03 22:45:10 b1 Exp $"; #include #include -#include -#include -#include - -#include "doomstat.h" -#include "i_system.h" -#include "v_video.h" -#include "m_argv.h" -#include "d_main.h" - -#include "doomdef.h" - struct color { uint32_t b:8; uint32_t g:8; @@ -53,7 +54,11 @@ struct color { uint32_t a:8; }; -struct color colors[256]; +static struct color colors[256]; + +// The screen buffer; this is modified to draw things to the screen + +byte *I_VideoBuffer = NULL; /* framebuffer file descriptor */ int fd_fb = 0; @@ -61,160 +66,290 @@ int fd_fb = 0; int X_width; int X_height; +// If true, game is running as a screensaver -void I_ShutdownGraphics(void) +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 +// +// This emulates some of the behavior of DOS mouse drivers by increasing +// the speed when the mouse is moved fast. +// +// 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; + +int usemouse = 0; + +// 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 { - printf("I_ShutdownGraphics\n"); - // Always be sure to clean up - //SDL_Quit(); - close(fd_fb); + byte r; + byte g; + byte b; +} col_t; + +// Palette converted to RGB565 + +static uint16_t rgb565_palette[256]; + +// Last touch state + +//static touch_state_t last_touch_state; + +// Last button state + +//static bool last_button_state; + +// run state + +//static bool run; + +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) + { + printf("Could not open /dev/fb0"); + exit(-1); + } + + /* 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); +} - -// -// I_StartFrame -// void I_StartFrame (void) { - // er? } -void I_GetEvent(void) +void I_GetEvent (void) { - /* - 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; - } - */ - +// 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; +// +// 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); +// } } -// -// 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? } // @@ -224,51 +359,34 @@ void I_UpdateNoBlit (void) #define FB_HEIGHT (272) #define FB_BPP_RGB565 (16) -unsigned char line_out[FB_WIDTH * (FB_BPP_RGB565/8)]; - -void cmap_to_rgb565(uint16_t * out, uint8_t * in, int in_pixels) -{ - int i; - struct color c; - uint16_t r, g, b; - - for (i = 0; i < in_pixels; i++) - { - c = colors[*in]; - r = ((uint16_t)(c.r >> 3)) << 11; - g = ((uint16_t)(c.g >> 2)) << 5; - b = ((uint16_t)(c.b >> 3)) << 0; - *out = (r | g | b); - - in++; - out++; - } -} - void I_FinishUpdate (void) { + //int x, y; + int y; unsigned char *line_in; - static int lasttic; - int tics; - int i; - int y; + //byte index; - // draws little dots on the bottom of the screen - if (devparm) - { - i = I_GetTime(); - tics = i - lasttic; - lasttic = i; - if (tics > 20) tics = 20; + //lcd_vsync = false; - for (i=0 ; i 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 (int i=0; i<256; ++i ) { + //for (i = 0; i < 256; i++) + //{ + // c = (col_t*)palette; + + // rgb565_palette[i] = GFX_RGB565(gammatable[usegamma][c->r], + // gammatable[usegamma][c->g], + // gammatable[usegamma][c->b]); + + // palette += 3; + //} + + for (i=0; i<256; ++i ) { colors[i].a = 0; colors[i].r = gammatable[usegamma][*palette++]; colors[i].g = gammatable[usegamma][*palette++]; @@ -327,27 +452,76 @@ void I_SetPalette (byte* palette) ioctl(fd_fb, IOCTL_FB_PUTCMAP, colors); } -void I_InitGraphics(void) +// Given an RGB value, find the closest matching palette index. + +int I_GetPaletteIndex (int r, int g, int b) { - unsigned char * screen_pixels; + int best, best_diff, diff; + int i; + col_t color; - X_width = SCREENWIDTH; - X_height = SCREENHEIGHT; + //printf("I_GetPaletteIndex\n"); - printf("I_InitGraphics: w x h: %d x %d\n", X_width, X_height); + best = 0; + best_diff = INT_MAX; - /* Open fbdev file descriptor */ - fd_fb = open("/dev/fb0", O_RDWR); - if (fd_fb < 0) + for (i = 0; i < 256; ++i) { - printf("Could not open /dev/fb0"); - exit(-1); + color.r = GFX_RGB565_R(rgb565_palette[i]); + color.g = GFX_RGB565_G(rgb565_palette[i]); + color.b = GFX_RGB565_B(rgb565_palette[i]); + + diff = (r - color.r) * (r - color.r) + + (g - color.g) * (g - color.g) + + (b - color.b) * (b - color.b); + + if (diff < best_diff) + { + best = i; + best_diff = diff; + } + + if (diff == 0) + { + break; + } } - /* Allocate screen to draw to */ - screen_pixels = malloc(X_width * X_height); - - screens[0] = (unsigned char *)screen_pixels; + 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) +{ +} + +void I_EnableLoadingDisk(void) +{ +} + +void I_BindVideoVariables (void) +{ +} + +void I_DisplayFPSDots (boolean dots_on) +{ +} + +void I_CheckIsScreensaver (void) +{ +} diff --git a/frosted-doom/icon.c b/frosted-doom/icon.c new file mode 100644 index 0000000..14c607c --- /dev/null +++ b/frosted-doom/icon.c @@ -0,0 +1,262 @@ +static int icon_w = 32; +static int icon_h = 32; + +static unsigned char icon_data[] = { + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xa2,0x86,0x73, + 0xa9,0x8d,0x7a, 0xbd,0xa0,0x8c, 0xda,0xba,0xa0, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0xbd,0x8d,0x67, 0xd7,0xb9,0xa5, 0xeb,0xd8,0xcd, 0xd3,0xbf,0xae, + 0xbd,0xa0,0x8c, 0xeb,0xd8,0xcd, 0xc2,0x9d,0x86, 0x95,0x5d,0x38, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x9b,0x7e,0x66, + 0xc5,0x9e,0x81, 0xd3,0xb3,0x99, 0xd4,0xac,0x8e, 0xee,0xdc,0xd1, + 0xb9,0x93,0x76, 0xad,0x71,0x45, 0xd4,0xac,0x8e, 0xb9,0x93,0x76, + 0xa3,0x77,0x58, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x39,0x1d,0x2d, 0x55,0x20,0x22, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0xda,0xb4,0x9c, 0xd3,0xa3,0x83, + 0xaf,0x91,0x78, 0xa7,0x83,0x6d, 0xc4,0xa7,0x93, 0xee,0xe2,0xd5, + 0xeb,0xd8,0xcd, 0x8c,0x60,0x3d, 0x9b,0x7e,0x66, 0xce,0x9f,0x7e, + 0x84,0x54,0x33, 0xba,0x83,0x5b, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x24,0x1c,0x35, 0x00,0x0f,0x32, 0x29,0x18,0x2e, 0x55,0x20,0x22, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0xd3,0xb3,0x99, 0xca,0x93,0x6f, 0xc4,0x94,0x6e, + 0x98,0x66,0x45, 0x78,0x50,0x2d, 0xd7,0xb9,0xa5, 0xee,0xdc,0xd1, + 0xc4,0x9b,0x79, 0xa1,0x6d,0x45, 0x66,0x40,0x24, 0xb8,0x7a,0x4f, + 0xcf,0xa6,0x83, 0x98,0x6d,0x4e, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x30,0x1c,0x2f, 0x08,0x13,0x30, 0x00,0x0f,0x32, 0x00,0x0f,0x32, + 0x39,0x1d,0x2d, 0x52,0x1c,0x1a, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x9e,0x7b,0x65, 0xb9,0x89,0x64, 0xaa,0x7d,0x5e, 0x9e,0x72,0x53, + 0x88,0x5e,0x40, 0xc4,0xa7,0x93, 0xb9,0x89,0x64, 0x90,0x6c,0x51, + 0x7f,0x50,0x2f, 0x90,0x5e,0x37, 0x75,0x4d,0x30, 0x7f,0x50,0x2f, + 0xd3,0xa3,0x83, 0xd4,0xac,0x8e, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x29,0x18,0x2e, 0x08,0x13,0x30, 0x08,0x13,0x30, 0x08,0x13,0x30, + 0x00,0x0f,0x32, 0x08,0x13,0x30, 0x49,0x1e,0x2b, 0x49,0x1a,0x16, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xda,0xba,0xa0, + 0xd4,0xac,0x8e, 0xc4,0x9b,0x79, 0xaa,0x7d,0x5e, 0xaa,0x7d,0x5e, + 0xbd,0xa0,0x8c, 0x8c,0x60,0x3d, 0x70,0x49,0x2c, 0x89,0x60,0x42, + 0x57,0x38,0x20, 0x6c,0x45,0x29, 0x66,0x40,0x24, 0x51,0x35,0x21, + 0x7e,0x55,0x38, 0xce,0x9f,0x7e, 0xc2,0x8a,0x61, 0x00,0x00,0x00, + 0x30,0x1c,0x2f, 0x00,0x0f,0x32, 0x00,0x0f,0x32, 0x08,0x13,0x30, + 0x00,0x0f,0x32, 0x00,0x0f,0x32, 0x08,0x13,0x30, 0x08,0x13,0x30, + 0x59,0x25,0x2b, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xcb,0x9a,0x74, + 0xb7,0x81,0x58, 0x8c,0x60,0x3d, 0x79,0x4b,0x2b, 0x89,0x58,0x31, + 0x89,0x58,0x31, 0x7f,0x50,0x2f, 0x9e,0x64,0x39, 0x75,0x4c,0x2a, + 0x51,0x35,0x21, 0x84,0x54,0x33, 0x54,0x36,0x1d, 0x98,0x6d,0x4e, + 0xb4,0x7f,0x5c, 0xba,0x83,0x5b, 0xb8,0x7a,0x4f, 0x00,0x00,0x00, + 0x3e,0x28,0x36, 0x08,0x13,0x30, 0x00,0x0f,0x32, 0x08,0x13,0x30, + 0x00,0x0f,0x32, 0x00,0x0f,0x32, 0x00,0x0f,0x32, 0x08,0x13,0x30, + 0x20,0x1f,0x36, 0x35,0x19,0x12, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xc2,0x8a,0x61, + 0x89,0x60,0x42, 0x84,0x54,0x33, 0x7f,0x50,0x2f, 0x86,0x56,0x35, + 0x8d,0x5b,0x35, 0x75,0x4c,0x2a, 0x8d,0x5b,0x35, 0x5c,0x38,0x22, + 0x5e,0x3f,0x27, 0x75,0x4d,0x30, 0x9d,0x64,0x3f, 0x75,0x4c,0x2a, + 0x78,0x50,0x2d, 0x7f,0x50,0x2f, 0xb7,0x81,0x58, 0x00,0x00,0x00, + 0x46,0x35,0x42, 0x04,0x18,0x3a, 0x08,0x13,0x30, 0x5d,0x30,0x28, + 0x20,0x1f,0x36, 0x08,0x13,0x30, 0x08,0x13,0x30, 0x04,0x18,0x3a, + 0x19,0x1c,0x37, 0x3a,0x1d,0x16, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x91,0x5f,0x3e, + 0x84,0x54,0x33, 0x89,0x58,0x31, 0x7e,0x6e,0x64, 0xc4,0x94,0x6e, + 0x78,0x50,0x2d, 0x92,0x6f,0x59, 0xa1,0x7c,0x60, 0x9c,0x6f,0x4b, + 0x8d,0x5b,0x35, 0xbc,0x7f,0x53, 0xad,0x71,0x45, 0x75,0x4d,0x30, + 0x51,0x35,0x21, 0x4b,0x2f,0x1c, 0x70,0x49,0x2c, 0x00,0x00,0x00, + 0x59,0x44,0x4d, 0x1e,0x28,0x42, 0x1e,0x28,0x42, 0x48,0x19,0x10, + 0x42,0x19,0x12, 0x53,0x2b,0x30, 0x0c,0x26,0x48, 0x1e,0x28,0x42, + 0x24,0x2d,0x48, 0x5f,0x2c,0x1d, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x89,0x58,0x31, + 0xa1,0x84,0x6c, 0xc4,0x94,0x6e, 0x88,0x64,0x44, 0xb5,0x8f,0x73, + 0x9e,0x72,0x53, 0xa1,0x6d,0x45, 0x93,0x60,0x3a, 0xad,0x71,0x45, + 0xb4,0x7f,0x5c, 0xbd,0x8d,0x67, 0xc2,0x8a,0x61, 0xb3,0x76,0x4b, + 0xb8,0x7a,0x4f, 0x88,0x64,0x44, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x61,0x50,0x52, 0x1c,0x34,0x52, 0x1c,0x34,0x52, 0x54,0x27,0x16, + 0x29,0x17,0x09, 0x5d,0x30,0x28, 0x1c,0x34,0x52, 0x1c,0x34,0x52, + 0x24,0x35,0x4f, 0x69,0x34,0x24, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xa7,0x83,0x6d, + 0xac,0x86,0x6a, 0x74,0x47,0x2d, 0x84,0x54,0x33, 0x5c,0x38,0x22, + 0x54,0x36,0x1d, 0x6c,0x45,0x29, 0x96,0x63,0x3c, 0xa3,0x6e,0x41, + 0xb3,0x76,0x4b, 0xb3,0x76,0x4b, 0xa2,0x68,0x3d, 0x7c,0x4e,0x2d, + 0x63,0x3e,0x27, 0x96,0x63,0x3c, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x6b,0x5d,0x59, 0x22,0x42,0x5f, 0x22,0x42,0x5f, 0x5d,0x34,0x1a, + 0x38,0x23,0x0f, 0x5c,0x38,0x22, 0x22,0x42,0x5f, 0x22,0x42,0x5f, + 0x2c,0x45,0x5e, 0x6f,0x3e,0x2b, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb7,0x81,0x58, + 0x98,0x74,0x59, 0x6c,0x45,0x29, 0x4b,0x35,0x25, 0x78,0x50,0x2d, + 0x78,0x50,0x2d, 0x78,0x50,0x2d, 0x7f,0x50,0x2f, 0x84,0x54,0x33, + 0x8d,0x5b,0x35, 0x96,0x63,0x3c, 0x74,0x47,0x2d, 0x65,0x45,0x26, + 0x65,0x45,0x26, 0x7c,0x4e,0x2d, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x77,0x69,0x64, 0x30,0x4e,0x6d, 0x32,0x52,0x6b, 0x69,0x42,0x26, + 0x49,0x31,0x11, 0x6c,0x47,0x2f, 0x27,0x4f,0x6d, 0x27,0x4f,0x6d, + 0x32,0x52,0x6b, 0x70,0x49,0x2c, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb7,0x81,0x58, + 0x8a,0x5a,0x39, 0x8a,0x5a,0x39, 0x91,0x5f,0x3e, 0x5e,0x3f,0x27, + 0x5c,0x38,0x22, 0x89,0x58,0x31, 0x89,0x58,0x31, 0x95,0x5d,0x38, + 0x9d,0x64,0x3f, 0x65,0x45,0x26, 0x4b,0x2f,0x1c, 0x7f,0x50,0x2f, + 0x78,0x50,0x2d, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x77,0x69,0x64, 0x36,0x5c,0x7a, 0x3e,0x5e,0x78, 0x76,0x52,0x2e, + 0x5d,0x42,0x22, 0x75,0x4d,0x30, 0x36,0x5c,0x7a, 0x36,0x5c,0x7a, + 0x3e,0x5e,0x78, 0x74,0x47,0x2d, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x89,0x58,0x31, 0x63,0x3e,0x27, 0xa8,0x6d,0x42, 0x4b,0x2f,0x1c, + 0x65,0x45,0x26, 0x70,0x49,0x2c, 0x51,0x35,0x21, 0x78,0x50,0x2d, + 0x42,0x30,0x14, 0x49,0x31,0x11, 0x59,0x44,0x22, 0x7c,0x5c,0x2a, + 0x8a,0x71,0x27, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x71,0x67,0x5c, 0x37,0x52,0x66, 0x3f,0x55,0x64, 0x80,0x55,0x27, + 0x64,0x4c,0x1f, 0x7e,0x59,0x2e, 0x37,0x52,0x66, 0x37,0x52,0x66, + 0x3f,0x55,0x64, 0x6c,0x47,0x2f, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x70,0x49,0x2c, 0x65,0x45,0x26, 0x65,0x45,0x26, 0x63,0x3e,0x27, + 0x76,0x4d,0x25, 0x5d,0x42,0x22, 0x5e,0x3f,0x27, 0x4e,0x43,0x18, + 0x4e,0x43,0x18, 0x6a,0x5b,0x1c, 0x4e,0x43,0x18, 0x5f,0x51,0x19, + 0x8a,0x76,0x2a, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x63,0x38,0x19, 0x34,0x11,0x04, 0x32,0x0f,0x00, 0x86,0x58,0x1e, + 0x74,0x59,0x25, 0x86,0x58,0x1e, 0x34,0x15,0x00, 0x32,0x0f,0x00, + 0x34,0x15,0x00, 0x4e,0x31,0x18, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x7e,0x6c,0x27, 0x5a,0x4d,0x1c, + 0x4d,0x3e,0x15, 0x67,0x58,0x21, 0x5a,0x4d,0x1c, 0x57,0x4b,0x1a, + 0x5f,0x51,0x19, 0x64,0x55,0x1e, 0x5a,0x4d,0x1c, 0x8a,0x71,0x27, + 0x8e,0x79,0x26, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x63,0x38,0x19, 0x34,0x11,0x04, 0x32,0x0f,0x00, 0x8d,0x63,0x1f, + 0x83,0x66,0x2c, 0x8d,0x63,0x1f, 0x32,0x0f,0x00, 0x35,0x19,0x12, + 0x34,0x11,0x04, 0x53,0x3a,0x20, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0xac,0x93,0x39, 0x76,0x65,0x20, + 0x6a,0x5b,0x1c, 0x6a,0x5b,0x1c, 0x67,0x58,0x21, 0x4e,0x43,0x18, + 0x4e,0x43,0x18, 0x9b,0x85,0x32, 0xb8,0x9e,0x3c, 0xb1,0x8d,0x36, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x63,0x38,0x19, 0x34,0x15,0x00, 0x32,0x0f,0x00, 0x8d,0x63,0x1f, + 0x83,0x66,0x2c, 0x8d,0x63,0x1f, 0x32,0x0f,0x00, 0x32,0x0f,0x00, + 0x34,0x15,0x00, 0x53,0x3a,0x20, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb0,0x96,0x34, 0x76,0x65,0x20, + 0x7e,0x66,0x23, 0x8e,0x79,0x26, 0x8a,0x71,0x27, 0x7e,0x6c,0x27, + 0x8a,0x71,0x27, 0x8a,0x71,0x27, 0xb0,0x96,0x34, 0x98,0x82,0x2f, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x75,0x4c,0x2a, 0x38,0x19,0x05, 0x38,0x19,0x05, 0x99,0x6d,0x22, + 0x96,0x70,0x2a, 0x99,0x6d,0x22, 0x38,0x19,0x05, 0x38,0x19,0x05, + 0x38,0x19,0x05, 0x59,0x3f,0x25, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0xac,0x93,0x39, 0x8a,0x76,0x2a, + 0x7e,0x66,0x23, 0x76,0x65,0x20, 0x93,0x7d,0x2a, 0x82,0x6f,0x23, + 0x9f,0x88,0x35, 0xb8,0xa0,0x4c, 0xb8,0xa0,0x4c, 0xc4,0xa8,0x3f, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x7c,0x5c,0x2a, 0x52,0x2e,0x0d, 0x52,0x2e,0x0d, 0xa4,0x7b,0x27, + 0xa1,0x80,0x37, 0x9f,0x77,0x1a, 0x52,0x2e,0x0d, 0x52,0x2e,0x0d, + 0x52,0x2e,0x0d, 0x5f,0x4e,0x2a, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x86,0x72,0x26, + 0xac,0x93,0x39, 0x97,0x82,0x36, 0xb1,0x8d,0x36, 0xac,0x93,0x39, + 0x97,0x82,0x36, 0xa4,0x8c,0x32, 0xbd,0xa2,0x41, 0x8a,0x71,0x27, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x8b,0x6d,0x32, 0x66,0x44,0x14, 0x6d,0x4a,0x20, 0xab,0x86,0x29, + 0xb1,0x8d,0x36, 0xa4,0x7b,0x27, 0x66,0x44,0x14, 0x66,0x44,0x14, + 0x66,0x44,0x14, 0x69,0x56,0x2c, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xac,0x93,0x31, + 0x7e,0x6c,0x27, 0x9f,0x88,0x35, 0x97,0x82,0x36, 0x7e,0x66,0x23, + 0x7e,0x66,0x23, 0xb2,0x99,0x3f, 0xbd,0xa2,0x41, 0x8a,0x76,0x2a, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x99,0x7a,0x38, 0x86,0x58,0x1e, 0x7f,0x59,0x22, 0xb2,0x8b,0x1c, + 0x94,0x6e,0x21, 0x7f,0x59,0x22, 0x7f,0x59,0x22, 0x7f,0x59,0x22, + 0x7f,0x59,0x22, 0x69,0x56,0x2c, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xac,0x93,0x39, + 0x8a,0x71,0x27, 0xb4,0x9c,0x48, 0x7e,0x66,0x23, 0xac,0x93,0x39, + 0x9c,0x87,0x3a, 0x9c,0x87,0x3a, 0xbd,0xa2,0x41, 0x8e,0x79,0x26, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0xa8,0x86,0x3d, 0x96,0x70,0x2a, 0x96,0x70,0x2a, 0x96,0x70,0x2a, + 0x96,0x70,0x2a, 0x96,0x70,0x2a, 0x96,0x70,0x2a, 0x96,0x70,0x2a, + 0xa1,0x80,0x37, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0xb4,0x9c,0x48, + 0xac,0x93,0x31, 0x93,0x7d,0x2a, 0xbd,0xa3,0x48, 0x93,0x7d,0x2a, + 0xb8,0xa0,0x4c, 0xb4,0x9c,0x48, 0xcc,0xa5,0x4e, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0xa8,0x86,0x3d, 0xaf,0x85,0x31, 0xaf,0x85,0x31, 0xaf,0x85,0x31, + 0xaf,0x85,0x31, 0xaf,0x85,0x31, 0xaf,0x85,0x31, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x97,0x82,0x36, 0xb4,0x9c,0x48, 0xb2,0x99,0x3f, 0xb4,0x9c,0x48, + 0xb0,0x96,0x34, 0xc1,0xa7,0x4c, 0x9b,0x84,0x2a, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0xbd,0x9e,0x4c, 0xc7,0x9a,0x3f, 0xc7,0x9a,0x3f, 0xc7,0x9a,0x3f, + 0xc7,0x9a,0x3f, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x9b,0x85,0x32, 0xa7,0x8e,0x2c, 0xac,0x93,0x39, 0xb5,0x91,0x41, + 0x76,0x65,0x20, 0xa7,0x8e,0x2c, 0xb4,0x9a,0x38, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0xcc,0xa5,0x4e, 0xe0,0xaf,0x45, 0xe0,0xaf,0x45, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0xa4,0x8c,0x32, 0xb8,0x9e,0x44, 0x86,0x72,0x26, 0x9f,0x88,0x35, + 0xbd,0xa3,0x48, 0x9b,0x85,0x32, 0xa3,0x81,0x32, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0xd1,0xae,0x4e, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0xb0,0x97,0x3c, 0xb4,0x9a,0x38, 0xac,0x94,0x41, 0xb2,0x99,0x3f, + 0xb4,0x9a,0x38, 0xb8,0x9e,0x3c, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0xcc,0xa5,0x4e, 0xa6,0x8f,0x3c, 0xb2,0x99,0x3f, 0xb4,0x9c,0x48, + 0xa8,0x90,0x36, 0x9f,0x88,0x35, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + +}; diff --git a/frosted-doom/info.c b/frosted-doom/info.c index 72a7362..9389e84 100644 --- a/frosted-doom/info.c +++ b/frosted-doom/info.c @@ -1,38 +1,30 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Thing frame/state LUT, // generated by multigen utilitiy. // This one is the original DOOM version, preserved. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: info.c,v 1.3 1997/01/26 07:45:00 b1 Exp $"; +#include +#include // Data. #include "sounds.h" #include "m_fixed.h" -#ifdef __GNUG__ -#pragma implementation "info.h" -#endif #include "info.h" #include "p_mobj.h" @@ -51,7 +43,7 @@ char *sprnames[] = { "POL3","POL1","POL6","GOR2","GOR3","GOR4","GOR5","SMIT","COL1","COL2", "COL3","COL4","CAND","CBRA","COL6","TRE1","TRE2","ELEC","CEYE","FSKU", "COL5","TBLU","TGRN","TRED","SMBT","SMGT","SMRT","HDB1","HDB2","HDB3", - "HDB4","HDB5","HDB6","POB1","POB2","BRS1","TLMP","TLP2",NULL,"DUMM" + "HDB4","HDB5","HDB6","POB1","POB2","BRS1","TLMP","TLP2", NULL }; diff --git a/frosted-doom/info.h b/frosted-doom/info.h index cc35e33..648b518 100644 --- a/frosted-doom/info.h +++ b/frosted-doom/info.h @@ -1,25 +1,22 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Thing frame/state LUT, // generated by multigen utilitiy. // This one is the original DOOM version, preserved. // -//----------------------------------------------------------------------------- #ifndef __INFO__ #define __INFO__ @@ -1146,20 +1143,19 @@ typedef enum typedef struct { - spritenum_t sprite; - long frame; - long tics; - // void (*action) (); - actionf_t action; - statenum_t nextstate; - long misc1, misc2; + spritenum_t sprite; + int frame; + int tics; + // void (*action) (); + actionf_t action; + statenum_t nextstate; + int misc1; + int misc2; } state_t; extern state_t states[NUMSTATES]; extern char *sprnames[]; - - typedef enum { MT_PLAYER, MT_POSSESSED, @@ -1333,8 +1329,3 @@ typedef struct extern mobjinfo_t mobjinfo[NUMMOBJTYPES]; #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/m_argv.c b/frosted-doom/m_argv.c index 1595671..1582450 100644 --- a/frosted-doom/m_argv.c +++ b/frosted-doom/m_argv.c @@ -1,31 +1,31 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // -//----------------------------------------------------------------------------- - -static const char -rcsid[] = "$Id: m_argv.c,v 1.1 1997/02/03 22:45:10 b1 Exp $"; +#include +#include +#include #include +#include "doomtype.h" +#include "i_system.h" +#include "m_misc.h" +#include "m_argv.h" // haleyjd 20110212: warning fix + int myargc; char** myargv; @@ -38,19 +38,228 @@ char** myargv; // in the program's command line arguments. // Returns the argument number (1 to argc-1) // or 0 if not present -int M_CheckParm (char *check) -{ - int i; +// - for (i = 1;i= 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 +#include #include "m_fixed.h" @@ -48,8 +45,3 @@ M_AddToBox #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/m_cheat.c b/frosted-doom/m_cheat.c index e5d4284..1565f9e 100644 --- a/frosted-doom/m_cheat.c +++ b/frosted-doom/m_cheat.c @@ -1,40 +1,32 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Cheat sequence checking. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: m_cheat.c,v 1.1 1997/02/03 21:24:34 b1 Exp $"; +#include + +#include "doomtype.h" #include "m_cheat.h" // // CHEAT SEQUENCE PACKAGE // -static int firsttime = 1; -static unsigned char cheat_xlate_table[256]; - - // // Called in st_stuff module, which handles the input. // Returns a 1 if the cheat was successful, 0 if failed. @@ -44,34 +36,46 @@ cht_CheckCheat ( cheatseq_t* cht, char key ) { - int i; - int rc = 0; + // if we make a short sequence on a cheat with parameters, this + // will not work in vanilla doom. behave the same. - if (firsttime) + if (cht->parameter_chars > 0 && strlen(cht->sequence) < cht->sequence_len) + return false; + + if (cht->chars_read < strlen(cht->sequence)) { - firsttime = 0; - for (i=0;i<256;i++) cheat_xlate_table[i] = SCRAMBLE(i); + // still reading characters from the cheat code + // and verifying. reset back to the beginning + // if a key is wrong + + if (key == cht->sequence[cht->chars_read]) + ++cht->chars_read; + else + cht->chars_read = 0; + + cht->param_chars_read = 0; + } + else if (cht->param_chars_read < cht->parameter_chars) + { + // we have passed the end of the cheat sequence and are + // entering parameters now + + cht->parameter_buf[cht->param_chars_read] = key; + + ++cht->param_chars_read; } - if (!cht->p) - cht->p = cht->sequence; // initialize if first time - - if (*cht->p == 0) - *(cht->p++) = key; - else if - (cheat_xlate_table[(unsigned char)key] == *cht->p) cht->p++; - else - cht->p = cht->sequence; - - if (*cht->p == 1) - cht->p++; - else if (*cht->p == 0xff) // end of sequence character + if (cht->chars_read >= strlen(cht->sequence) + && cht->param_chars_read >= cht->parameter_chars) { - cht->p = cht->sequence; - rc = 1; - } + cht->chars_read = cht->param_chars_read = 0; - return rc; + return true; + } + + // cheat not matched yet + + return false; } void @@ -79,23 +83,7 @@ cht_GetParam ( cheatseq_t* cht, char* buffer ) { - - unsigned char *p, c; - - p = cht->sequence; - while (*(p++) != 1); - - do - { - c = *p; - *(buffer++) = c; - *(p++) = 0; - } - while (c && *p!=0xff ); - - if (*p==0xff) - *buffer = 0; - + memcpy(buffer, cht->parameter_buf, cht->parameter_chars); } diff --git a/frosted-doom/m_cheat.h b/frosted-doom/m_cheat.h index 3646368..6775e70 100644 --- a/frosted-doom/m_cheat.h +++ b/frosted-doom/m_cheat.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Cheat code checking. // -//----------------------------------------------------------------------------- #ifndef __M_CHEAT__ @@ -27,15 +24,27 @@ // CHEAT SEQUENCE PACKAGE // -#define SCRAMBLE(a) \ -((((a)&1)<<7) + (((a)&2)<<5) + ((a)&4) + (((a)&8)<<1) \ - + (((a)&16)>>1) + ((a)&32) + (((a)&64)>>5) + (((a)&128)>>7)) +// declaring a cheat + +#define CHEAT(value, parameters) \ + { value, sizeof(value) - 1, parameters, 0, 0, "" } + +#define MAX_CHEAT_LEN 25 +#define MAX_CHEAT_PARAMS 5 typedef struct { - unsigned char* sequence; - unsigned char* p; - + // settings for this cheat + + char sequence[MAX_CHEAT_LEN]; + size_t sequence_len; + int parameter_chars; + + // state used during the game + + size_t chars_read; + int param_chars_read; + char parameter_buf[MAX_CHEAT_PARAMS]; } cheatseq_t; int @@ -51,8 +60,3 @@ cht_GetParam #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/m_config.c b/frosted-doom/m_config.c new file mode 100644 index 0000000..31ac7a6 --- /dev/null +++ b/frosted-doom/m_config.c @@ -0,0 +1,2150 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 1993-2008 Raven Software +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Configuration file interface. +// + + +#include +#include +#include +#include +#include + +#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; inumdefaults; ++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 ; inumdefaults ; 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 + // @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 + // + // Load additional configuration from the specified file, instead of + // the default. + // + + i = M_CheckParmWithArgs("-extraconfig", 1); + + if (i) + { + extra_defaults.filename = myargv[i+1]; + printf(" extra configuration file: %s\n", + extra_defaults.filename); + } + else + { + extra_defaults.filename + = M_StringJoin(configdir, default_extra_config, NULL); + } + + LoadDefaultCollection(&doom_defaults); + LoadDefaultCollection(&extra_defaults); +} + +// Get a configuration file variable by its name + +static default_t *GetDefaultForName(char *name) +{ + default_t *result; + + // Try the main list and the extras + + result = SearchCollection(&doom_defaults, name); + + if (result == NULL) + { + result = SearchCollection(&extra_defaults, name); + } + + // Not found? Internal error. + + if (result == NULL) + { + I_Error("Unknown configuration variable: '%s'", name); + } + + return result; +} + +// +// Bind a variable to a given configuration file variable, by name. +// + +void M_BindVariable(char *name, void *location) +{ + default_t *variable; + + variable = GetDefaultForName(name); + + variable->location = location; + variable->bound = true; +} + +// Set the value of a particular variable; an API function for other +// parts of the program to assign values to config variables by name. + +boolean M_SetVariable(char *name, char *value) +{ + default_t *variable; + + variable = GetDefaultForName(name); + + if (variable == NULL || !variable->bound) + { + return false; + } + + SetVariable(variable, value); + + return true; +} + +// Get the value of a variable. + +int M_GetIntVariable(char *name) +{ + default_t *variable; + + variable = GetDefaultForName(name); + + if (variable == NULL || !variable->bound + || (variable->type != DEFAULT_INT && variable->type != DEFAULT_INT_HEX)) + { + return 0; + } + + return *((int *) variable->location); +} + +const char *M_GetStrVariable(char *name) +{ + default_t *variable; + + variable = GetDefaultForName(name); + + if (variable == NULL || !variable->bound + || variable->type != DEFAULT_STRING) + { + return NULL; + } + + return *((const char **) variable->location); +} + +float M_GetFloatVariable(char *name) +{ + default_t *variable; + + variable = GetDefaultForName(name); + + if (variable == NULL || !variable->bound + || variable->type != DEFAULT_FLOAT) + { + return 0; + } + + return *((float *) variable->location); +} + +// Get the path to the default configuration dir to use, if NULL +// is passed to M_SetConfigDir. + +static char *GetDefaultConfigDir(void) +{ +#if !defined(_WIN32) || defined(_WIN32_WCE) + + // Configuration settings are stored in ~/.chocolate-doom/, + // except on Windows, where we behave like Vanilla Doom and + // save in the current directory. + + char *homedir; + char *result; + + // frosted HACK - homedir = getenv("HOME"); + homedir = "/mnt"; + + if (homedir != NULL) + { + // put all configuration in a config directory off the + // homedir + + result = M_StringJoin(homedir, DIR_SEPARATOR_S, + "." PACKAGE_TARNAME, DIR_SEPARATOR_S, NULL); + + return result; + } + else +#endif /* #ifndef _WIN32 */ + { + return strdup(FILES_DIR"/"); + } +} + +// +// SetConfigDir: +// +// Sets the location of the configuration directory, where configuration +// files are stored - default.cfg, chocolate-doom.cfg, savegames, etc. +// + +void M_SetConfigDir(char *dir) +{ + // Use the directory that was passed, or find the default. + + if (dir != NULL) + { + configdir = dir; + } + else + { + configdir = GetDefaultConfigDir(); + } + + if (strcmp(configdir, "") != 0) + { + printf("Using %s for configuration and saves\n", configdir); + } + + // Make the directory if it doesn't already exist: + + M_MakeDirectory(configdir); +} + +// +// Calculate the path to the directory to use to store save games. +// Creates the directory as necessary. +// + +char *M_GetSaveGameDir(char *iwadname) +{ + char *savegamedir; +#if ORIGCODE + char *topdir; +#endif + + // If not "doing" a configuration directory (Windows), don't "do" + // a savegame directory, either. + + if (!strcmp(configdir, "")) + { + savegamedir = strdup(""); + } + else + { +#if ORIGCODE + // ~/.chocolate-doom/savegames + + topdir = M_StringJoin(configdir, "savegame", NULL); + M_MakeDirectory(topdir); + + // eg. ~/.chocolate-doom/savegames/doom2.wad/ + + savegamedir = M_StringJoin(topdir, DIR_SEPARATOR_S, iwadname, + DIR_SEPARATOR_S, NULL); + + M_MakeDirectory(savegamedir); + + free(topdir); +#else + savegamedir = M_StringJoin(configdir, "savegame/", NULL); + + M_MakeDirectory(savegamedir); + + printf ("Using %s for savegames\n", savegamedir); +#endif + } + + return savegamedir; +} + diff --git a/frosted-doom/m_config.h b/frosted-doom/m_config.h new file mode 100644 index 0000000..a17de2b --- /dev/null +++ b/frosted-doom/m_config.h @@ -0,0 +1,39 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Configuration file interface. +// + + +#ifndef __M_CONFIG__ +#define __M_CONFIG__ + +#include "doomtype.h" + +void M_LoadDefaults(void); +void M_SaveDefaults(void); +void M_SaveDefaultsAlternate(char *main, char *extra); +void M_SetConfigDir(char *dir); +void M_BindVariable(char *name, void *variable); +boolean M_SetVariable(char *name, char *value); +int M_GetIntVariable(char *name); +const char *M_GetStrVariable(char *name); +float M_GetFloatVariable(char *name); +void M_SetConfigFilenames(char *main_config, char *extra_config); +char *M_GetSaveGameDir(char *iwadname); + +extern char *configdir; + +#endif diff --git a/frosted-doom/m_controls.c b/frosted-doom/m_controls.c new file mode 100644 index 0000000..f0ffa01 --- /dev/null +++ b/frosted-doom/m_controls.c @@ -0,0 +1,398 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 1993-2008 Raven Software +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// + +#include + +#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> FRACBITS; + return ((int64_t) a * (int64_t) b) >> FRACBITS; } @@ -54,34 +44,19 @@ FixedMul // FixedDiv, C version. // -fixed_t -FixedDiv -( fixed_t a, - fixed_t b ) +fixed_t FixedDiv(fixed_t a, fixed_t b) { - if ( (abs(a)>>14) >= abs(b)) - return (a^b)<0 ? MININT : MAXINT; - return FixedDiv2 (a,b); + if ((abs(a) >> 14) >= abs(b)) + { + return (a^b) < 0 ? INT_MIN : INT_MAX; + } + else + { + int64_t result; + + result = ((int64_t) a << 16) / b; + + return (fixed_t) result; + } } - - -fixed_t -FixedDiv2 -( fixed_t a, - fixed_t b ) -{ -#if 0 - long long c; - c = ((long long)a<<16) / ((long long)b); - return (fixed_t) c; -#endif - - double c; - - c = ((double)a) / ((double)b) * FRACUNIT; - - if (c >= 2147483648.0 || c < -2147483648.0) - I_Error("FixedDiv: divide by zero"); - return (fixed_t) c; -} diff --git a/frosted-doom/m_fixed.h b/frosted-doom/m_fixed.h index 7cd7c66..733b290 100644 --- a/frosted-doom/m_fixed.h +++ b/frosted-doom/m_fixed.h @@ -1,32 +1,26 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Fixed point arithemtics, implementation. // -//----------------------------------------------------------------------------- #ifndef __M_FIXED__ #define __M_FIXED__ -#ifdef __GNUG__ -#pragma interface -#endif // @@ -39,13 +33,7 @@ typedef int fixed_t; fixed_t FixedMul (fixed_t a, fixed_t b); fixed_t FixedDiv (fixed_t a, fixed_t b); -fixed_t FixedDiv2 (fixed_t a, fixed_t b); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/m_menu.c b/frosted-doom/m_menu.c index 6055d47..5347522 100644 --- a/frosted-doom/m_menu.c +++ b/frosted-doom/m_menu.c @@ -1,48 +1,42 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // DOOM selection menu, options, episode etc. // Sliders and icons. Kinda widget stuff. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: m_menu.c,v 1.7 1997/02/03 22:45:10 b1 Exp $"; -#include -#include -#include -#include #include #include #include "doomdef.h" +#include "doomkeys.h" #include "dstrings.h" #include "d_main.h" +#include "deh_main.h" +#include "i_swap.h" #include "i_system.h" +#include "i_timer.h" #include "i_video.h" -#include "z_zone.h" +#include "m_misc.h" #include "v_video.h" #include "w_wad.h" +#include "z_zone.h" #include "r_local.h" @@ -52,7 +46,8 @@ rcsid[] = "$Id: m_menu.c,v 1.7 1997/02/03 22:45:10 b1 Exp $"; #include "g_game.h" #include "m_argv.h" -#include "m_swap.h" +#include "m_controls.h" +#include "p_saveg.h" #include "s_sound.h" @@ -64,7 +59,6 @@ rcsid[] = "$Id: m_menu.c,v 1.7 1997/02/03 22:45:10 b1 Exp $"; #include "m_menu.h" - extern patch_t* hu_font[HU_FONTSIZE]; extern boolean message_dontfuckwithme; @@ -73,39 +67,37 @@ extern boolean chat_on; // in heads-up code // // defaulted values // -int mouseSensitivity; // has default +int mouseSensitivity = 5; // Show messages has default, 0 = off, 1 = on -int showMessages; +int showMessages = 1; // Blocky mode, has default, 0 = high, 1 = normal -int detailLevel; -int screenblocks; // has default +int detailLevel = 0; +int screenblocks = 9; // temp for screenblocks (0-9) -int screenSize; +int screenSize; // -1 = no quicksave slot picked! -int quickSaveSlot; +int quickSaveSlot; // 1 = message to be printed int messageToPrint; // ...and here is the message string! -char* messageString; +char* messageString; // message x & y -int messx; +int messx; int messy; int messageLastMenuActive; // timed message = no input from user -boolean messageNeedsInput; +boolean messageNeedsInput; void (*messageRoutine)(int response); -#define SAVESTRINGSIZE 24 - char gammamsg[5][26] = { GAMMALVL0, @@ -133,6 +125,7 @@ char savegamestrings[10][SAVESTRINGSIZE]; char endstring[160]; +//static boolean opldev; // // MENU TYPEDEFS @@ -172,7 +165,7 @@ short whichSkull; // which skull to draw // graphic name of skulls // warning: initializer-string for array of chars is too long -char skullName[2][/*8*/9] = {"M_SKULL1","M_SKULL2"}; +char *skullName[2] = {"M_SKULL1","M_SKULL2"}; // current menudef menu_t* currentMenu; @@ -225,7 +218,6 @@ void M_DrawSelCell(menu_t *menu,int item); void M_WriteText(int x, int y, char *string); int M_StringWidth(char *string); int M_StringHeight(char *string); -void M_StartControlPanel(void); void M_StartMessage(char *string,void *routine,boolean input); void M_StopMessage(void); void M_ClearMenus (void); @@ -355,9 +347,9 @@ menuitem_t OptionsMenu[]= {1,"M_MESSG", M_ChangeMessages,'m'}, {1,"M_DETAIL", M_ChangeDetail,'g'}, {2,"M_SCRNSZ", M_SizeDisplay,'s'}, - {-1,"",0}, + {-1,"",0,'\0'}, {2,"M_MSENS", M_ChangeSensitivity,'m'}, - {-1,"",0}, + {-1,"",0,'\0'}, {1,"M_SVOL", M_Sound,'s'} }; @@ -431,9 +423,9 @@ enum menuitem_t SoundMenu[]= { {2,"M_SFXVOL",M_SfxVol,'s'}, - {-1,"",0}, + {-1,"",0,'\0'}, {2,"M_MUSVOL",M_MusicVol,'m'}, - {-1,"",0} + {-1,"",0,'\0'} }; menu_t SoundDef = @@ -510,28 +502,23 @@ menu_t SaveDef = // void M_ReadSaveStrings(void) { - int handle; - //int count; - int i; + FILE *handle; + int i; char name[256]; - + for (i = 0;i < load_end;i++) { - if (M_CheckParm("-cdrom")) - sprintf(name,"c:\\doomdata\\"SAVEGAMENAME"%d.dsg",i); - else - sprintf(name,SAVEGAMENAME"%d.dsg",i); + M_StringCopy(name, P_SaveGameFile(i), sizeof(name)); - 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); + handle = fopen(name, "rb"); + if (handle == NULL) + { + M_StringCopy(savegamestrings[i], EMPTYSTRING, SAVESTRINGSIZE); + LoadMenu[i].status = 0; + continue; + } + fread(&savegamestrings[i], 1, SAVESTRINGSIZE, handle); + fclose(handle); LoadMenu[i].status = 1; } } @@ -544,7 +531,9 @@ void M_DrawLoad(void) { int i; - V_DrawPatchDirect (72,28,0,W_CacheLumpName("M_LOADG",PU_CACHE)); + V_DrawPatchDirect(72, 28, + W_CacheLumpName(DEH_String("M_LOADG"), PU_CACHE)); + for (i = 0;i < load_end; i++) { M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); @@ -561,15 +550,18 @@ void M_DrawSaveLoadBorder(int x,int y) { int i; - V_DrawPatchDirect (x-8,y+7,0,W_CacheLumpName("M_LSLEFT",PU_CACHE)); + V_DrawPatchDirect(x - 8, y + 7, + W_CacheLumpName(DEH_String("M_LSLEFT"), PU_CACHE)); for (i = 0;i < 24;i++) { - V_DrawPatchDirect (x,y+7,0,W_CacheLumpName("M_LSCNTR",PU_CACHE)); + V_DrawPatchDirect(x, y + 7, + W_CacheLumpName(DEH_String("M_LSCNTR"), PU_CACHE)); x += 8; } - V_DrawPatchDirect (x,y+7,0,W_CacheLumpName("M_LSRGHT",PU_CACHE)); + V_DrawPatchDirect(x, y + 7, + W_CacheLumpName(DEH_String("M_LSRGHT"), PU_CACHE)); } @@ -581,10 +573,8 @@ void M_LoadSelect(int choice) { char name[256]; - if (M_CheckParm("-cdrom")) - sprintf(name,"c:\\doomdata\\"SAVEGAMENAME"%d.dsg",choice); - else - sprintf(name,SAVEGAMENAME"%d.dsg",choice); + M_StringCopy(name, P_SaveGameFile(choice), sizeof(name)); + G_LoadGame (name); M_ClearMenus (); } @@ -596,7 +586,7 @@ void M_LoadGame (int choice) { if (netgame) { - M_StartMessage(LOADNET,NULL,false); + M_StartMessage(DEH_String(LOADNET),NULL,false); return; } @@ -612,7 +602,7 @@ void M_DrawSave(void) { int i; - V_DrawPatchDirect (72,28,0,W_CacheLumpName("M_SAVEG",PU_CACHE)); + V_DrawPatchDirect(72, 28, W_CacheLumpName(DEH_String("M_SAVEG"), PU_CACHE)); for (i = 0;i < load_end; i++) { M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); @@ -648,8 +638,8 @@ void M_SaveSelect(int choice) saveStringEnter = 1; saveSlot = choice; - strcpy(saveOldString,savegamestrings[choice]); - if (!strcmp(savegamestrings[choice],EMPTYSTRING)) + M_StringCopy(saveOldString,savegamestrings[choice], SAVESTRINGSIZE); + if (!strcmp(savegamestrings[choice], EMPTYSTRING)) savegamestrings[choice][0] = 0; saveCharIndex = strlen(savegamestrings[choice]); } @@ -661,7 +651,7 @@ void M_SaveGame (int choice) { if (!usergame) { - M_StartMessage(SAVEDEAD,NULL,false); + M_StartMessage(DEH_String(SAVEDEAD),NULL,false); return; } @@ -679,9 +669,9 @@ void M_SaveGame (int choice) // char tempstring[80]; -void M_QuickSaveResponse(int ch) +void M_QuickSaveResponse(int key) { - if (ch == 'y') + if (key == key_menu_confirm) { M_DoSave(quickSaveSlot); S_StartSound(NULL,sfx_swtchx); @@ -707,7 +697,7 @@ void M_QuickSave(void) quickSaveSlot = -2; // means to pick a slot now return; } - sprintf(tempstring,QSPROMPT,savegamestrings[quickSaveSlot]); + DEH_snprintf(tempstring, 80, QSPROMPT, savegamestrings[quickSaveSlot]); M_StartMessage(tempstring,M_QuickSaveResponse,true); } @@ -716,9 +706,9 @@ void M_QuickSave(void) // // M_QuickLoad // -void M_QuickLoadResponse(int ch) +void M_QuickLoadResponse(int key) { - if (ch == 'y') + if (key == key_menu_confirm) { M_LoadSelect(quickSaveSlot); S_StartSound(NULL,sfx_swtchx); @@ -730,16 +720,16 @@ void M_QuickLoad(void) { if (netgame) { - M_StartMessage(QLOADNET,NULL,false); + M_StartMessage(DEH_String(QLOADNET),NULL,false); return; } if (quickSaveSlot < 0) { - M_StartMessage(QSAVESPOT,NULL,false); + M_StartMessage(DEH_String(QSAVESPOT),NULL,false); return; } - sprintf(tempstring,QLPROMPT,savegamestrings[quickSaveSlot]); + DEH_snprintf(tempstring, 80, QLPROMPT, savegamestrings[quickSaveSlot]); M_StartMessage(tempstring,M_QuickLoadResponse,true); } @@ -752,21 +742,74 @@ void M_QuickLoad(void) // void M_DrawReadThis1(void) { + char *lumpname = "CREDIT"; + int skullx = 330, skully = 175; + inhelpscreens = true; - switch ( gamemode ) + + // Different versions of Doom 1.9 work differently + + switch (gameversion) { - case commercial: - V_DrawPatchDirect (0,0,0,W_CacheLumpName("HELP",PU_CACHE)); - break; - case shareware: - case registered: - case retail: - V_DrawPatchDirect (0,0,0,W_CacheLumpName("HELP1",PU_CACHE)); - break; - default: - break; + case exe_doom_1_666: + case exe_doom_1_7: + case exe_doom_1_8: + case exe_doom_1_9: + case exe_hacx: + + if (gamemode == commercial) + { + // Doom 2 + + lumpname = "HELP"; + + skullx = 330; + skully = 165; + } + else + { + // Doom 1 + // HELP2 is the first screen shown in Doom 1 + + lumpname = "HELP2"; + + skullx = 280; + skully = 185; + } + break; + + case exe_ultimate: + case exe_chex: + + // Ultimate Doom always displays "HELP1". + + // Chex Quest version also uses "HELP1", even though it is based + // on Final Doom. + + lumpname = "HELP1"; + + break; + + case exe_final: + case exe_final2: + + // Final Doom always displays "HELP". + + lumpname = "HELP"; + + break; + + default: + I_Error("Unhandled game version"); + break; } - return; + + lumpname = DEH_String(lumpname); + + V_DrawPatchDirect (0, 0, W_CacheLumpName(lumpname, PU_CACHE)); + + ReadDef1.x = skullx; + ReadDef1.y = skully; } @@ -777,21 +820,11 @@ void M_DrawReadThis1(void) void M_DrawReadThis2(void) { inhelpscreens = true; - switch ( gamemode ) - { - case retail: - case commercial: - // This hack keeps us from having to change menus. - V_DrawPatchDirect (0,0,0,W_CacheLumpName("CREDIT",PU_CACHE)); - break; - case shareware: - case registered: - V_DrawPatchDirect (0,0,0,W_CacheLumpName("HELP2",PU_CACHE)); - break; - default: - break; - } - return; + + // We only ever draw the second page if this is + // gameversion == exe_doom_1_9 and gamemode == registered + + V_DrawPatchDirect(0, 0, W_CacheLumpName(DEH_String("HELP1"), PU_CACHE)); } @@ -800,13 +833,13 @@ void M_DrawReadThis2(void) // void M_DrawSound(void) { - V_DrawPatchDirect (60,38,0,W_CacheLumpName("M_SVOL",PU_CACHE)); + V_DrawPatchDirect (60, 38, W_CacheLumpName(DEH_String("M_SVOL"), PU_CACHE)); M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1), - 16,snd_SfxVolume); + 16,sfxVolume); M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1), - 16,snd_MusicVolume); + 16,musicVolume); } void M_Sound(int choice) @@ -819,16 +852,16 @@ void M_SfxVol(int choice) switch(choice) { case 0: - if (snd_SfxVolume) - snd_SfxVolume--; + if (sfxVolume) + sfxVolume--; break; case 1: - if (snd_SfxVolume < 15) - snd_SfxVolume++; + if (sfxVolume < 15) + sfxVolume++; break; } - S_SetSfxVolume(snd_SfxVolume /* *8 */); + S_SetSfxVolume(sfxVolume * 8); } void M_MusicVol(int choice) @@ -836,16 +869,16 @@ void M_MusicVol(int choice) switch(choice) { case 0: - if (snd_MusicVolume) - snd_MusicVolume--; + if (musicVolume) + musicVolume--; break; case 1: - if (snd_MusicVolume < 15) - snd_MusicVolume++; + if (musicVolume < 15) + musicVolume++; break; } - S_SetMusicVolume(snd_MusicVolume /* *8 */); + S_SetMusicVolume(musicVolume * 8); } @@ -856,7 +889,8 @@ void M_MusicVol(int choice) // void M_DrawMainMenu(void) { - V_DrawPatchDirect (94,2,0,W_CacheLumpName("M_DOOM",PU_CACHE)); + V_DrawPatchDirect(94, 2, + W_CacheLumpName(DEH_String("M_DOOM"), PU_CACHE)); } @@ -867,19 +901,21 @@ void M_DrawMainMenu(void) // void M_DrawNewGame(void) { - V_DrawPatchDirect (96,14,0,W_CacheLumpName("M_NEWG",PU_CACHE)); - V_DrawPatchDirect (54,38,0,W_CacheLumpName("M_SKILL",PU_CACHE)); + V_DrawPatchDirect(96, 14, W_CacheLumpName(DEH_String("M_NEWG"), PU_CACHE)); + V_DrawPatchDirect(54, 38, W_CacheLumpName(DEH_String("M_SKILL"), PU_CACHE)); } void M_NewGame(int choice) { if (netgame && !demoplayback) { - M_StartMessage(NEWGAME,NULL,false); + M_StartMessage(DEH_String(NEWGAME),NULL,false); return; } - if ( gamemode == commercial ) + // Chex Quest disabled the episode select screen, as did Doom II. + + if (gamemode == commercial || gameversion == exe_chex) M_SetupNextMenu(&NewDef); else M_SetupNextMenu(&EpiDef); @@ -893,12 +929,12 @@ int epi; void M_DrawEpisode(void) { - V_DrawPatchDirect (54,38,0,W_CacheLumpName("M_EPISOD",PU_CACHE)); + V_DrawPatchDirect(54, 38, W_CacheLumpName(DEH_String("M_EPISOD"), PU_CACHE)); } -void M_VerifyNightmare(int ch) +void M_VerifyNightmare(int key) { - if (ch != 'y') + if (key != key_menu_confirm) return; G_DeferedInitNew(nightmare,epi+1,1); @@ -909,7 +945,7 @@ void M_ChooseSkill(int choice) { if (choice == nightmare) { - M_StartMessage(NIGHTMARE,M_VerifyNightmare,true); + M_StartMessage(DEH_String(NIGHTMARE),M_VerifyNightmare,true); return; } @@ -922,7 +958,7 @@ void M_Episode(int choice) if ( (gamemode == shareware) && choice) { - M_StartMessage(SWSTRING,NULL,false); + M_StartMessage(DEH_String(SWSTRING),NULL,false); M_SetupNextMenu(&ReadDef1); return; } @@ -945,23 +981,25 @@ void M_Episode(int choice) // // M_Options // -char detailNames[2][9] = {"M_GDHIGH","M_GDLOW"}; -char msgNames[2][9] = {"M_MSGOFF","M_MSGON"}; - +static char *detailNames[2] = {"M_GDHIGH","M_GDLOW"}; +static char *msgNames[2] = {"M_MSGOFF","M_MSGON"}; void M_DrawOptions(void) { - V_DrawPatchDirect (108,15,0,W_CacheLumpName("M_OPTTTL",PU_CACHE)); + V_DrawPatchDirect(108, 15, W_CacheLumpName(DEH_String("M_OPTTTL"), + PU_CACHE)); - V_DrawPatchDirect (OptionsDef.x + 175,OptionsDef.y+LINEHEIGHT*detail,0, - W_CacheLumpName(detailNames[detailLevel],PU_CACHE)); + V_DrawPatchDirect(OptionsDef.x + 175, OptionsDef.y + LINEHEIGHT * detail, + W_CacheLumpName(DEH_String(detailNames[detailLevel]), + PU_CACHE)); - V_DrawPatchDirect (OptionsDef.x + 120,OptionsDef.y+LINEHEIGHT*messages,0, - W_CacheLumpName(msgNames[showMessages],PU_CACHE)); + V_DrawPatchDirect(OptionsDef.x + 120, OptionsDef.y + LINEHEIGHT * messages, + W_CacheLumpName(DEH_String(msgNames[showMessages]), + PU_CACHE)); + + M_DrawThermo(OptionsDef.x, OptionsDef.y + LINEHEIGHT * (mousesens + 1), + 10, mouseSensitivity); - M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(mousesens+1), - 10,mouseSensitivity); - M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1), 9,screenSize); } @@ -983,9 +1021,9 @@ void M_ChangeMessages(int choice) showMessages = 1 - showMessages; if (!showMessages) - players[consoleplayer].message = MSGOFF; + players[consoleplayer].message = DEH_String(MSGOFF); else - players[consoleplayer].message = MSGON ; + players[consoleplayer].message = DEH_String(MSGON); message_dontfuckwithme = true; } @@ -994,9 +1032,9 @@ void M_ChangeMessages(int choice) // // M_EndGame // -void M_EndGameResponse(int ch) +void M_EndGameResponse(int key) { - if (ch != 'y') + if (key != key_menu_confirm) return; currentMenu->lastOn = itemOn; @@ -1015,11 +1053,11 @@ void M_EndGame(int choice) if (netgame) { - M_StartMessage(NETEND,NULL,false); + M_StartMessage(DEH_String(NETEND),NULL,false); return; } - M_StartMessage(ENDGAME,M_EndGameResponse,true); + M_StartMessage(DEH_String(ENDGAME),M_EndGameResponse,true); } @@ -1036,8 +1074,20 @@ void M_ReadThis(int choice) void M_ReadThis2(int choice) { - choice = 0; - M_SetupNextMenu(&ReadDef2); + // Doom 1.9 had two menus when playing Doom 1 + // All others had only one + + if (gameversion <= exe_doom_1_9 && gamemode != commercial) + { + choice = 0; + M_SetupNextMenu(&ReadDef2); + } + else + { + // Close the menu + + M_FinishReadThis(0); + } } void M_FinishReadThis(int choice) @@ -1078,9 +1128,9 @@ int quitsounds2[8] = -void M_QuitResponse(int ch) +void M_QuitResponse(int key) { - if (ch != 'y') + if (key != key_menu_confirm) return; if (!netgame) { @@ -1094,18 +1144,33 @@ void M_QuitResponse(int ch) } +static char *M_SelectEndMessage(void) +{ + char **endmsg; + + if (logical_gamemission == doom) + { + // Doom 1 + + endmsg = doom1_endmsg; + } + else + { + // Doom 2 + + endmsg = doom2_endmsg; + } + + return endmsg[gametic % NUM_QUITMESSAGES]; +} void M_QuitDOOM(int choice) { - // We pick index 0 which is language sensitive, - // or one at random, between 1 and maximum number. - if (language != english ) - sprintf(endstring,"%s\n\n"DOSY, endmsg[0] ); - else - sprintf(endstring,"%s\n\n"DOSY, endmsg[ (gametic%(NUM_QUITMESSAGES-2))+1 ]); - - M_StartMessage(endstring,M_QuitResponse,true); + DEH_snprintf(endstring, sizeof(endstring), "%s\n\n" DOSY, + DEH_String(M_SelectEndMessage())); + + M_StartMessage(endstring,M_QuitResponse,true); } @@ -1134,17 +1199,12 @@ void M_ChangeDetail(int choice) choice = 0; detailLevel = 1 - detailLevel; - // FIXME - does not work. Remove anyway? - fprintf( stderr, "M_ChangeDetail: low detail mode n.a.\n"); - - return; - - /*R_SetViewSize (screenblocks, detailLevel); + R_SetViewSize (screenblocks, detailLevel); if (!detailLevel) - players[consoleplayer].message = DETAILHI; + players[consoleplayer].message = DEH_String(DETAILHI); else - players[consoleplayer].message = DETAILLO;*/ + players[consoleplayer].message = DEH_String(DETAILLO); } @@ -1191,17 +1251,17 @@ M_DrawThermo int i; xx = x; - V_DrawPatchDirect (xx,y,0,W_CacheLumpName("M_THERML",PU_CACHE)); + V_DrawPatchDirect(xx, y, W_CacheLumpName(DEH_String("M_THERML"), PU_CACHE)); xx += 8; for (i=0;ix - 10, menu->y+item*LINEHEIGHT - 1, 0, - W_CacheLumpName("M_CELL1",PU_CACHE)); + V_DrawPatchDirect(menu->x - 10, menu->y + item * LINEHEIGHT - 1, + W_CacheLumpName(DEH_String("M_CELL1"), PU_CACHE)); } void @@ -1220,8 +1280,8 @@ M_DrawSelCell ( menu_t* menu, int item ) { - V_DrawPatchDirect (menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0, - W_CacheLumpName("M_CELL2",PU_CACHE)); + V_DrawPatchDirect(menu->x - 10, menu->y + item * LINEHEIGHT - 1, + W_CacheLumpName(DEH_String("M_CELL2"), PU_CACHE)); } @@ -1241,7 +1301,6 @@ M_StartMessage } - void M_StopMessage(void) { menuactive = messageLastMenuActive; @@ -1255,7 +1314,7 @@ void M_StopMessage(void) // int M_StringWidth(char* string) { - int i; + size_t i; int w = 0; int c; @@ -1278,7 +1337,7 @@ int M_StringWidth(char* string) // int M_StringHeight(char* string) { - int i; + size_t i; int h; int height = SHORT(hu_font[0]->height); @@ -1333,12 +1392,19 @@ M_WriteText w = SHORT (hu_font[c]->width); if (cx+w > SCREENWIDTH) break; - V_DrawPatchDirect(cx, cy, 0, hu_font[c]); + V_DrawPatchDirect(cx, cy, hu_font[c]); cx+=w; } } +// These keys evaluate to a "null" key in Vanilla Doom that allows weird +// jumping in the menus. Preserve this behavior for accuracy. +static boolean IsNullKey(int key) +{ + return key == KEY_PAUSE || key == KEY_CAPSLOCK + || key == KEY_SCRLCK || key == KEY_NUMLOCK; +} // // CONTROL PANEL @@ -1350,6 +1416,7 @@ M_WriteText boolean M_Responder (event_t* ev) { int ch; + int key; int i; static int joywait = 0; static int mousewait = 0; @@ -1357,43 +1424,86 @@ boolean M_Responder (event_t* ev) static int lasty = 0; static int mousex = 0; static int lastx = 0; - - ch = -1; + + // In testcontrols mode, none of the function keys should do anything + // - the only key is escape to quit. + + if (testcontrols) + { + if (ev->type == ev_quit + || (ev->type == ev_keydown + && (ev->data1 == key_menu_activate || ev->data1 == key_menu_quit))) + { + I_Quit(); + return true; + } + + return false; + } + + // "close" button pressed on window? + if (ev->type == ev_quit) + { + // First click on close button = bring up quit confirm message. + // Second click on close button = confirm quit + + if (menuactive && messageToPrint && messageRoutine == M_QuitResponse) + { + M_QuitResponse(key_menu_confirm); + } + else + { + S_StartSound(NULL,sfx_swtchn); + M_QuitDOOM(0); + } + + return true; + } + + // key is the key pressed, ch is the actual character typed + + ch = 0; + key = -1; if (ev->type == ev_joystick && joywait < I_GetTime()) { - if (ev->data3 == -1) + if (ev->data3 < 0) { - ch = KEY_UPARROW; + key = key_menu_up; joywait = I_GetTime() + 5; } - else if (ev->data3 == 1) + else if (ev->data3 > 0) { - ch = KEY_DOWNARROW; + key = key_menu_down; joywait = I_GetTime() + 5; } - if (ev->data2 == -1) + if (ev->data2 < 0) { - ch = KEY_LEFTARROW; + key = key_menu_left; joywait = I_GetTime() + 2; } - else if (ev->data2 == 1) + else if (ev->data2 > 0) { - ch = KEY_RIGHTARROW; + key = key_menu_right; joywait = I_GetTime() + 2; } if (ev->data1&1) { - ch = KEY_ENTER; + key = key_menu_forward; joywait = I_GetTime() + 5; } if (ev->data1&2) { - ch = KEY_BACKSPACE; + key = key_menu_back; joywait = I_GetTime() + 5; } + if (joybmenu >= 0 && (ev->data1 & (1 << joybmenu)) != 0) + { + key = key_menu_activate; + joywait = I_GetTime() + 5; + } } else { @@ -1402,13 +1512,13 @@ boolean M_Responder (event_t* ev) mousey += ev->data3; if (mousey < lasty-30) { - ch = KEY_DOWNARROW; + key = key_menu_down; mousewait = I_GetTime() + 5; mousey = lasty -= 30; } else if (mousey > lasty+30) { - ch = KEY_UPARROW; + key = key_menu_up; mousewait = I_GetTime() + 5; mousey = lasty += 30; } @@ -1416,44 +1526,46 @@ boolean M_Responder (event_t* ev) mousex += ev->data2; if (mousex < lastx-30) { - ch = KEY_LEFTARROW; + key = key_menu_left; mousewait = I_GetTime() + 5; mousex = lastx -= 30; } else if (mousex > lastx+30) { - ch = KEY_RIGHTARROW; + key = key_menu_right; mousewait = I_GetTime() + 5; mousex = lastx += 30; } if (ev->data1&1) { - ch = KEY_ENTER; + key = key_menu_forward; mousewait = I_GetTime() + 15; } if (ev->data1&2) { - ch = KEY_BACKSPACE; + key = key_menu_back; mousewait = I_GetTime() + 15; } } else + { if (ev->type == ev_keydown) { - ch = ev->data1; + key = ev->data1; + ch = ev->data2; } + } } - if (ch == -1) + if (key == -1) return false; - // Save Game string input if (saveStringEnter) { - switch(ch) + switch(key) { case KEY_BACKSPACE: if (saveCharIndex > 0) @@ -1462,23 +1574,40 @@ boolean M_Responder (event_t* ev) savegamestrings[saveSlot][saveCharIndex] = 0; } break; - - case KEY_ESCAPE: - saveStringEnter = 0; - strcpy(&savegamestrings[saveSlot][0],saveOldString); - break; - + + case KEY_ESCAPE: + saveStringEnter = 0; + M_StringCopy(savegamestrings[saveSlot], saveOldString, + SAVESTRINGSIZE); + break; + case KEY_ENTER: saveStringEnter = 0; if (savegamestrings[saveSlot][0]) M_DoSave(saveSlot); break; - + default: - ch = toupper(ch); - if (ch != 32) - if (ch-HU_FONTSTART < 0 || ch-HU_FONTSTART >= HU_FONTSIZE) - break; + // This is complicated. + // Vanilla has a bug where the shift key is ignored when entering + // a savegame name. If vanilla_keyboard_mapping is on, we want + // to emulate this bug by using 'data1'. But if it's turned off, + // it implies the user doesn't care about Vanilla emulation: just + // use the correct 'data2'. + + if (vanilla_keyboard_mapping) + { + ch = key; + } + + ch = toupper(ch); + + if (ch != ' ' + && (ch - HU_FONTSTART < 0 || ch - HU_FONTSTART >= HU_FONTSIZE)) + { + break; + } + if (ch >= 32 && ch <= 127 && saveCharIndex < SAVESTRINGSIZE-1 && M_StringWidth(savegamestrings[saveSlot]) < @@ -1495,121 +1624,137 @@ boolean M_Responder (event_t* ev) // Take care of any messages that need input if (messageToPrint) { - if (messageNeedsInput == true && - !(ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE)) - return false; - + if (messageNeedsInput) + { + if (key != ' ' && key != KEY_ESCAPE + && key != key_menu_confirm && key != key_menu_abort) + { + return false; + } + } + menuactive = messageLastMenuActive; messageToPrint = 0; if (messageRoutine) - messageRoutine(ch); - + messageRoutine(key); + menuactive = false; S_StartSound(NULL,sfx_swtchx); return true; } - - if (devparm && ch == KEY_F1) + + if ((devparm && key == key_menu_help) || + (key != 0 && key == key_menu_screenshot)) { G_ScreenShot (); return true; } - - + // F-Keys if (!menuactive) - switch(ch) - { - case KEY_MINUS: // Screen size down + { + if (key == key_menu_decscreen) // Screen size down + { if (automapactive || chat_on) return false; M_SizeDisplay(0); S_StartSound(NULL,sfx_stnmov); return true; - - case KEY_EQUALS: // Screen size up + } + else if (key == key_menu_incscreen) // Screen size up + { if (automapactive || chat_on) return false; M_SizeDisplay(1); S_StartSound(NULL,sfx_stnmov); return true; - - case KEY_F1: // Help key + } + else if (key == key_menu_help) // Help key + { M_StartControlPanel (); if ( gamemode == retail ) currentMenu = &ReadDef2; else currentMenu = &ReadDef1; - + itemOn = 0; S_StartSound(NULL,sfx_swtchn); return true; - - case KEY_F2: // Save + } + else if (key == key_menu_save) // Save + { M_StartControlPanel(); S_StartSound(NULL,sfx_swtchn); M_SaveGame(0); return true; - - case KEY_F3: // Load + } + else if (key == key_menu_load) // Load + { M_StartControlPanel(); S_StartSound(NULL,sfx_swtchn); M_LoadGame(0); return true; - - case KEY_F4: // Sound Volume + } + else if (key == key_menu_volume) // Sound Volume + { M_StartControlPanel (); currentMenu = &SoundDef; itemOn = sfx_vol; S_StartSound(NULL,sfx_swtchn); return true; - - case KEY_F5: // Detail toggle + } + else if (key == key_menu_detail) // Detail toggle + { M_ChangeDetail(0); S_StartSound(NULL,sfx_swtchn); return true; - - case KEY_F6: // Quicksave + } + else if (key == key_menu_qsave) // Quicksave + { S_StartSound(NULL,sfx_swtchn); M_QuickSave(); return true; - - case KEY_F7: // End game + } + else if (key == key_menu_endgame) // End game + { S_StartSound(NULL,sfx_swtchn); M_EndGame(0); return true; - - case KEY_F8: // Toggle messages + } + else if (key == key_menu_messages) // Toggle messages + { M_ChangeMessages(0); S_StartSound(NULL,sfx_swtchn); return true; - - case KEY_F9: // Quickload + } + else if (key == key_menu_qload) // Quickload + { S_StartSound(NULL,sfx_swtchn); M_QuickLoad(); return true; - - case KEY_F10: // Quit DOOM + } + else if (key == key_menu_quit) // Quit DOOM + { S_StartSound(NULL,sfx_swtchn); M_QuitDOOM(0); return true; - - case KEY_F11: // gamma toggle + } + else if (key == key_menu_gamma) // gamma toggle + { usegamma++; if (usegamma > 4) usegamma = 0; - players[consoleplayer].message = gammamsg[usegamma]; - I_SetPalette (W_CacheLumpName ("PLAYPAL",PU_CACHE)); + players[consoleplayer].message = DEH_String(gammamsg[usegamma]); + I_SetPalette (W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE)); return true; - } + } - // Pop-up menu? if (!menuactive) { - if (ch == KEY_ESCAPE) + if (key == key_menu_activate) { M_StartControlPanel (); S_StartSound(NULL,sfx_swtchn); @@ -1618,21 +1763,26 @@ boolean M_Responder (event_t* ev) return false; } - // Keys usable within menu - switch (ch) + + if (key == key_menu_down) { - case KEY_DOWNARROW: - do + // Move down to next item + + do { if (itemOn+1 > currentMenu->numitems-1) itemOn = 0; else itemOn++; S_StartSound(NULL,sfx_pstop); } while(currentMenu->menuitems[itemOn].status==-1); + return true; - - case KEY_UPARROW: + } + else if (key == key_menu_up) + { + // Move back up to previous item + do { if (!itemOn) @@ -1640,9 +1790,13 @@ boolean M_Responder (event_t* ev) else itemOn--; S_StartSound(NULL,sfx_pstop); } while(currentMenu->menuitems[itemOn].status==-1); - return true; - case KEY_LEFTARROW: + return true; + } + else if (key == key_menu_left) + { + // Slide slider left + if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status == 2) { @@ -1650,8 +1804,11 @@ boolean M_Responder (event_t* ev) currentMenu->menuitems[itemOn].routine(0); } return true; - - case KEY_RIGHTARROW: + } + else if (key == key_menu_right) + { + // Slide slider right + if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status == 2) { @@ -1659,8 +1816,11 @@ boolean M_Responder (event_t* ev) currentMenu->menuitems[itemOn].routine(1); } return true; + } + else if (key == key_menu_forward) + { + // Activate menu item - case KEY_ENTER: if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status) { @@ -1677,14 +1837,20 @@ boolean M_Responder (event_t* ev) } } return true; - - case KEY_ESCAPE: + } + else if (key == key_menu_activate) + { + // Deactivate menu + currentMenu->lastOn = itemOn; M_ClearMenus (); S_StartSound(NULL,sfx_swtchx); return true; - - case KEY_BACKSPACE: + } + else if (key == key_menu_back) + { + // Go back to previous menu + currentMenu->lastOn = itemOn; if (currentMenu->prevMenu) { @@ -1693,24 +1859,33 @@ boolean M_Responder (event_t* ev) S_StartSound(NULL,sfx_swtchn); } return true; - - default: + } + + // Keyboard shortcut? + // Vanilla Doom has a weird behavior where it jumps to the scroll bars + // when the certain keys are pressed, so emulate this. + + else if (ch != 0 || IsNullKey(key)) + { for (i = itemOn+1;i < currentMenu->numitems;i++) + { if (currentMenu->menuitems[i].alphaKey == ch) { itemOn = i; S_StartSound(NULL,sfx_pstop); return true; } + } + for (i = 0;i <= itemOn;i++) + { if (currentMenu->menuitems[i].alphaKey == ch) { itemOn = i; S_StartSound(NULL,sfx_pstop); return true; } - break; - + } } return false; @@ -1732,6 +1907,41 @@ void M_StartControlPanel (void) itemOn = currentMenu->lastOn; // JDC } +// Display OPL debug messages - hack for GENMIDI development. + +#if 0 +static void M_DrawOPLDev(void) +{ + extern void I_OPL_DevMessages(char *, size_t); + char debug[1024]; + char *curr, *p; + int line; + + //XXX I_OPL_DevMessages(debug, sizeof(debug)); + curr = debug; + line = 0; + + for (;;) + { + p = strchr(curr, '\n'); + + if (p != NULL) + { + *p = '\0'; + } + + M_WriteText(0, line * 8, curr); + ++line; + + if (p == NULL) + { + break; + } + + curr = p + 1; + } +} +#endif // // M_Drawer @@ -1742,43 +1952,59 @@ void M_Drawer (void) { static short x; static short y; - short i; - short max; - char string[40]; + unsigned int i; + unsigned int max; + char string[80]; + char *name; int start; inhelpscreens = false; - // Horiz. & Vertically center string and print it. if (messageToPrint) { start = 0; - y = 100 - M_StringHeight(messageString)/2; - while(*(messageString+start)) + y = SCREENHEIGHT/2 - M_StringHeight(messageString) / 2; + while (messageString[start] != '\0') { - for (i = 0;i < strlen(messageString+start);i++) - if (*(messageString+start+i) == '\n') - { - memset(string,0,40); - strncpy(string,messageString+start,i); - start += i+1; - break; - } - - if (i == strlen(messageString+start)) - { - strcpy(string,messageString+start); - start += i; - } - - x = 160 - M_StringWidth(string)/2; - M_WriteText(x,y,string); + int foundnewline = 0; + + for (i = 0; i < strlen(messageString + start); i++) + { + if (messageString[start + i] == '\n') + { + M_StringCopy(string, messageString + start, + sizeof(string)); + if (i < sizeof(string)) + { + string[i] = '\0'; + } + + foundnewline = 1; + start += i + 1; + break; + } + } + + if (!foundnewline) + { + M_StringCopy(string, messageString + start, sizeof(string)); + start += strlen(string); + } + + x = SCREENWIDTH/2 - M_StringWidth(string) / 2; + M_WriteText(x, y, string); y += SHORT(hu_font[0]->height); } + return; } + //if (opldev) + //{ + // M_DrawOPLDev(); + //} + if (!menuactive) return; @@ -1792,17 +2018,20 @@ void M_Drawer (void) for (i=0;imenuitems[i].name[0]) - V_DrawPatchDirect (x,y,0, - W_CacheLumpName(currentMenu->menuitems[i].name ,PU_CACHE)); + name = DEH_String(currentMenu->menuitems[i].name); + + if (name[0]) + { + V_DrawPatchDirect (x, y, W_CacheLumpName(name, PU_CACHE)); + } y += LINEHEIGHT; } // DRAW SKULL - V_DrawPatchDirect(x + SKULLXOFF,currentMenu->y - 5 + itemOn*LINEHEIGHT, 0, - W_CacheLumpName(skullName[whichSkull],PU_CACHE)); - + V_DrawPatchDirect(x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT, + W_CacheLumpName(DEH_String(skullName[whichSkull]), + PU_CACHE)); } @@ -1865,30 +2094,32 @@ void M_Init (void) switch ( gamemode ) { case commercial: - // This is used because DOOM 2 had only one HELP - // page. I use CREDIT as second page now, but - // kept this hack for educational purposes. + // Commercial has no "read this" entry. MainMenu[readthis] = MainMenu[quitdoom]; MainDef.numitems--; MainDef.y += 8; NewDef.prevMenu = &MainDef; - ReadDef1.routine = M_DrawReadThis1; - ReadDef1.x = 330; - ReadDef1.y = 165; - ReadMenu1[0].routine = M_FinishReadThis; break; case shareware: // Episode 2 and 3 are handled, // branching to an ad screen. case registered: - // We need to remove the fourth episode. - EpiDef.numitems--; break; case retail: // We are fine. default: break; } - + + // Versions of doom.exe before the Ultimate Doom release only had + // three episodes; if we're emulating one of those then don't try + // to show episode four. If we are, then do show episode four + // (should crash if missing). + if (gameversion < exe_ultimate) + { + EpiDef.numitems--; + } + + //opldev = M_CheckParm("-opldev") > 0; } diff --git a/frosted-doom/m_menu.h b/frosted-doom/m_menu.h index b02aa07..ce41db3 100644 --- a/frosted-doom/m_menu.h +++ b/frosted-doom/m_menu.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Menu widget stuff, episode selection and such. // -//----------------------------------------------------------------------------- #ifndef __M_MENU__ @@ -56,12 +53,9 @@ void M_StartControlPanel (void); +extern int detailLevel; +extern int screenblocks; #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/m_misc.c b/frosted-doom/m_misc.c index 0df4fe5..53b86db 100644 --- a/frosted-doom/m_misc.c +++ b/frosted-doom/m_misc.c @@ -1,130 +1,126 @@ -// 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 +#include +#include +#include +#include + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#ifdef _MSC_VER +#include +#endif +#else #include #include -#include -#include -#include +#endif -#include +#include "doomtype.h" +#include "deh_str.h" -#include "doomdef.h" - -#include "z_zone.h" - -#include "m_swap.h" -#include "m_argv.h" - -#include "w_wad.h" - +#include "i_swap.h" #include "i_system.h" #include "i_video.h" -#include "v_video.h" - -#include "hu_stuff.h" - -// State. -#include "doomstat.h" - -// Data. -#include "dstrings.h" - #include "m_misc.h" +#include "v_video.h" +#include "w_wad.h" +#include "z_zone.h" // -// M_DrawText -// Returns the final X coordinate -// HU_Init must have been called to init the font +// Create a directory // -extern patch_t* hu_font[HU_FONTSIZE]; -int -M_DrawText -( int x, - int y, - boolean direct, - char* string ) +void M_MakeDirectory(char *path) { - int c; - int w; - - while (*string) - { - 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; - } - - return x; +#ifdef _WIN32 + mkdir(path); +#else + mkdir(path, 0755); +#endif } +// Check if a file exists +boolean M_FileExists(char *filename) +{ + FILE *fstream; + fstream = fopen(filename, "r"); + + if (fstream != NULL) + { + fclose(fstream); + return true; + } + else + { + // If we can't open because the file is a directory, the + // "file" exists at least! + + return errno == EISDIR; + } +} + +// +// Determine the length of an open file. +// + +long M_FileLength(FILE *handle) +{ + long savedpos; + long length; + + // save the current position in the file + savedpos = ftell(handle); + + // jump to the end and find the length + fseek(handle, 0, SEEK_END); + length = ftell(handle); + + // go back to the old location + fseek(handle, savedpos, SEEK_SET); + + return length; +} // // M_WriteFile // -#ifndef O_BINARY -#define O_BINARY 0 -#endif -boolean -M_WriteFile -( char const* name, - void* source, - int length ) +boolean M_WriteFile(char *name, void *source, int length) { - int handle; - int count; + FILE *handle; + int count; - handle = open ( name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + handle = fopen(name, "wb"); - if (handle == -1) + if (handle == NULL) return false; - count = write (handle, source, length); - close (handle); + count = fwrite(source, 1, length, handle); + fclose(handle); if (count < length) return false; @@ -136,24 +132,25 @@ M_WriteFile // // M_ReadFile // -int -M_ReadFile -( char const* name, - byte** buffer ) + +int M_ReadFile(char *name, byte **buffer) { - int handle, count, length; - struct stat fileinfo; - byte *buf; + FILE *handle; + int count, length; + byte *buf; - handle = open (name, O_RDONLY | O_BINARY, 0666); - if (handle == -1) + handle = fopen(name, "rb"); + if (handle == NULL) I_Error ("Couldn't read file %s", name); - if (fstat (handle,&fileinfo) == -1) - I_Error ("Couldn't read file %s", name); - length = fileinfo.st_size; + + // find the size of the file by seeking to the end and + // reading the current position + + length = M_FileLength(handle); + buf = Z_Malloc (length, PU_STATIC, NULL); - count = read (handle, buf, length); - close (handle); + count = fread(buf, 1, length, handle); + fclose (handle); if (count < length) I_Error ("Couldn't read file %s", name); @@ -162,373 +159,378 @@ M_ReadFile return length; } - +// Returns the path to a temporary file of the given name, stored +// inside the system temporary directory. // -// DEFAULTS -// -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; - -extern int key_fire; -extern int key_use; -extern int key_strafe; -extern int key_speed; - -extern int mousebfire; -extern int mousebstrafe; -extern int mousebforward; - -extern int joybfire; -extern int joybstrafe; -extern int joybuse; -extern int joybspeed; - -extern int viewwidth; -extern int viewheight; - -extern int mouseSensitivity; -extern int showMessages; - -extern int detailLevel; - -extern int screenblocks; - -extern int showMessages; - -// machine-independent sound params -extern int numChannels; - - -// UNIX hack, to be removed. -#ifdef SNDSERV -extern char* sndserver_filename; -extern int mb_used; -#endif - -#ifdef LINUX -char* mousetype; -char* mousedev; -#endif - -extern char* chat_macros[]; - - - -typedef struct +char *M_TempFile(char *s) { - char* name; - int* location; - int defaultvalue; - int scantranslate; // PC scan code hack - int untranslated; // lousy hack -} default_t; + char *tempdir; -default_t defaults[] = -{ - {"mouse_sensitivity",&mouseSensitivity, 5}, - {"sfx_volume",&snd_SfxVolume, 8}, - {"music_volume",&snd_MusicVolume, 8}, - {"show_messages",&showMessages, 1}, - +#ifdef _WIN32 -#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, '.'}, + // Check the TEMP environment variable to find the location. - {"key_fire",&key_fire, KEY_RCTRL}, - {"key_use",&key_use, ' '}, - {"key_strafe",&key_strafe, KEY_RALT}, - {"key_speed",&key_speed, KEY_RSHIFT}, + tempdir = getenv("TEMP"); -// UNIX hack, to be removed. -#ifdef SNDSERV - {"sndserver", (int *) &sndserver_filename, (int) "sndserver"}, - {"mb_used", &mb_used, 2}, -#endif - -#endif - -#ifdef LINUX - {"mousedev", (int*)&mousedev, (int)"/dev/ttyS0"}, - {"mousetype", (int*)&mousetype, (int)"microsoft"}, -#endif - - {"use_mouse",&usemouse, 1}, - {"mouseb_fire",&mousebfire,0}, - {"mouseb_strafe",&mousebstrafe,1}, - {"mouseb_forward",&mousebforward,2}, - - {"use_joystick",&usejoystick, 0}, - {"joyb_fire",&joybfire,0}, - {"joyb_strafe",&joybstrafe,1}, - {"joyb_use",&joybuse,3}, - {"joyb_speed",&joybspeed,2}, - - {"screenblocks",&screenblocks, 9}, - {"detaillevel",&detailLevel, 0}, - - {"snd_channels",&numChannels, 3}, - - - - {"usegamma",&usegamma, 0}, - - {"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 } - -}; - -int numdefaults; -char* defaultfile; - - -// -// M_SaveDefaults -// -void M_SaveDefaults (void) -{ - 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 -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)); - } + tempdir = "."; } - - fclose (f); +#else + // In Unix, just use /tmp. + + tempdir = "/tmp"; +#endif + + return M_StringJoin(tempdir, DIR_SEPARATOR_S, s, NULL); } - -// -// M_LoadDefaults -// -extern byte scantokey[128]; - -void M_LoadDefaults (void) +boolean M_StrToInt(const char *str, int *result) { - 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= 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. +// +//--------------------------------------------------------------------------- + +void M_ForceUppercase(char *text) +{ + char *p; + + for (p = text; *p != '\0'; ++p) + { + *p = toupper(*p); + } +} + +// +// M_StrCaseStr +// +// Case-insensitive version of strstr() +// + +char *M_StrCaseStr(char *haystack, char *needle) +{ + unsigned int haystack_len; + unsigned int needle_len; + unsigned int len; + unsigned int i; + + haystack_len = strlen(haystack); + needle_len = strlen(needle); + + if (haystack_len < needle_len) + { + return NULL; + } + + len = haystack_len - needle_len; + + for (i = 0; i <= len; ++i) + { + if (!strncasecmp(haystack + i, needle, needle_len)) + { + return haystack + i; + } + } + + return NULL; +} + +// +// Safe version of strdup() that checks the string was successfully +// allocated. +// + +char *M_StringDuplicate(const char *orig) +{ + char *result; + + result = strdup(orig); + + if (result == NULL) + { + I_Error("Failed to duplicate string (length %i)\n", + strlen(orig)); + } + + return result; +} + +// +// String replace function. +// + +char *M_StringReplace(const char *haystack, const char *needle, + const char *replacement) +{ + 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 (;;) + { + p = strstr(p, needle); + if (p == NULL) + { + break; + } + + p += needle_len; + result_len += strlen(replacement) - needle_len; + } + + // Construct new string. + + 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. + +boolean M_StringCopy(char *dest, const char *src, size_t dest_size) +{ + size_t len; + + if (dest_size >= 1) + { + 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 ; imanufacturer = 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 dest_size) { - if ( (*data & 0xc0) != 0xc0) - *pack++ = *data++; - else - { - *pack++ = 0xc1; - *pack++ = *data++; - } + offset = dest_size; } - - // 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); + return M_StringCopy(dest + offset, src, dest_size - offset); } +// Returns true if 's' begins with the specified prefix. -// -// M_ScreenShot -// -void M_ScreenShot (void) +boolean M_StringStartsWith(const char *s, const char *prefix) { - 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++) - { - lbmname[4] = i/10 + '0'; - lbmname[5] = i%10 + '0'; - if (access(lbmname,0) == -1) - break; // file doesn't exist - } - 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"; + return strlen(s) > strlen(prefix) + && strncmp(s, prefix, strlen(prefix)) == 0; } +// 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; +} + +// Return a newly-malloced string with all the strings given as arguments +// concatenated together. + +char *M_StringJoin(const char *s, ...) +{ + char *result; + const char *v; + va_list args; + size_t result_len; + + result_len = strlen(s) + 1; + + va_start(args, s); + for (;;) + { + v = va_arg(args, const char *); + if (v == NULL) + { + break; + } + + result_len += strlen(v); + } + 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); + + 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 + +// Safe, portable vsnprintf(). +int M_vsnprintf(char *buf, size_t buf_len, const char *s, va_list args) +{ + int result; + + if (buf_len < 1) + { + return 0; + } + + // 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 diff --git a/frosted-doom/m_misc.h b/frosted-doom/m_misc.h index 82afb0f..844b485 100644 --- a/frosted-doom/m_misc.h +++ b/frosted-doom/m_misc.h @@ -1,65 +1,51 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: -// +// Miscellaneous. // -//----------------------------------------------------------------------------- #ifndef __M_MISC__ #define __M_MISC__ +#include +#include #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:$ -// -//----------------------------------------------------------------------------- + diff --git a/frosted-doom/m_random.c b/frosted-doom/m_random.c index 09f857d..8e3b4e1 100644 --- a/frosted-doom/m_random.c +++ b/frosted-doom/m_random.c @@ -1,34 +1,27 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Random number LUT. // -//----------------------------------------------------------------------------- - -static const char rcsid[] = "$Id: m_random.c,v 1.1 1997/02/03 22:45:11 b1 Exp $"; - // // M_Random // Returns a 0-255 number // -unsigned char rndtable[256] = { + +static const unsigned char rndtable[256] = { 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66 , 74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36 , 95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188 , @@ -70,7 +63,3 @@ void M_ClearRandom (void) { rndindex = prndindex = 0; } - - - - diff --git a/frosted-doom/m_random.h b/frosted-doom/m_random.h index 40b86d5..aa6291a 100644 --- a/frosted-doom/m_random.h +++ b/frosted-doom/m_random.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // // -//----------------------------------------------------------------------------- #ifndef __M_RANDOM__ @@ -40,8 +37,3 @@ void M_ClearRandom (void); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/m_swap.c b/frosted-doom/m_swap.c deleted file mode 100644 index 1db93c8..0000000 --- a/frosted-doom/m_swap.c +++ /dev/null @@ -1,57 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ -// -// DESCRIPTION: -// Endianess handling, swapping 16bit and 32bit. -// -//----------------------------------------------------------------------------- - -static const char -rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $"; - - -#ifdef __GNUG__ -#pragma implementation "m_swap.h" -#endif -#include "m_swap.h" - - -// Not needed with big endian. -#ifndef __BIG_ENDIAN__ - -// Swap 16bit, that is, MSB and LSB byte. -unsigned short SwapSHORT(unsigned short x) -{ - // No masking with 0xFF should be necessary. - return (x>>8) | (x<<8); -} - -// Swapping 32bit. -unsigned long SwapLONG( unsigned long x) -{ - return - (x>>24) - | ((x>>8) & 0xff00) - | ((x<<8) & 0xff0000) - | (x<<24); -} - - -#endif - - diff --git a/frosted-doom/m_swap.h b/frosted-doom/m_swap.h deleted file mode 100644 index 86f6e0a..0000000 --- a/frosted-doom/m_swap.h +++ /dev/null @@ -1,52 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// DESCRIPTION: -// Endianess handling, swapping 16bit and 32bit. -// -//----------------------------------------------------------------------------- - - -#ifndef __M_SWAP__ -#define __M_SWAP__ - - -#ifdef __GNUG__ -#pragma interface -#endif - - -// Endianess handling. -// WAD files are stored little endian. -#ifdef __BIG_ENDIAN__ -short SwapSHORT(short); -long SwapLONG(long); -#define SHORT(x) ((short)SwapSHORT((unsigned short) (x))) -#define LONG(x) ((long)SwapLONG((unsigned long) (x))) -#else -#define SHORT(x) (x) -#define LONG(x) (x) -#endif - - - - -#endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/memio.c b/frosted-doom/memio.c new file mode 100644 index 0000000..3cc769a --- /dev/null +++ b/frosted-doom/memio.c @@ -0,0 +1,197 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// Emulates the IO functions in C stdio.h reading and writing to +// memory. +// + +#include +#include +#include + +#include "memio.h" + +#include "z_zone.h" + +typedef enum { + MODE_READ, + MODE_WRITE, +} memfile_mode_t; + +struct _MEMFILE { + unsigned char *buf; + size_t buflen; + size_t alloced; + unsigned int position; + memfile_mode_t mode; +}; + +// Open a memory area for reading + +MEMFILE *mem_fopen_read(void *buf, size_t buflen) +{ + MEMFILE *file; + + file = Z_Malloc(sizeof(MEMFILE), PU_STATIC, 0); + + file->buf = (unsigned char *) buf; + file->buflen = buflen; + file->position = 0; + file->mode = MODE_READ; + + return file; +} + +// Read bytes + +size_t mem_fread(void *buf, size_t size, size_t nmemb, MEMFILE *stream) +{ + size_t items; + + if (stream->mode != MODE_READ) + { + printf("not a read stream\n"); + return -1; + } + + // Trying to read more bytes than we have left? + + items = nmemb; + + if (items * size > stream->buflen - stream->position) + { + items = (stream->buflen - stream->position) / size; + } + + // Copy bytes to buffer + + memcpy(buf, stream->buf + stream->position, items * size); + + // Update position + + stream->position += items * size; + + return items; +} + +// Open a memory area for writing + +MEMFILE *mem_fopen_write(void) +{ + MEMFILE *file; + + file = Z_Malloc(sizeof(MEMFILE), PU_STATIC, 0); + + file->alloced = 1024; + file->buf = Z_Malloc(file->alloced, PU_STATIC, 0); + file->buflen = 0; + file->position = 0; + file->mode = MODE_WRITE; + + return file; +} + +// Write bytes to stream + +size_t mem_fwrite(const void *ptr, size_t size, size_t nmemb, MEMFILE *stream) +{ + size_t bytes; + + if (stream->mode != MODE_WRITE) + { + return -1; + } + + // More bytes than can fit in the buffer? + // If so, reallocate bigger. + + bytes = size * nmemb; + + while (bytes > stream->alloced - stream->position) + { + unsigned char *newbuf; + + newbuf = Z_Malloc(stream->alloced * 2, PU_STATIC, 0); + memcpy(newbuf, stream->buf, stream->alloced); + Z_Free(stream->buf); + stream->buf = newbuf; + stream->alloced *= 2; + } + + // Copy into buffer + + memcpy(stream->buf + stream->position, ptr, bytes); + stream->position += bytes; + + if (stream->position > stream->buflen) + stream->buflen = stream->position; + + return nmemb; +} + +void mem_get_buf(MEMFILE *stream, void **buf, size_t *buflen) +{ + *buf = stream->buf; + *buflen = stream->buflen; +} + +void mem_fclose(MEMFILE *stream) +{ + if (stream->mode == MODE_WRITE) + { + Z_Free(stream->buf); + } + + Z_Free(stream); +} + +long mem_ftell(MEMFILE *stream) +{ + return stream->position; +} + +int mem_fseek(MEMFILE *stream, signed long position, mem_rel_t whence) +{ + unsigned int newpos; + + switch (whence) + { + case MEM_SEEK_SET: + newpos = (int) position; + break; + + case MEM_SEEK_CUR: + newpos = (int) (stream->position + position); + break; + + case MEM_SEEK_END: + newpos = (int) (stream->buflen + position); + break; + default: + return -1; + } + + if (newpos < stream->buflen) + { + stream->position = newpos; + return 0; + } + else + { + printf("Error seeking to %i\n", newpos); + return -1; + } +} + + diff --git a/frosted-doom/memio.h b/frosted-doom/memio.h new file mode 100644 index 0000000..03706a3 --- /dev/null +++ b/frosted-doom/memio.h @@ -0,0 +1,38 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// + +#ifndef MEMIO_H +#define MEMIO_H + +typedef struct _MEMFILE MEMFILE; + +typedef enum +{ + MEM_SEEK_SET, + MEM_SEEK_CUR, + MEM_SEEK_END, +} mem_rel_t; + +MEMFILE *mem_fopen_read(void *buf, size_t buflen); +size_t mem_fread(void *buf, size_t size, size_t nmemb, MEMFILE *stream); +MEMFILE *mem_fopen_write(void); +size_t mem_fwrite(const void *ptr, size_t size, size_t nmemb, MEMFILE *stream); +void mem_get_buf(MEMFILE *stream, void **buf, size_t *buflen); +void mem_fclose(MEMFILE *stream); +long mem_ftell(MEMFILE *stream); +int mem_fseek(MEMFILE *stream, signed long offset, mem_rel_t whence); + +#endif /* #ifndef MEMIO_H */ + diff --git a/frosted-doom/net_client.h b/frosted-doom/net_client.h new file mode 100644 index 0000000..31dc9e4 --- /dev/null +++ b/frosted-doom/net_client.h @@ -0,0 +1,52 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// Network client code +// + +#ifndef NET_CLIENT_H +#define NET_CLIENT_H + +#include "doomtype.h" +#include "d_ticcmd.h" +#include "sha1.h" +#include "net_defs.h" + +boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data); +void NET_CL_Disconnect(void); +void NET_CL_Run(void); +void NET_CL_Init(void); +void NET_CL_LaunchGame(void); +void NET_CL_StartGame(net_gamesettings_t *settings); +void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic); +boolean NET_CL_GetSettings(net_gamesettings_t *_settings); +void NET_Init(void); + +void NET_BindVariables(void); + +extern boolean net_client_connected; +extern boolean net_client_received_wait_data; +extern net_waitdata_t net_client_wait_data; +extern boolean net_waiting_for_launch; +extern char *net_player_name; + +extern sha1_digest_t net_server_wad_sha1sum; +extern sha1_digest_t net_server_deh_sha1sum; +extern unsigned int net_server_is_freedoom; +extern sha1_digest_t net_local_wad_sha1sum; +extern sha1_digest_t net_local_deh_sha1sum; +extern unsigned int net_local_is_freedoom; + +extern boolean drone; + +#endif /* #ifndef NET_CLIENT_H */ diff --git a/frosted-doom/net_dedicated.h b/frosted-doom/net_dedicated.h new file mode 100644 index 0000000..3d7387b --- /dev/null +++ b/frosted-doom/net_dedicated.h @@ -0,0 +1,25 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// +// Dedicated server code. +// + +#ifndef NET_DEDICATED_H +#define NET_DEDICATED_H + +void NET_DedicatedServer(void); + +#endif /* #ifndef NET_DEDICATED_H */ + + diff --git a/frosted-doom/net_defs.h b/frosted-doom/net_defs.h new file mode 100644 index 0000000..bedfb95 --- /dev/null +++ b/frosted-doom/net_defs.h @@ -0,0 +1,248 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Definitions for use in networking code. +// + +#ifndef NET_DEFS_H +#define NET_DEFS_H + +#include + +#include "doomtype.h" +#include "d_ticcmd.h" +#include "sha1.h" + +// Absolute maximum number of "nodes" in the game. This is different to +// NET_MAXPLAYERS, as there may be observers that are not participating +// (eg. left/right monitors) + +#define MAXNETNODES 16 + +// The maximum number of players, multiplayer/networking. +// This is the maximum supported by the networking code; individual games +// have their own values for MAXPLAYERS that can be smaller. + +#define NET_MAXPLAYERS 8 + +// Maximum length of a player's name. + +#define MAXPLAYERNAME 30 + +// Networking and tick handling related. + +#define BACKUPTICS 128 + +typedef struct _net_module_s net_module_t; +typedef struct _net_packet_s net_packet_t; +typedef struct _net_addr_s net_addr_t; +typedef struct _net_context_s net_context_t; + +struct _net_packet_s +{ + byte *data; + size_t len; + size_t alloced; + unsigned int pos; +}; + +struct _net_module_s +{ + // Initialize this module for use as a client + + boolean (*InitClient)(void); + + // Initialize this module for use as a server + + boolean (*InitServer)(void); + + // Send a packet + + void (*SendPacket)(net_addr_t *addr, net_packet_t *packet); + + // Check for new packets to receive + // + // Returns true if packet received + + boolean (*RecvPacket)(net_addr_t **addr, net_packet_t **packet); + + // Converts an address to a string + + void (*AddrToString)(net_addr_t *addr, char *buffer, int buffer_len); + + // Free back an address when no longer in use + + void (*FreeAddress)(net_addr_t *addr); + + // Try to resolve a name to an address + + net_addr_t *(*ResolveAddress)(char *addr); +}; + +// net_addr_t + +struct _net_addr_s +{ + net_module_t *module; + void *handle; +}; + +// magic number sent when connecting to check this is a valid client + +#define NET_MAGIC_NUMBER 3436803284U + +// header field value indicating that the packet is a reliable packet + +#define NET_RELIABLE_PACKET (1 << 15) + +// packet types + +typedef enum +{ + NET_PACKET_TYPE_SYN, + NET_PACKET_TYPE_ACK, + NET_PACKET_TYPE_REJECTED, + NET_PACKET_TYPE_KEEPALIVE, + NET_PACKET_TYPE_WAITING_DATA, + NET_PACKET_TYPE_GAMESTART, + NET_PACKET_TYPE_GAMEDATA, + NET_PACKET_TYPE_GAMEDATA_ACK, + NET_PACKET_TYPE_DISCONNECT, + NET_PACKET_TYPE_DISCONNECT_ACK, + NET_PACKET_TYPE_RELIABLE_ACK, + NET_PACKET_TYPE_GAMEDATA_RESEND, + NET_PACKET_TYPE_CONSOLE_MESSAGE, + NET_PACKET_TYPE_QUERY, + NET_PACKET_TYPE_QUERY_RESPONSE, + NET_PACKET_TYPE_LAUNCH, +} net_packet_type_t; + +typedef enum +{ + NET_MASTER_PACKET_TYPE_ADD, + NET_MASTER_PACKET_TYPE_ADD_RESPONSE, + NET_MASTER_PACKET_TYPE_QUERY, + NET_MASTER_PACKET_TYPE_QUERY_RESPONSE, + NET_MASTER_PACKET_TYPE_GET_METADATA, + NET_MASTER_PACKET_TYPE_GET_METADATA_RESPONSE, + NET_MASTER_PACKET_TYPE_SIGN_START, + NET_MASTER_PACKET_TYPE_SIGN_START_RESPONSE, + NET_MASTER_PACKET_TYPE_SIGN_END, + NET_MASTER_PACKET_TYPE_SIGN_END_RESPONSE, +} net_master_packet_type_t; + +// Settings specified when the client connects to the server. + +typedef struct +{ + int gamemode; + int gamemission; + int lowres_turn; + int drone; + int max_players; + int is_freedoom; + sha1_digest_t wad_sha1sum; + sha1_digest_t deh_sha1sum; + int player_class; +} net_connect_data_t; + +// Game settings sent by client to server when initiating game start, +// and received from the server by clients when the game starts. + +typedef struct +{ + int ticdup; + int extratics; + int deathmatch; + int episode; + int nomonsters; + int fast_monsters; + int respawn_monsters; + int map; + int skill; + int gameversion; + int lowres_turn; + int new_sync; + int timelimit; + int loadgame; + int random; // [Strife only] + + // These fields are only used by the server when sending a game + // start message: + + int num_players; + int consoleplayer; + + // Hexen player classes: + + int player_classes[NET_MAXPLAYERS]; + +} net_gamesettings_t; + +#define NET_TICDIFF_FORWARD (1 << 0) +#define NET_TICDIFF_SIDE (1 << 1) +#define NET_TICDIFF_TURN (1 << 2) +#define NET_TICDIFF_BUTTONS (1 << 3) +#define NET_TICDIFF_CONSISTANCY (1 << 4) +#define NET_TICDIFF_CHATCHAR (1 << 5) +#define NET_TICDIFF_RAVEN (1 << 6) +#define NET_TICDIFF_STRIFE (1 << 7) + +typedef struct +{ + unsigned int diff; + ticcmd_t cmd; +} net_ticdiff_t; + +// Complete set of ticcmds from all players + +typedef struct +{ + signed int latency; + unsigned int seq; + boolean playeringame[NET_MAXPLAYERS]; + net_ticdiff_t cmds[NET_MAXPLAYERS]; +} net_full_ticcmd_t; + +// Data sent in response to server queries + +typedef struct +{ + char *version; + int server_state; + int num_players; + int max_players; + int gamemode; + int gamemission; + char *description; +} net_querydata_t; + +// Data sent by the server while waiting for the game to start. + +typedef struct +{ + int num_players; + int num_drones; + int ready_players; + int max_players; + int is_controller; + int consoleplayer; + char player_names[NET_MAXPLAYERS][MAXPLAYERNAME]; + char player_addrs[NET_MAXPLAYERS][MAXPLAYERNAME]; + sha1_digest_t wad_sha1sum; + sha1_digest_t deh_sha1sum; + int is_freedoom; +} net_waitdata_t; + +#endif /* #ifndef NET_DEFS_H */ diff --git a/frosted-doom/net_gui.h b/frosted-doom/net_gui.h new file mode 100644 index 0000000..4f4198b --- /dev/null +++ b/frosted-doom/net_gui.h @@ -0,0 +1,29 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// Graphical stuff related to the networking code: +// +// * The client waiting screen when we are waiting for the server to +// start the game. +// + + +#ifndef NET_GUI_H +#define NET_GUI_H + +#include "doomtype.h" + +extern void NET_WaitForLaunch(void); + +#endif /* #ifndef NET_GUI_H */ + diff --git a/frosted-doom/net_io.h b/frosted-doom/net_io.h new file mode 100644 index 0000000..5350222 --- /dev/null +++ b/frosted-doom/net_io.h @@ -0,0 +1,36 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Network packet manipulation (net_packet_t) +// + +#ifndef NET_IO_H +#define NET_IO_H + +#include "net_defs.h" + +extern net_addr_t net_broadcast_addr; + +net_context_t *NET_NewContext(void); +void NET_AddModule(net_context_t *context, net_module_t *module); +void NET_SendPacket(net_addr_t *addr, net_packet_t *packet); +void NET_SendBroadcast(net_context_t *context, net_packet_t *packet); +boolean NET_RecvPacket(net_context_t *context, net_addr_t **addr, + net_packet_t **packet); +char *NET_AddrToString(net_addr_t *addr); +void NET_FreeAddress(net_addr_t *addr); +net_addr_t *NET_ResolveAddress(net_context_t *context, char *address); + +#endif /* #ifndef NET_IO_H */ + diff --git a/frosted-doom/net_loop.h b/frosted-doom/net_loop.h new file mode 100644 index 0000000..5a2e58e --- /dev/null +++ b/frosted-doom/net_loop.h @@ -0,0 +1,27 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Loopback network module for server compiled into the client +// + +#ifndef NET_LOOP_H +#define NET_LOOP_H + +#include "net_defs.h" + +extern net_module_t net_loop_client_module; +extern net_module_t net_loop_server_module; + +#endif /* #ifndef NET_LOOP_H */ + diff --git a/frosted-doom/net_packet.h b/frosted-doom/net_packet.h new file mode 100644 index 0000000..ced4e43 --- /dev/null +++ b/frosted-doom/net_packet.h @@ -0,0 +1,44 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Definitions for use in networking code. +// + +#ifndef NET_PACKET_H +#define NET_PACKET_H + +#include "net_defs.h" + +net_packet_t *NET_NewPacket(int initial_size); +net_packet_t *NET_PacketDup(net_packet_t *packet); +void NET_FreePacket(net_packet_t *packet); + +boolean NET_ReadInt8(net_packet_t *packet, unsigned int *data); +boolean NET_ReadInt16(net_packet_t *packet, unsigned int *data); +boolean NET_ReadInt32(net_packet_t *packet, unsigned int *data); + +boolean NET_ReadSInt8(net_packet_t *packet, signed int *data); +boolean NET_ReadSInt16(net_packet_t *packet, signed int *data); +boolean NET_ReadSInt32(net_packet_t *packet, signed int *data); + +char *NET_ReadString(net_packet_t *packet); + +void NET_WriteInt8(net_packet_t *packet, unsigned int i); +void NET_WriteInt16(net_packet_t *packet, unsigned int i); +void NET_WriteInt32(net_packet_t *packet, unsigned int i); + +void NET_WriteString(net_packet_t *packet, char *string); + +#endif /* #ifndef NET_PACKET_H */ + diff --git a/frosted-doom/net_query.h b/frosted-doom/net_query.h new file mode 100644 index 0000000..563a055 --- /dev/null +++ b/frosted-doom/net_query.h @@ -0,0 +1,44 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Querying servers to find their current status. +// + +#ifndef NET_QUERY_H +#define NET_QUERY_H + +#include "net_defs.h" + +typedef void (*net_query_callback_t)(net_addr_t *addr, + net_querydata_t *querydata, + unsigned int ping_time, + void *user_data); + +extern int NET_StartLANQuery(void); +extern int NET_StartMasterQuery(void); + +extern void NET_LANQuery(void); +extern void NET_MasterQuery(void); +extern void NET_QueryAddress(char *addr); +extern net_addr_t *NET_FindLANServer(void); + +extern int NET_Query_Poll(net_query_callback_t callback, void *user_data); + +extern net_addr_t *NET_Query_ResolveMaster(net_context_t *context); +extern void NET_Query_AddToMaster(net_addr_t *master_addr); +extern boolean NET_Query_CheckAddedToMaster(boolean *result); +extern void NET_Query_MasterResponse(net_packet_t *packet); + +#endif /* #ifndef NET_QUERY_H */ + diff --git a/frosted-doom/net_sdl.h b/frosted-doom/net_sdl.h new file mode 100644 index 0000000..c249de1 --- /dev/null +++ b/frosted-doom/net_sdl.h @@ -0,0 +1,26 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Networking module which uses SDL_net +// + +#ifndef NET_SDL_H +#define NET_SDL_H + +#include "net_defs.h" + +extern net_module_t net_sdl_module; + +#endif /* #ifndef NET_SDL_H */ + diff --git a/frosted-doom/net_server.h b/frosted-doom/net_server.h new file mode 100644 index 0000000..b9de745 --- /dev/null +++ b/frosted-doom/net_server.h @@ -0,0 +1,42 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// Network server code +// + +#ifndef NET_SERVER_H +#define NET_SERVER_H + +// initialize server and wait for connections + +void NET_SV_Init(void); + +// run server: check for new packets received etc. + +void NET_SV_Run(void); + +// Shut down the server +// Blocks until all clients disconnect, or until a 5 second timeout + +void NET_SV_Shutdown(void); + +// Add a network module to the context used by the server + +void NET_SV_AddModule(net_module_t *module); + +// Register server with master server. + +void NET_SV_RegisterWithMaster(void); + +#endif /* #ifndef NET_SERVER_H */ + diff --git a/frosted-doom/p_ceilng.c b/frosted-doom/p_ceilng.c index 6809902..d1e61c8 100644 --- a/frosted-doom/p_ceilng.c +++ b/frosted-doom/p_ceilng.c @@ -1,27 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: Ceiling aninmation (lowering, crushing, raising) // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: p_ceilng.c,v 1.4 1997/02/03 16:47:53 b1 Exp $"; #include "z_zone.h" @@ -72,8 +65,7 @@ void T_MoveCeiling (ceiling_t* ceiling) case silentCrushAndRaise: break; default: - S_StartSound((mobj_t *)&ceiling->sector->soundorg, - sfx_stnmov); + S_StartSound(&ceiling->sector->soundorg, sfx_stnmov); // ? break; } @@ -88,8 +80,7 @@ void T_MoveCeiling (ceiling_t* ceiling) break; case silentCrushAndRaise: - S_StartSound((mobj_t *)&ceiling->sector->soundorg, - sfx_pstop); + S_StartSound(&ceiling->sector->soundorg, sfx_pstop); case fastCrushAndRaise: case crushAndRaise: ceiling->direction = -1; @@ -115,8 +106,7 @@ void T_MoveCeiling (ceiling_t* ceiling) { case silentCrushAndRaise: break; default: - S_StartSound((mobj_t *)&ceiling->sector->soundorg, - sfx_stnmov); + S_StartSound(&ceiling->sector->soundorg, sfx_stnmov); } } @@ -125,8 +115,7 @@ void T_MoveCeiling (ceiling_t* ceiling) switch(ceiling->type) { case silentCrushAndRaise: - S_StartSound((mobj_t *)&ceiling->sector->soundorg, - sfx_pstop); + S_StartSound(&ceiling->sector->soundorg, sfx_pstop); case crushAndRaise: ceiling->speed = CEILSPEED; case fastCrushAndRaise: diff --git a/frosted-doom/p_doors.c b/frosted-doom/p_doors.c index 2e0442e..cafab0f 100644 --- a/frosted-doom/p_doors.c +++ b/frosted-doom/p_doors.c @@ -1,31 +1,25 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: Door animation code (opening/closing) // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: p_doors.c,v 1.4 1997/02/03 16:47:53 b1 Exp $"; #include "z_zone.h" #include "doomdef.h" +#include "deh_main.h" #include "p_local.h" #include "s_sound.h" @@ -72,22 +66,19 @@ void T_VerticalDoor (vldoor_t* door) { switch(door->type) { - case blazeRaise: + case vld_blazeRaise: door->direction = -1; // time to go back down - S_StartSound((mobj_t *)&door->sector->soundorg, - sfx_bdcls); + S_StartSound(&door->sector->soundorg, sfx_bdcls); break; - case normal: + case vld_normal: door->direction = -1; // time to go back down - S_StartSound((mobj_t *)&door->sector->soundorg, - sfx_dorcls); + S_StartSound(&door->sector->soundorg, sfx_dorcls); break; - case close30ThenOpen: + case vld_close30ThenOpen: door->direction = 1; - S_StartSound((mobj_t *)&door->sector->soundorg, - sfx_doropn); + S_StartSound(&door->sector->soundorg, sfx_doropn); break; default: @@ -102,11 +93,10 @@ void T_VerticalDoor (vldoor_t* door) { switch(door->type) { - case raiseIn5Mins: + case vld_raiseIn5Mins: door->direction = 1; - door->type = normal; - S_StartSound((mobj_t *)&door->sector->soundorg, - sfx_doropn); + door->type = vld_normal; + S_StartSound(&door->sector->soundorg, sfx_doropn); break; default: @@ -125,23 +115,22 @@ void T_VerticalDoor (vldoor_t* door) { switch(door->type) { - case blazeRaise: - case blazeClose: + case vld_blazeRaise: + case vld_blazeClose: door->sector->specialdata = NULL; P_RemoveThinker (&door->thinker); // unlink and free - S_StartSound((mobj_t *)&door->sector->soundorg, - sfx_bdcls); + S_StartSound(&door->sector->soundorg, sfx_bdcls); break; - case normal: - case close: + case vld_normal: + case vld_close: door->sector->specialdata = NULL; P_RemoveThinker (&door->thinker); // unlink and free break; - case close30ThenOpen: + case vld_close30ThenOpen: door->direction = 0; - door->topcountdown = 35*30; + door->topcountdown = TICRATE*30; break; default: @@ -152,14 +141,13 @@ void T_VerticalDoor (vldoor_t* door) { switch(door->type) { - case blazeClose: - case close: // DO NOT GO BACK UP! + case vld_blazeClose: + case vld_close: // DO NOT GO BACK UP! break; default: door->direction = 1; - S_StartSound((mobj_t *)&door->sector->soundorg, - sfx_doropn); + S_StartSound(&door->sector->soundorg, sfx_doropn); break; } } @@ -176,15 +164,15 @@ void T_VerticalDoor (vldoor_t* door) { switch(door->type) { - case blazeRaise: - case normal: + case vld_blazeRaise: + case vld_normal: door->direction = 0; // wait at top door->topcountdown = door->topwait; break; - case close30ThenOpen: - case blazeOpen: - case open: + case vld_close30ThenOpen: + case vld_blazeOpen: + case vld_open: door->sector->specialdata = NULL; P_RemoveThinker (&door->thinker); // unlink and free break; @@ -224,7 +212,7 @@ EV_DoLockedDoor return 0; if (!p->cards[it_bluecard] && !p->cards[it_blueskull]) { - p->message = PD_BLUEO; + p->message = DEH_String(PD_BLUEO); S_StartSound(NULL,sfx_oof); return 0; } @@ -236,7 +224,7 @@ EV_DoLockedDoor return 0; if (!p->cards[it_redcard] && !p->cards[it_redskull]) { - p->message = PD_REDO; + p->message = DEH_String(PD_REDO); S_StartSound(NULL,sfx_oof); return 0; } @@ -249,7 +237,7 @@ EV_DoLockedDoor if (!p->cards[it_yellowcard] && !p->cards[it_yellowskull]) { - p->message = PD_YELLOWO; + p->message = DEH_String(PD_YELLOWO); S_StartSound(NULL,sfx_oof); return 0; } @@ -293,49 +281,44 @@ EV_DoDoor switch(type) { - case blazeClose: + case vld_blazeClose: door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->direction = -1; door->speed = VDOORSPEED * 4; - S_StartSound((mobj_t *)&door->sector->soundorg, - sfx_bdcls); + S_StartSound(&door->sector->soundorg, sfx_bdcls); break; - case close: + case vld_close: door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->direction = -1; - S_StartSound((mobj_t *)&door->sector->soundorg, - sfx_dorcls); + S_StartSound(&door->sector->soundorg, sfx_dorcls); break; - case close30ThenOpen: + case vld_close30ThenOpen: door->topheight = sec->ceilingheight; door->direction = -1; - S_StartSound((mobj_t *)&door->sector->soundorg, - sfx_dorcls); + S_StartSound(&door->sector->soundorg, sfx_dorcls); break; - case blazeRaise: - case blazeOpen: + case vld_blazeRaise: + case vld_blazeOpen: door->direction = 1; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->speed = VDOORSPEED * 4; if (door->topheight != sec->ceilingheight) - S_StartSound((mobj_t *)&door->sector->soundorg, - sfx_bdopn); + S_StartSound(&door->sector->soundorg, sfx_bdopn); break; - case normal: - case open: + case vld_normal: + case vld_open: door->direction = 1; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; if (door->topheight != sec->ceilingheight) - S_StartSound((mobj_t *)&door->sector->soundorg, - sfx_doropn); + S_StartSound(&door->sector->soundorg, sfx_doropn); break; default: @@ -356,7 +339,6 @@ EV_VerticalDoor mobj_t* thing ) { player_t* player; - //int secnum; sector_t* sec; vldoor_t* door; int side; @@ -375,7 +357,7 @@ EV_VerticalDoor if (!player->cards[it_bluecard] && !player->cards[it_blueskull]) { - player->message = PD_BLUEK; + player->message = DEH_String(PD_BLUEK); S_StartSound(NULL,sfx_oof); return; } @@ -389,7 +371,7 @@ EV_VerticalDoor if (!player->cards[it_yellowcard] && !player->cards[it_yellowskull]) { - player->message = PD_YELLOWK; + player->message = DEH_String(PD_YELLOWK); S_StartSound(NULL,sfx_oof); return; } @@ -402,7 +384,7 @@ EV_VerticalDoor if (!player->cards[it_redcard] && !player->cards[it_redskull]) { - player->message = PD_REDK; + player->message = DEH_String(PD_REDK); S_StartSound(NULL,sfx_oof); return; } @@ -411,7 +393,6 @@ EV_VerticalDoor // if the sector has an active thinker, use it sec = sides[ line->sidenum[side^1]] .sector; - //secnum = sec-sectors; if (sec->specialdata) { @@ -429,8 +410,41 @@ EV_VerticalDoor { if (!thing->player) return; // JDC: bad guys never close doors - - door->direction = -1; // start going down immediately + + // When is a door not a door? + // In Vanilla, door->direction is set, even though + // "specialdata" might not actually point at a door. + + if (door->thinker.function.acp1 == (actionf_p1) T_VerticalDoor) + { + door->direction = -1; // start going down immediately + } + else if (door->thinker.function.acp1 == (actionf_p1) T_PlatRaise) + { + // Erm, this is a plat, not a door. + // This notably causes a problem in ep1-0500.lmp where + // a plat and a door are cross-referenced; the door + // doesn't open on 64-bit. + // The direction field in vldoor_t corresponds to the wait + // field in plat_t. Let's set that to -1 instead. + + plat_t *plat; + + plat = (plat_t *) door; + plat->wait = -1; + } + else + { + // This isn't a door OR a plat. Now we're in trouble. + + fprintf(stderr, "EV_VerticalDoor: Tried to close " + "something that wasn't a door.\n"); + + // Try closing it anyway. At least it will work on 32-bit + // machines. + + door->direction = -1; + } } return; } @@ -441,16 +455,16 @@ EV_VerticalDoor { case 117: // BLAZING DOOR RAISE case 118: // BLAZING DOOR OPEN - S_StartSound((mobj_t *)&sec->soundorg,sfx_bdopn); + S_StartSound(&sec->soundorg,sfx_bdopn); break; case 1: // NORMAL DOOR SOUND case 31: - S_StartSound((mobj_t *)&sec->soundorg,sfx_doropn); + S_StartSound(&sec->soundorg,sfx_doropn); break; default: // LOCKED DOOR SOUND - S_StartSound((mobj_t *)&sec->soundorg,sfx_doropn); + S_StartSound(&sec->soundorg,sfx_doropn); break; } @@ -471,23 +485,23 @@ EV_VerticalDoor case 26: case 27: case 28: - door->type = normal; + door->type = vld_normal; break; case 31: case 32: case 33: case 34: - door->type = open; + door->type = vld_open; line->special = 0; break; case 117: // blazing door raise - door->type = blazeRaise; + door->type = vld_blazeRaise; door->speed = VDOORSPEED*4; break; case 118: // blazing door open - door->type = blazeOpen; + door->type = vld_blazeOpen; line->special = 0; door->speed = VDOORSPEED*4; break; @@ -516,9 +530,9 @@ void P_SpawnDoorCloseIn30 (sector_t* sec) door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor; door->sector = sec; door->direction = 0; - door->type = normal; + door->type = vld_normal; door->speed = VDOORSPEED; - door->topcountdown = 30 * 35; + door->topcountdown = 30 * TICRATE; } // @@ -541,12 +555,12 @@ P_SpawnDoorRaiseIn5Mins door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor; door->sector = sec; door->direction = 2; - door->type = raiseIn5Mins; + door->type = vld_raiseIn5Mins; door->speed = VDOORSPEED; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->topwait = VDOORWAIT; - door->topcountdown = 5 * 60 * 35; + door->topcountdown = 5 * 60 * TICRATE; } diff --git a/frosted-doom/p_enemy.c b/frosted-doom/p_enemy.c index 6d0175a..f2b44d1 100644 --- a/frosted-doom/p_enemy.c +++ b/frosted-doom/p_enemy.c @@ -1,31 +1,24 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Enemy thinking, AI. // Action Pointer Functions // that are associated with states/frames. // -//----------------------------------------------------------------------------- - -static const char -rcsid[] = "$Id: p_enemy.c,v 1.5 1997/02/03 22:45:11 b1 Exp $"; +#include #include #include "m_random.h" @@ -264,11 +257,6 @@ boolean P_CheckMissileRange (mobj_t* actor) fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000}; fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000}; -#define MAXSPECIALCROSS 8 - -extern line_t* spechit[MAXSPECIALCROSS]; -extern int numspechit; - boolean P_Move (mobj_t* actor) { fixed_t tryx; @@ -400,7 +388,7 @@ void P_NewChaseDir (mobj_t* actor) && d[2] != DI_NODIR) { actor->movedir = diags[((deltay<0)<<1)+(deltax>0)]; - if (actor->movedir != turnaround && P_TryWalk(actor)) + if (actor->movedir != (int) turnaround && P_TryWalk(actor)) return; } @@ -453,7 +441,7 @@ void P_NewChaseDir (mobj_t* actor) tdir<=DI_SOUTHEAST; tdir++ ) { - if (tdir!=turnaround) + if (tdir != (int) turnaround) { actor->movedir =tdir; @@ -468,9 +456,9 @@ void P_NewChaseDir (mobj_t* actor) tdir != (DI_EAST-1); tdir-- ) { - if (tdir!=turnaround) + if (tdir != (int) turnaround) { - actor->movedir =tdir; + actor->movedir = tdir; if ( P_TryWalk(actor) ) return; @@ -503,12 +491,9 @@ P_LookForPlayers int c; int stop; player_t* player; - //sector_t* sector; angle_t an; fixed_t dist; - - //sector = actor->subsector->sector; - + c = 0; stop = (actor->lastlook-1)&3; @@ -589,7 +574,7 @@ void A_KeenDie (mobj_t* mo) } junk.tag = 666; - EV_DoDoor(&junk,open); + EV_DoDoor(&junk, vld_open); } @@ -1257,14 +1242,17 @@ void A_FireCrackle (mobj_t* actor) void A_Fire (mobj_t* actor) { mobj_t* dest; + mobj_t* target; unsigned an; dest = actor->tracer; if (!dest) return; + + target = P_SubstNullMobj(actor->target); // don't move it if the vile lost sight - if (!P_CheckSight (actor->target, dest) ) + if (!P_CheckSight (target, dest) ) return; an = dest->angle >> ANGLETOFINESHIFT; @@ -1358,14 +1346,17 @@ void A_FatRaise (mobj_t *actor) void A_FatAttack1 (mobj_t* actor) { mobj_t* mo; + mobj_t* target; int an; - + A_FaceTarget (actor); + // Change direction to ... actor->angle += FATSPREAD; - P_SpawnMissile (actor, actor->target, MT_FATSHOT); + target = P_SubstNullMobj(actor->target); + P_SpawnMissile (actor, target, MT_FATSHOT); - mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT); + mo = P_SpawnMissile (actor, target, MT_FATSHOT); mo->angle += FATSPREAD; an = mo->angle >> ANGLETOFINESHIFT; mo->momx = FixedMul (mo->info->speed, finecosine[an]); @@ -1375,14 +1366,16 @@ void A_FatAttack1 (mobj_t* actor) void A_FatAttack2 (mobj_t* actor) { mobj_t* mo; + mobj_t* target; int an; A_FaceTarget (actor); // Now here choose opposite deviation. actor->angle -= FATSPREAD; - P_SpawnMissile (actor, actor->target, MT_FATSHOT); + target = P_SubstNullMobj(actor->target); + P_SpawnMissile (actor, target, MT_FATSHOT); - mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT); + mo = P_SpawnMissile (actor, target, MT_FATSHOT); mo->angle -= FATSPREAD*2; an = mo->angle >> ANGLETOFINESHIFT; mo->momx = FixedMul (mo->info->speed, finecosine[an]); @@ -1392,17 +1385,20 @@ void A_FatAttack2 (mobj_t* actor) void A_FatAttack3 (mobj_t* actor) { mobj_t* mo; + mobj_t* target; int an; A_FaceTarget (actor); + + target = P_SubstNullMobj(actor->target); - mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT); + mo = P_SpawnMissile (actor, target, MT_FATSHOT); mo->angle -= FATSPREAD/2; an = mo->angle >> ANGLETOFINESHIFT; mo->momx = FixedMul (mo->info->speed, finecosine[an]); mo->momy = FixedMul (mo->info->speed, finesine[an]); - mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT); + mo = P_SpawnMissile (actor, target, MT_FATSHOT); mo->angle += FATSPREAD/2; an = mo->angle >> ANGLETOFINESHIFT; mo->momx = FixedMul (mo->info->speed, finecosine[an]); @@ -1597,9 +1593,60 @@ void A_Fall (mobj_t *actor) // void A_Explode (mobj_t* thingy) { - P_RadiusAttack ( thingy, thingy->target, 128 ); + P_RadiusAttack(thingy, thingy->target, 128); } +// Check whether the death of the specified monster type is allowed +// to trigger the end of episode special action. +// +// This behavior changed in v1.9, the most notable effect of which +// was to break uac_dead.wad + +static boolean CheckBossEnd(mobjtype_t motype) +{ + if (gameversion < exe_ultimate) + { + if (gamemap != 8) + { + return false; + } + + // Baron death on later episodes is nothing special. + + if (motype == MT_BRUISER && gameepisode != 1) + { + return false; + } + + return true; + } + else + { + // New logic that appeared in Ultimate Doom. + // Looks like the logic was overhauled while adding in the + // episode 4 support. Now bosses only trigger on their + // specific episode. + + switch(gameepisode) + { + case 1: + return gamemap == 8 && motype == MT_BRUISER; + + case 2: + return gamemap == 8 && motype == MT_CYBORG; + + case 3: + return gamemap == 8 && motype == MT_SPIDER; + + case 4: + return (gamemap == 6 && motype == MT_CYBORG) + || (gamemap == 8 && motype == MT_SPIDER); + + default: + return gamemap == 8; + } + } +} // // A_BossDeath @@ -1624,61 +1671,12 @@ void A_BossDeath (mobj_t* mo) } else { - switch(gameepisode) - { - case 1: - if (gamemap != 8) - return; - - if (mo->type != MT_BRUISER) - return; - break; - - case 2: - if (gamemap != 8) - return; - - if (mo->type != MT_CYBORG) - return; - break; - - case 3: - if (gamemap != 8) - return; - - if (mo->type != MT_SPIDER) - return; - - break; - - case 4: - switch(gamemap) - { - case 6: - if (mo->type != MT_CYBORG) - return; - break; - - case 8: - if (mo->type != MT_SPIDER) - return; - break; - - default: - return; - break; - } - break; - - default: - if (gamemap != 8) - return; - break; - } - + if (!CheckBossEnd(mo->type)) + { + return; + } } - // make sure there is a player alive for victory for (i=0 ; i 0) @@ -1739,7 +1737,7 @@ void A_BossDeath (mobj_t* mo) { case 6: junk.tag = 666; - EV_DoDoor (&junk, blazeOpen); + EV_DoDoor (&junk, vld_blazeOpen); return; break; @@ -1808,7 +1806,7 @@ A_CloseShotgun2 mobj_t* braintargets[32]; int numbraintargets; -int braintargeton; +int braintargeton = 0; void A_BrainAwake (mobj_t* mo) { @@ -1944,7 +1942,7 @@ void A_SpawnFly (mobj_t* mo) if (--mo->reactiontime) return; // still flying - targ = mo->target; + targ = P_SubstNullMobj(mo->target); // First spawn teleport fog. fog = P_SpawnMobj (targ->x, targ->y, targ->z, MT_SPAWNFIRE); diff --git a/frosted-doom/p_floor.c b/frosted-doom/p_floor.c index 37a6cd8..1384ee6 100644 --- a/frosted-doom/p_floor.c +++ b/frosted-doom/p_floor.c @@ -1,28 +1,21 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Floor animation: raising stairs. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: p_floor.c,v 1.4 1997/02/03 16:47:54 b1 Exp $"; #include "z_zone.h" @@ -216,8 +209,7 @@ void T_MoveFloor(floormove_t* floor) floor->crush,0,floor->direction); if (!(leveltime&7)) - S_StartSound((mobj_t *)&floor->sector->soundorg, - sfx_stnmov); + S_StartSound(&floor->sector->soundorg, sfx_stnmov); if (res == pastdest) { @@ -247,8 +239,7 @@ void T_MoveFloor(floormove_t* floor) } P_RemoveThinker(&floor->thinker); - S_StartSound((mobj_t *)&floor->sector->soundorg, - sfx_pstop); + S_StartSound(&floor->sector->soundorg, sfx_pstop); } } @@ -371,7 +362,7 @@ EV_DoFloor case raiseToTexture: { - int minsize = MAXINT; + int minsize = INT_MAX; side_t* side; floor->direction = 1; @@ -467,8 +458,8 @@ EV_BuildStairs floormove_t* floor; - fixed_t stairsize; - fixed_t speed; + fixed_t stairsize = 0; + fixed_t speed = 0; secnum = -1; rtn = 0; diff --git a/frosted-doom/p_inter.c b/frosted-doom/p_inter.c index eea30f1..1eb58cf 100644 --- a/frosted-doom/p_inter.c +++ b/frosted-doom/p_inter.c @@ -1,29 +1,22 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Handling interactions (i.e., collisions). // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: p_inter.c,v 1.4 1997/02/03 22:45:11 b1 Exp $"; // Data. @@ -31,6 +24,8 @@ rcsid[] = "$Id: p_inter.c,v 1.4 1997/02/03 22:45:11 b1 Exp $"; #include "dstrings.h" #include "sounds.h" +#include "deh_main.h" +#include "deh_misc.h" #include "doomstat.h" #include "m_random.h" @@ -42,9 +37,6 @@ rcsid[] = "$Id: p_inter.c,v 1.4 1997/02/03 22:45:11 b1 Exp $"; #include "s_sound.h" -#ifdef __GNUG__ -#pragma implementation "p_inter.h" -#endif #include "p_inter.h" @@ -81,7 +73,7 @@ P_GiveAmmo if (ammo == am_noammo) return false; - if (ammo < 0 || ammo > NUMAMMO) + if (ammo > NUMAMMO) I_Error ("P_GiveAmmo: bad type %i", ammo); if ( player->ammo[ammo] == player->maxammo[ammo] ) @@ -172,48 +164,50 @@ P_GiveWeapon { boolean gaveammo; boolean gaveweapon; + + if (netgame && (deathmatch!=2) && !dropped ) + { + // leave placed weapons forever on net games + if (player->weaponowned[weapon]) + return false; + + player->bonuscount += BONUSADD; + player->weaponowned[weapon] = true; - if (netgame - && (deathmatch!=2) - && !dropped ) - { - // leave placed weapons forever on net games - if (player->weaponowned[weapon]) - return false; + if (deathmatch) + P_GiveAmmo (player, weaponinfo[weapon].ammo, 5); + else + P_GiveAmmo (player, weaponinfo[weapon].ammo, 2); + player->pendingweapon = weapon; - 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 (player == &players[consoleplayer]) + S_StartSound (NULL, sfx_wpnup); + return false; } if (weaponinfo[weapon].ammo != am_noammo) { - // give one clip with a dropped weapon, - // two clips with a found weapon - if (dropped) - gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1); - else - gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2); + // give one clip with a dropped weapon, + // two clips with a found weapon + if (dropped) + gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1); + else + gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2); } else - gaveammo = false; + { + gaveammo = false; + } if (player->weaponowned[weapon]) - gaveweapon = false; + { + gaveweapon = false; + } else { - gaveweapon = true; - player->weaponowned[weapon] = true; - player->pendingweapon = weapon; + gaveweapon = true; + player->weaponowned[weapon] = true; + player->pendingweapon = weapon; } return (gaveweapon || gaveammo); @@ -368,51 +362,55 @@ P_TouchSpecialThing { // armor case SPR_ARM1: - if (!P_GiveArmor (player, 1)) + if (!P_GiveArmor (player, deh_green_armor_class)) return; - player->message = GOTARMOR; + player->message = DEH_String(GOTARMOR); break; case SPR_ARM2: - if (!P_GiveArmor (player, 2)) + if (!P_GiveArmor (player, deh_blue_armor_class)) return; - player->message = GOTMEGA; + player->message = DEH_String(GOTMEGA); break; // bonus items case SPR_BON1: player->health++; // can go over 100% - if (player->health > 200) - player->health = 200; + if (player->health > deh_max_health) + player->health = deh_max_health; player->mo->health = player->health; - player->message = GOTHTHBONUS; + player->message = DEH_String(GOTHTHBONUS); break; case SPR_BON2: player->armorpoints++; // can go over 100% - if (player->armorpoints > 200) - player->armorpoints = 200; + if (player->armorpoints > deh_max_armor) + player->armorpoints = deh_max_armor; + // deh_green_armor_class only applies to the green armor shirt; + // for the armor helmets, armortype 1 is always used. if (!player->armortype) player->armortype = 1; - player->message = GOTARMBONUS; + player->message = DEH_String(GOTARMBONUS); break; case SPR_SOUL: - player->health += 100; - if (player->health > 200) - player->health = 200; + player->health += deh_soulsphere_health; + if (player->health > deh_max_soulsphere) + player->health = deh_max_soulsphere; player->mo->health = player->health; - player->message = GOTSUPER; + player->message = DEH_String(GOTSUPER); sound = sfx_getpow; break; case SPR_MEGA: if (gamemode != commercial) return; - player->health = 200; + player->health = deh_megasphere_health; player->mo->health = player->health; - P_GiveArmor (player,2); - player->message = GOTMSPHERE; + // We always give armor type 2 for the megasphere; dehacked only + // affects the MegaArmor. + P_GiveArmor (player, 2); + player->message = DEH_String(GOTMSPHERE); sound = sfx_getpow; break; @@ -420,7 +418,7 @@ P_TouchSpecialThing // leave cards for everyone case SPR_BKEY: if (!player->cards[it_bluecard]) - player->message = GOTBLUECARD; + player->message = DEH_String(GOTBLUECARD); P_GiveCard (player, it_bluecard); if (!netgame) break; @@ -428,7 +426,7 @@ P_TouchSpecialThing case SPR_YKEY: if (!player->cards[it_yellowcard]) - player->message = GOTYELWCARD; + player->message = DEH_String(GOTYELWCARD); P_GiveCard (player, it_yellowcard); if (!netgame) break; @@ -436,7 +434,7 @@ P_TouchSpecialThing case SPR_RKEY: if (!player->cards[it_redcard]) - player->message = GOTREDCARD; + player->message = DEH_String(GOTREDCARD); P_GiveCard (player, it_redcard); if (!netgame) break; @@ -444,7 +442,7 @@ P_TouchSpecialThing case SPR_BSKU: if (!player->cards[it_blueskull]) - player->message = GOTBLUESKUL; + player->message = DEH_String(GOTBLUESKUL); P_GiveCard (player, it_blueskull); if (!netgame) break; @@ -452,7 +450,7 @@ P_TouchSpecialThing case SPR_YSKU: if (!player->cards[it_yellowskull]) - player->message = GOTYELWSKUL; + player->message = DEH_String(GOTYELWSKUL); P_GiveCard (player, it_yellowskull); if (!netgame) break; @@ -460,7 +458,7 @@ P_TouchSpecialThing case SPR_RSKU: if (!player->cards[it_redskull]) - player->message = GOTREDSKULL; + player->message = DEH_String(GOTREDSKULL); P_GiveCard (player, it_redskull); if (!netgame) break; @@ -470,7 +468,7 @@ P_TouchSpecialThing case SPR_STIM: if (!P_GiveBody (player, 10)) return; - player->message = GOTSTIM; + player->message = DEH_String(GOTSTIM); break; case SPR_MEDI: @@ -478,9 +476,9 @@ P_TouchSpecialThing return; if (player->health < 25) - player->message = GOTMEDINEED; + player->message = DEH_String(GOTMEDINEED); else - player->message = GOTMEDIKIT; + player->message = DEH_String(GOTMEDIKIT); break; @@ -488,14 +486,14 @@ P_TouchSpecialThing case SPR_PINV: if (!P_GivePower (player, pw_invulnerability)) return; - player->message = GOTINVUL; + player->message = DEH_String(GOTINVUL); sound = sfx_getpow; break; case SPR_PSTR: if (!P_GivePower (player, pw_strength)) return; - player->message = GOTBERSERK; + player->message = DEH_String(GOTBERSERK); if (player->readyweapon != wp_fist) player->pendingweapon = wp_fist; sound = sfx_getpow; @@ -504,28 +502,28 @@ P_TouchSpecialThing case SPR_PINS: if (!P_GivePower (player, pw_invisibility)) return; - player->message = GOTINVIS; + player->message = DEH_String(GOTINVIS); sound = sfx_getpow; break; case SPR_SUIT: if (!P_GivePower (player, pw_ironfeet)) return; - player->message = GOTSUIT; + player->message = DEH_String(GOTSUIT); sound = sfx_getpow; break; case SPR_PMAP: if (!P_GivePower (player, pw_allmap)) return; - player->message = GOTMAP; + player->message = DEH_String(GOTMAP); sound = sfx_getpow; break; case SPR_PVIS: if (!P_GivePower (player, pw_infrared)) return; - player->message = GOTVISOR; + player->message = DEH_String(GOTVISOR); sound = sfx_getpow; break; @@ -541,49 +539,49 @@ P_TouchSpecialThing if (!P_GiveAmmo (player,am_clip,1)) return; } - player->message = GOTCLIP; + player->message = DEH_String(GOTCLIP); break; case SPR_AMMO: if (!P_GiveAmmo (player, am_clip,5)) return; - player->message = GOTCLIPBOX; + player->message = DEH_String(GOTCLIPBOX); break; case SPR_ROCK: if (!P_GiveAmmo (player, am_misl,1)) return; - player->message = GOTROCKET; + player->message = DEH_String(GOTROCKET); break; case SPR_BROK: if (!P_GiveAmmo (player, am_misl,5)) return; - player->message = GOTROCKBOX; + player->message = DEH_String(GOTROCKBOX); break; case SPR_CELL: if (!P_GiveAmmo (player, am_cell,1)) return; - player->message = GOTCELL; + player->message = DEH_String(GOTCELL); break; case SPR_CELP: if (!P_GiveAmmo (player, am_cell,5)) return; - player->message = GOTCELLBOX; + player->message = DEH_String(GOTCELLBOX); break; case SPR_SHEL: if (!P_GiveAmmo (player, am_shell,1)) return; - player->message = GOTSHELLS; + player->message = DEH_String(GOTSHELLS); break; case SPR_SBOX: if (!P_GiveAmmo (player, am_shell,5)) return; - player->message = GOTSHELLBOX; + player->message = DEH_String(GOTSHELLBOX); break; case SPR_BPAK: @@ -595,56 +593,56 @@ P_TouchSpecialThing } for (i=0 ; imessage = GOTBACKPACK; + player->message = DEH_String(GOTBACKPACK); break; // weapons case SPR_BFUG: if (!P_GiveWeapon (player, wp_bfg, false) ) return; - player->message = GOTBFG9000; + player->message = DEH_String(GOTBFG9000); sound = sfx_wpnup; break; case SPR_MGUN: - if (!P_GiveWeapon (player, wp_chaingun, special->flags&MF_DROPPED) ) + if (!P_GiveWeapon (player, wp_chaingun, (special->flags&MF_DROPPED) != 0) ) return; - player->message = GOTCHAINGUN; + player->message = DEH_String(GOTCHAINGUN); sound = sfx_wpnup; break; case SPR_CSAW: if (!P_GiveWeapon (player, wp_chainsaw, false) ) return; - player->message = GOTCHAINSAW; + player->message = DEH_String(GOTCHAINSAW); sound = sfx_wpnup; break; case SPR_LAUN: if (!P_GiveWeapon (player, wp_missile, false) ) return; - player->message = GOTLAUNCHER; + player->message = DEH_String(GOTLAUNCHER); sound = sfx_wpnup; break; case SPR_PLAS: if (!P_GiveWeapon (player, wp_plasma, false) ) return; - player->message = GOTPLASMA; + player->message = DEH_String(GOTPLASMA); sound = sfx_wpnup; break; case SPR_SHOT: - if (!P_GiveWeapon (player, wp_shotgun, special->flags&MF_DROPPED ) ) + if (!P_GiveWeapon (player, wp_shotgun, (special->flags&MF_DROPPED) != 0 ) ) return; - player->message = GOTSHOTGUN; + player->message = DEH_String(GOTSHOTGUN); sound = sfx_wpnup; break; case SPR_SGN2: - if (!P_GiveWeapon (player, wp_supershotgun, special->flags&MF_DROPPED ) ) + if (!P_GiveWeapon (player, wp_supershotgun, (special->flags&MF_DROPPED) != 0 ) ) return; - player->message = GOTSHOTGUN2; + player->message = DEH_String(GOTSHOTGUN2); sound = sfx_wpnup; break; @@ -730,6 +728,12 @@ P_KillMobj // I_StartSound (&actor->r, actor->info->deathsound); + // In Chex Quest, monsters don't drop items. + + if (gameversion == exe_chex) + { + return; + } // Drop stuff. // This determines the kind of object spawned diff --git a/frosted-doom/p_inter.h b/frosted-doom/p_inter.h index 1b1c516..5764d5d 100644 --- a/frosted-doom/p_inter.h +++ b/frosted-doom/p_inter.h @@ -1,32 +1,26 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // // -//----------------------------------------------------------------------------- #ifndef __P_INTER__ #define __P_INTER__ -#ifdef __GNUG__ -#pragma interface -#endif boolean P_GivePower(player_t*, int); @@ -34,8 +28,3 @@ boolean P_GivePower(player_t*, int); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/p_lights.c b/frosted-doom/p_lights.c index 2a0555e..863338d 100644 --- a/frosted-doom/p_lights.c +++ b/frosted-doom/p_lights.c @@ -1,29 +1,22 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Handle Sector base lighting effects. // Muzzle flash? // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: p_lights.c,v 1.5 1997/02/03 22:45:11 b1 Exp $"; #include "z_zone.h" diff --git a/frosted-doom/p_local.h b/frosted-doom/p_local.h index c3e181b..95fa405 100644 --- a/frosted-doom/p_local.h +++ b/frosted-doom/p_local.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Play functions, animation, global header. // -//----------------------------------------------------------------------------- #ifndef __P_LOCAL__ @@ -92,8 +89,8 @@ void P_PlayerThink (player_t* player); // // P_MOBJ // -#define ONFLOORZ MININT -#define ONCEILINGZ MAXINT +#define ONFLOORZ INT_MIN +#define ONCEILINGZ INT_MAX // Time interval for item respawning. #define ITEMQUESIZE 128 @@ -114,6 +111,7 @@ P_SpawnMobj mobjtype_t type ); void P_RemoveMobj (mobj_t* th); +mobj_t* P_SubstNullMobj (mobj_t* th); boolean P_SetMobjState (mobj_t* mobj, statenum_t state); void P_MobjThinker (mobj_t* mobj); @@ -151,7 +149,10 @@ typedef struct } d; } intercept_t; -#define MAXINTERCEPTS 128 +// Extended MAXINTERCEPTS, to allow for intercepts overrun emulation. + +#define MAXINTERCEPTS_ORIGINAL 128 +#define MAXINTERCEPTS (MAXINTERCEPTS_ORIGINAL + 61) extern intercept_t intercepts[MAXINTERCEPTS]; extern intercept_t* intercept_p; @@ -207,6 +208,20 @@ extern fixed_t tmceilingz; extern line_t* ceilingline; +// fraggle: I have increased the size of this buffer. In the original Doom, +// overrunning past this limit caused other bits of memory to be overwritten, +// affecting demo playback. However, in doing so, the limit was still +// exceeded. So we have to support more than 8 specials. +// +// We keep the original limit, to detect what variables in memory were +// overwritten (see SpechitOverrun()) + +#define MAXSPECIALCROSS 20 +#define MAXSPECIALCROSS_ORIGINAL 8 + +extern line_t* spechit[MAXSPECIALCROSS]; +extern int numspechit; + boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y); boolean P_TryMove (mobj_t* thing, fixed_t x, fixed_t y); boolean P_TeleportMove (mobj_t* thing, fixed_t x, fixed_t y); @@ -280,10 +295,3 @@ P_DamageMobj #endif // __P_LOCAL__ -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- - - diff --git a/frosted-doom/p_map.c b/frosted-doom/p_map.c index aba15d8..e371869 100644 --- a/frosted-doom/p_map.c +++ b/frosted-doom/p_map.c @@ -1,37 +1,34 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard, Andrey Budko // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Movement, collision handling. // Shooting and aiming. // -//----------------------------------------------------------------------------- - -static const char -rcsid[] = "$Id: p_map.c,v 1.5 1997/02/03 22:45:11 b1 Exp $"; +#include #include +#include "deh_misc.h" + #include "m_bbox.h" #include "m_random.h" #include "i_system.h" #include "doomdef.h" +#include "m_argv.h" +#include "m_misc.h" #include "p_local.h" #include "s_sound.h" @@ -42,6 +39,26 @@ rcsid[] = "$Id: p_map.c,v 1.5 1997/02/03 22:45:11 b1 Exp $"; // Data. #include "sounds.h" +// Spechit overrun magic value. +// +// This is the value used by PrBoom-plus. I think the value below is +// actually better and works with more demos. However, I think +// it's better for the spechits emulation to be compatible with +// PrBoom-plus, at least so that the big spechits emulation list +// on Doomworld can also be used with Chocolate Doom. + +#define DEFAULT_SPECHIT_MAGIC 0x01C09C98 + +// This is from a post by myk on the Doomworld forums, +// outputted from entryway's spechit_magic generator for +// s205n546.lmp. The _exact_ value of this isn't too +// important; as long as it is in the right general +// range, it will usually work. Otherwise, we can use +// the generator (hacked doom2.exe) and provide it +// with -spechit. + +//#define DEFAULT_SPECHIT_MAGIC 0x84f968e8 + fixed_t tmbbox[4]; mobj_t* tmthing; @@ -64,7 +81,6 @@ line_t* ceilingline; // keep track of special lines as they are hit, // but don't process them until the move is proven valid -#define MAXSPECIALCROSS 8 line_t* spechit[MAXSPECIALCROSS]; int numspechit; @@ -181,6 +197,7 @@ P_TeleportMove // MOVEMENT ITERATOR FUNCTIONS // +static void SpechitOverrun(line_t *ld); // // PIT_CheckLine @@ -239,8 +256,14 @@ boolean PIT_CheckLine (line_t* ld) // if contacted a special line, add it to the list if (ld->special) { - spechit[numspechit] = ld; + spechit[numspechit] = ld; numspechit++; + + // fraggle: spechits overrun emulation code from prboom-plus + if (numspechit > MAXSPECIALCROSS_ORIGINAL) + { + SpechitOverrun(ld); + } } return true; @@ -296,8 +319,8 @@ boolean PIT_CheckThing (mobj_t* thing) if (tmthing->z+tmthing->height < thing->z) return true; // underneath - if (tmthing->target && ( - tmthing->target->type == thing->type || + if (tmthing->target + && (tmthing->target->type == thing->type || (tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER)|| (tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT) ) ) { @@ -305,7 +328,11 @@ boolean PIT_CheckThing (mobj_t* thing) if (thing == tmthing->target) return true; - if (thing->type != MT_PLAYER) + // sdh: Add deh_species_infighting here. We can override the + // "monsters of the same species cant hurt each other" behavior + // through dehacked patches + + if (thing->type != MT_PLAYER && !deh_species_infighting) { // Explode, but do no damage. // Let players missile other players. @@ -839,14 +866,16 @@ PTR_AimTraverse (intercept_t* in) dist = FixedMul (attackrange, in->frac); - if (li->frontsector->floorheight != li->backsector->floorheight) + if (li->backsector == NULL + || li->frontsector->floorheight != li->backsector->floorheight) { slope = FixedDiv (openbottom - shootz , dist); if (slope > bottomslope) bottomslope = slope; } - if (li->frontsector->ceilingheight != li->backsector->ceilingheight) + if (li->backsector == NULL + || li->frontsector->ceilingheight != li->backsector->ceilingheight) { slope = FixedDiv (opentop - shootz , dist); if (slope < topslope) @@ -927,19 +956,35 @@ boolean PTR_ShootTraverse (intercept_t* in) dist = FixedMul (attackrange, in->frac); - if (li->frontsector->floorheight != li->backsector->floorheight) - { - slope = FixedDiv (openbottom - shootz , dist); - if (slope > aimslope) - goto hitline; - } - - if (li->frontsector->ceilingheight != li->backsector->ceilingheight) - { - slope = FixedDiv (opentop - shootz , dist); - if (slope < aimslope) - goto hitline; - } + // e6y: emulation of missed back side on two-sided lines. + // backsector can be NULL when emulating missing back side. + + if (li->backsector == NULL) + { + slope = FixedDiv (openbottom - shootz , dist); + if (slope > aimslope) + goto hitline; + + slope = FixedDiv (opentop - shootz , dist); + if (slope < aimslope) + goto hitline; + } + else + { + if (li->frontsector->floorheight != li->backsector->floorheight) + { + slope = FixedDiv (openbottom - shootz , dist); + if (slope > aimslope) + goto hitline; + } + + if (li->frontsector->ceilingheight != li->backsector->ceilingheight) + { + slope = FixedDiv (opentop - shootz , dist); + if (slope < aimslope) + goto hitline; + } + } // shot continues return true; @@ -1027,6 +1072,8 @@ P_AimLineAttack { fixed_t x2; fixed_t y2; + + t1 = P_SubstNullMobj(t1); angle >>= ANGLETOFINESHIFT; shootthing = t1; @@ -1337,3 +1384,65 @@ P_ChangeSector return nofit; } +// Code to emulate the behavior of Vanilla Doom when encountering an overrun +// of the spechit array. This is by Andrey Budko (e6y) and comes from his +// PrBoom plus port. A big thanks to Andrey for this. + +static void SpechitOverrun(line_t *ld) +{ + static unsigned int baseaddr = 0; + unsigned int addr; + + if (baseaddr == 0) + { + int p; + + // This is the first time we have had an overrun. Work out + // what base address we are going to use. + // Allow a spechit value to be specified on the command line. + + //! + // @category compat + // @arg + // + // 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; + } +} + diff --git a/frosted-doom/p_maputl.c b/frosted-doom/p_maputl.c index 597b19c..916f2b6 100644 --- a/frosted-doom/p_maputl.c +++ b/frosted-doom/p_maputl.c @@ -1,20 +1,17 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// Copyright(C) 2005, 2006 Andrey Budko // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Movement/collision utility functions, @@ -22,10 +19,7 @@ // 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 @@ -34,6 +28,7 @@ rcsid[] = "$Id: p_maputl.c,v 1.5 1997/02/03 22:45:11 b1 Exp $"; #include "m_bbox.h" #include "doomdef.h" +#include "doomstat.h" #include "p_local.h" @@ -111,8 +106,8 @@ P_BoxOnLineSide ( fixed_t* tmbox, line_t* ld ) { - int p1; - int p2; + int p1 = 0; + int p2 = 0; switch (ld->slopetype) { @@ -548,6 +543,8 @@ divline_t trace; boolean earlyout; int ptflags; +static void InterceptsOverrun(int num_intercepts, intercept_t *intercept); + // // PIT_AddLineIntercepts. // Looks for lines in the given block @@ -603,6 +600,7 @@ PIT_AddLineIntercepts (line_t* ld) intercept_p->frac = frac; intercept_p->isaline = true; intercept_p->d.line = ld; + InterceptsOverrun(intercept_p - intercepts, intercept_p); intercept_p++; return true; // continue @@ -668,6 +666,7 @@ boolean PIT_AddThingIntercepts (mobj_t* thing) intercept_p->frac = frac; intercept_p->isaline = false; intercept_p->d.thing = thing; + InterceptsOverrun(intercept_p - intercepts, intercept_p); intercept_p++; return true; // keep going @@ -695,7 +694,7 @@ P_TraverseIntercepts while (count--) { - dist = MAXINT; + dist = INT_MAX; for (scan = intercepts ; scanfrac < dist) @@ -723,13 +722,132 @@ P_TraverseIntercepts if ( !func (in) ) return false; // don't bother going farther - in->frac = MAXINT; + in->frac = INT_MAX; } return true; // everything was traversed } +extern fixed_t bulletslope; +// Intercepts Overrun emulation, from PrBoom-plus. +// Thanks to Andrey Budko (entryway) for researching this and his +// implementation of Intercepts Overrun emulation in PrBoom-plus +// which this is based on. + +typedef struct +{ + int len; + void *addr; + boolean int16_array; +} intercepts_overrun_t; + +// Intercepts memory table. This is where various variables are located +// in memory in Vanilla Doom. When the intercepts table overflows, we +// need to write to them. +// +// Almost all of the values to overwrite are 32-bit integers, except for +// playerstarts, which is effectively an array of 16-bit integers and +// must be treated differently. + +static intercepts_overrun_t intercepts_overrun[] = +{ + {4, NULL, false}, + {4, NULL, /* &earlyout, */ false}, + {4, NULL, /* &intercept_p, */ false}, + {4, &lowfloor, false}, + {4, &openbottom, false}, + {4, &opentop, false}, + {4, &openrange, false}, + {4, NULL, false}, + {120, NULL, /* &activeplats, */ false}, + {8, NULL, false}, + {4, &bulletslope, false}, + {4, NULL, /* &swingx, */ false}, + {4, NULL, /* &swingy, */ false}, + {4, NULL, false}, + {40, &playerstarts, true}, + {4, NULL, /* &blocklinks, */ false}, + {4, &bmapwidth, false}, + {4, NULL, /* &blockmap, */ false}, + {4, &bmaporgx, false}, + {4, &bmaporgy, false}, + {4, NULL, /* &blockmaplump, */ false}, + {4, &bmapheight, false}, + {0, NULL, false}, +}; + +// Overwrite a specific memory location with a value. + +static void InterceptsMemoryOverrun(int location, int value) +{ + int i, offset; + int index; + void *addr; + + i = 0; + offset = 0; + + // Search down the array until we find the right entry + + while (intercepts_overrun[i].len != 0) + { + if (offset + intercepts_overrun[i].len > location) + { + addr = intercepts_overrun[i].addr; + + // Write the value to the memory location. + // 16-bit and 32-bit values are written differently. + + if (addr != NULL) + { + if (intercepts_overrun[i].int16_array) + { + index = (location - offset) / 2; + ((short *) addr)[index] = value & 0xffff; + ((short *) addr)[index + 1] = (value >> 16) & 0xffff; + } + else + { + index = (location - offset) / 4; + ((int *) addr)[index] = value; + } + } + + break; + } + + offset += intercepts_overrun[i].len; + ++i; + } +} + +// Emulate overruns of the intercepts[] array. + +static void InterceptsOverrun(int num_intercepts, intercept_t *intercept) +{ + int location; + + if (num_intercepts <= MAXINTERCEPTS_ORIGINAL) + { + // No overrun + + return; + } + + location = (num_intercepts - MAXINTERCEPTS_ORIGINAL - 1) * 12; + + // Overwrite memory that is overwritten in Vanilla Doom, using + // the values from the intercept structure. + // + // Note: the ->d.{thing,line} member should really have its + // address translated into the correct address value for + // Vanilla Doom. + + InterceptsMemoryOverrun(location, intercept->frac); + InterceptsMemoryOverrun(location + 4, intercept->isaline); + InterceptsMemoryOverrun(location + 8, (int) intercept->d.thing); +} // diff --git a/frosted-doom/p_mobj.c b/frosted-doom/p_mobj.c index 209d161..a3b9c43 100644 --- a/frosted-doom/p_mobj.c +++ b/frosted-doom/p_mobj.c @@ -1,28 +1,22 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Moving object handling. Spawn functions. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: p_mobj.c,v 1.5 1997/02/03 22:45:12 b1 Exp $"; +#include #include "i_system.h" #include "z_zone.h" @@ -288,7 +282,29 @@ void P_ZMovement (mobj_t* mo) // Note (id): // somebody left this after the setting momz to 0, // kinda useless there. - if (mo->flags & MF_SKULLFLY) + // + // cph - This was the a bug in the linuxdoom-1.10 source which + // caused it not to sync Doom 2 v1.9 demos. Someone + // added the above comment and moved up the following code. So + // demos would desync in close lost soul fights. + // Note that this only applies to original Doom 1 or Doom2 demos - not + // Final Doom and Ultimate Doom. So we test demo_compatibility *and* + // gamemission. (Note we assume that Doom1 is always Ult Doom, which + // seems to hold for most published demos.) + // + // fraggle - cph got the logic here slightly wrong. There are three + // versions of Doom 1.9: + // + // * The version used in registered doom 1.9 + doom2 - no bounce + // * The version used in ultimate doom - has bounce + // * The version used in final doom - has bounce + // + // So we need to check that this is either retail or commercial + // (but not doom2) + + int correct_lost_soul_bounce = gameversion >= exe_ultimate; + + if (correct_lost_soul_bounce && mo->flags & MF_SKULLFLY) { // the skull slammed into something mo->momz = -mo->momz; @@ -310,6 +326,16 @@ void P_ZMovement (mobj_t* mo) } mo->z = mo->floorz; + + // cph 2001/05/26 - + // See lost soul bouncing comment above. We need this here for bug + // compatibility with original Doom2 v1.9 - if a soul is charging and + // hit by a raising floor this incorrectly reverses its Y momentum. + // + + if (!correct_lost_soul_bounce && mo->flags & MF_SKULLFLY) + mo->momz = -mo->momz; + if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) ) { @@ -458,7 +484,7 @@ void P_MobjThinker (mobj_t* mobj) mobj->movecount++; - if (mobj->movecount < 12*35) + if (mobj->movecount < 12*TICRATE) return; if ( leveltime&31 ) @@ -596,7 +622,7 @@ void P_RespawnSpecials (void) return; // wait at least 30 seconds - if (leveltime - itemrespawntime[iquetail] < 30*35) + if (leveltime - itemrespawntime[iquetail] < 30*TICRATE) return; mthing = &itemrespawnque[iquetail]; @@ -650,6 +676,11 @@ void P_SpawnPlayer (mapthing_t* mthing) int i; + if (mthing->type == 0) + { + return; + } + // not playing? if (!playeringame[mthing->type-1]) return; @@ -724,6 +755,14 @@ void P_SpawnMapThing (mapthing_t* mthing) } return; } + + if (mthing->type <= 0) + { + // Thing type 0 is actually "player -1 start". + // For some reason, Vanilla Doom accepts/ignores this. + + return; + } // check for players specially if (mthing->type <= 4) @@ -881,6 +920,28 @@ void P_CheckMissileSpawn (mobj_t* th) P_ExplodeMissile (th); } +// Certain functions assume that a mobj_t pointer is non-NULL, +// causing a crash in some situations where it is NULL. Vanilla +// Doom did not crash because of the lack of proper memory +// protection. This function substitutes NULL pointers for +// pointers to a dummy mobj, to avoid a crash. + +mobj_t *P_SubstNullMobj(mobj_t *mobj) +{ + if (mobj == NULL) + { + static mobj_t dummy_mobj; + + dummy_mobj.x = 0; + dummy_mobj.y = 0; + dummy_mobj.z = 0; + dummy_mobj.flags = 0; + + mobj = &dummy_mobj; + } + + return mobj; +} // // P_SpawnMissile @@ -903,7 +964,7 @@ P_SpawnMissile S_StartSound (th, th->info->seesound); th->target = source; // where it came from - an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y); + an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y); // fuzzy player if (dest->flags & MF_SHADOW) diff --git a/frosted-doom/p_mobj.h b/frosted-doom/p_mobj.h index 75d368a..90ed764 100644 --- a/frosted-doom/p_mobj.h +++ b/frosted-doom/p_mobj.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Map Objects, MObj, definition and handling. // -//----------------------------------------------------------------------------- #ifndef __P_MOBJ__ @@ -41,9 +38,6 @@ -#ifdef __GNUG__ -#pragma interface -#endif @@ -288,8 +282,3 @@ typedef struct mobj_s #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/p_plats.c b/frosted-doom/p_plats.c index 47150f1..9e773d5 100644 --- a/frosted-doom/p_plats.c +++ b/frosted-doom/p_plats.c @@ -1,29 +1,22 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Plats (i.e. elevator platforms) code, raising/lowering. // -//----------------------------------------------------------------------------- - -static const char -rcsid[] = "$Id: p_plats.c,v 1.5 1997/02/03 22:45:12 b1 Exp $"; +#include #include "i_system.h" #include "z_zone.h" @@ -65,8 +58,7 @@ void T_PlatRaise(plat_t* plat) || plat->type == raiseToNearestAndChange) { if (!(leveltime&7)) - S_StartSound((mobj_t *)&plat->sector->soundorg, - sfx_stnmov); + S_StartSound(&plat->sector->soundorg, sfx_stnmov); } @@ -74,8 +66,7 @@ void T_PlatRaise(plat_t* plat) { plat->count = plat->wait; plat->status = down; - S_StartSound((mobj_t *)&plat->sector->soundorg, - sfx_pstart); + S_StartSound(&plat->sector->soundorg, sfx_pstart); } else { @@ -83,8 +74,7 @@ void T_PlatRaise(plat_t* plat) { plat->count = plat->wait; plat->status = waiting; - S_StartSound((mobj_t *)&plat->sector->soundorg, - sfx_pstop); + S_StartSound(&plat->sector->soundorg, sfx_pstop); switch(plat->type) { @@ -112,7 +102,7 @@ void T_PlatRaise(plat_t* plat) { plat->count = plat->wait; plat->status = waiting; - S_StartSound((mobj_t *)&plat->sector->soundorg,sfx_pstop); + S_StartSound(&plat->sector->soundorg,sfx_pstop); } break; @@ -123,7 +113,7 @@ void T_PlatRaise(plat_t* plat) plat->status = up; else plat->status = down; - S_StartSound((mobj_t *)&plat->sector->soundorg,sfx_pstart); + S_StartSound(&plat->sector->soundorg,sfx_pstart); } case in_stasis: break; @@ -191,7 +181,7 @@ EV_DoPlat // NO MORE DAMAGE, IF APPLICABLE sec->special = 0; - S_StartSound((mobj_t *)&sec->soundorg,sfx_stnmov); + S_StartSound(&sec->soundorg,sfx_stnmov); break; case raiseAndChange: @@ -201,7 +191,7 @@ EV_DoPlat plat->wait = 0; plat->status = up; - S_StartSound((mobj_t *)&sec->soundorg,sfx_stnmov); + S_StartSound(&sec->soundorg,sfx_stnmov); break; case downWaitUpStay: @@ -212,9 +202,9 @@ EV_DoPlat plat->low = sec->floorheight; plat->high = sec->floorheight; - plat->wait = 35*PLATWAIT; + plat->wait = TICRATE*PLATWAIT; plat->status = down; - S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart); + S_StartSound(&sec->soundorg,sfx_pstart); break; case blazeDWUS: @@ -225,9 +215,9 @@ EV_DoPlat plat->low = sec->floorheight; plat->high = sec->floorheight; - plat->wait = 35*PLATWAIT; + plat->wait = TICRATE*PLATWAIT; plat->status = down; - S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart); + S_StartSound(&sec->soundorg,sfx_pstart); break; case perpetualRaise: @@ -242,10 +232,10 @@ EV_DoPlat if (plat->high < sec->floorheight) plat->high = sec->floorheight; - plat->wait = 35*PLATWAIT; + plat->wait = TICRATE*PLATWAIT; plat->status = P_Random()&1; - S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart); + S_StartSound(&sec->soundorg,sfx_pstart); break; } P_AddActivePlat(plat); diff --git a/frosted-doom/p_pspr.c b/frosted-doom/p_pspr.c index 2ac53b8..e4774c7 100644 --- a/frosted-doom/p_pspr.c +++ b/frosted-doom/p_pspr.c @@ -1,33 +1,27 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Weapon sprite animation, weapon objects. // Action functions for weapons. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: p_pspr.c,v 1.5 1997/02/03 22:45:12 b1 Exp $"; #include "doomdef.h" #include "d_event.h" +#include "deh_misc.h" #include "m_random.h" #include "p_local.h" @@ -48,9 +42,6 @@ rcsid[] = "$Id: p_pspr.c,v 1.5 1997/02/03 22:45:12 b1 Exp $"; #define WEAPONTOP 32*FRACUNIT -// plasma cells for a bfg attack -#define BFGCELLS 40 - // // P_SetPsprite @@ -167,7 +158,7 @@ boolean P_CheckAmmo (player_t* player) // Minimal amount for one shot varies. if (player->readyweapon == wp_bfg) - count = BFGCELLS; + count = deh_bfg_cells_per_shot; else if (player->readyweapon == wp_supershotgun) count = 2; // Double barrel. else @@ -527,7 +518,7 @@ A_Saw linetarget->x, linetarget->y); if (angle - player->mo->angle > ANG180) { - if (angle - player->mo->angle < -ANG90/20) + if ((signed int) (angle - player->mo->angle) < -ANG90/20) player->mo->angle = angle + ANG90/21; else player->mo->angle -= ANG90/20; @@ -542,6 +533,23 @@ A_Saw player->mo->flags |= MF_JUSTATTACKED; } +// Doom does not check the bounds of the ammo array. As a result, +// it is possible to use an ammo type > 4 that overflows into the +// maxammo array and affects that instead. Through dehacked, for +// example, it is possible to make a weapon that decreases the max +// number of ammo for another weapon. Emulate this. + +static void DecreaseAmmo(player_t *player, int ammonum, int amount) +{ + if (ammonum < NUMAMMO) + { + player->ammo[ammonum] -= amount; + } + else + { + player->maxammo[ammonum - NUMAMMO] -= amount; + } +} // @@ -552,7 +560,7 @@ A_FireMissile ( player_t* player, pspdef_t* psp ) { - player->ammo[weaponinfo[player->readyweapon].ammo]--; + DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1); P_SpawnPlayerMissile (player->mo, MT_ROCKET); } @@ -565,7 +573,8 @@ A_FireBFG ( player_t* player, pspdef_t* psp ) { - player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS; + DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, + deh_bfg_cells_per_shot); P_SpawnPlayerMissile (player->mo, MT_BFG); } @@ -579,7 +588,7 @@ A_FirePlasma ( player_t* player, pspdef_t* psp ) { - player->ammo[weaponinfo[player->readyweapon].ammo]--; + DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1); P_SetPsprite (player, ps_flash, @@ -651,7 +660,7 @@ A_FirePistol S_StartSound (player->mo, sfx_pistol); P_SetMobjState (player->mo, S_PLAY_ATK2); - player->ammo[weaponinfo[player->readyweapon].ammo]--; + DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1); P_SetPsprite (player, ps_flash, @@ -675,7 +684,7 @@ A_FireShotgun S_StartSound (player->mo, sfx_shotgn); P_SetMobjState (player->mo, S_PLAY_ATK2); - player->ammo[weaponinfo[player->readyweapon].ammo]--; + DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1); P_SetPsprite (player, ps_flash, @@ -705,7 +714,7 @@ A_FireShotgun2 S_StartSound (player->mo, sfx_dshtgn); P_SetMobjState (player->mo, S_PLAY_ATK2); - player->ammo[weaponinfo[player->readyweapon].ammo]-=2; + DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 2); P_SetPsprite (player, ps_flash, @@ -740,7 +749,7 @@ A_FireCGun return; P_SetMobjState (player->mo, S_PLAY_ATK2); - player->ammo[weaponinfo[player->readyweapon].ammo]--; + DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1); P_SetPsprite (player, ps_flash, diff --git a/frosted-doom/p_pspr.h b/frosted-doom/p_pspr.h index b76b6cc..f98fe35 100644 --- a/frosted-doom/p_pspr.h +++ b/frosted-doom/p_pspr.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Sprite animation. // -//----------------------------------------------------------------------------- #ifndef __P_PSPR__ @@ -38,9 +35,6 @@ // and the Frame Sequence table. #include "info.h" -#ifdef __GNUG__ -#pragma interface -#endif // @@ -75,8 +69,3 @@ typedef struct } pspdef_t; #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/p_saveg.c b/frosted-doom/p_saveg.c index 4500a54..5cb8196 100644 --- a/frosted-doom/p_saveg.c +++ b/frosted-doom/p_saveg.c @@ -1,45 +1,1438 @@ -// 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. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: p_tick.c,v 1.4 1997/02/03 16:47:55 b1 Exp $"; +#include +#include + +#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" -byte* save_p; +#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; ix = 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; ipowers[i] = saveg_read32(); + } + + // boolean cards[NUMCARDS]; + for (i=0; icards[i] = saveg_read32(); + } + + // boolean backpack; + str->backpack = saveg_read32(); + + // int frags[MAXPLAYERS]; + for (i=0; ifrags[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; iweaponowned[i] = saveg_read32(); + } + + // int ammo[NUMAMMO]; + for (i=0; iammo[i] = saveg_read32(); + } + + // int maxammo[NUMAMMO]; + for (i=0; imaxammo[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; ipsprites[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; ipowers[i]); + } + + // boolean cards[NUMCARDS]; + for (i=0; icards[i]); + } + + // boolean backpack; + saveg_write32(str->backpack); + + // int frags[MAXPLAYERS]; + for (i=0; ifrags[i]); + } + + // weapontype_t readyweapon; + saveg_write_enum(str->readyweapon); + + // weapontype_t pendingweapon; + saveg_write_enum(str->pendingweapon); + + // boolean weaponowned[NUMWEAPONS]; + for (i=0; iweaponowned[i]); + } + + // int ammo[NUMAMMO]; + for (i=0; iammo[i]); + } + + // int maxammo[NUMAMMO]; + for (i=0; imaxammo[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; ipsprites[i]); + } + + // boolean didsecret; + saveg_write32(str->didsecret); +} + + +// +// ceiling_t +// + +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); +} + +// +// vldoor_t +// + +static void saveg_read_vldoor_t(vldoor_t *str) +{ + int sector; + + // thinker_t thinker; + saveg_read_thinker_t(&str->thinker); + + // 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); + + // 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> 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; ipsprites[j].state) - { - dest->psprites[j].state - = (state_t *)(dest->psprites[j].state-states); - } - } + saveg_write_player_t(&players[i]); } } @@ -79,31 +1460,20 @@ void P_ArchivePlayers (void) void P_UnArchivePlayers (void) { int i; - int j; for (i=0 ; ifloorheight >> 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 ; iflags; - *put++ = li->special; - *put++ = li->tag; + saveg_write16(li->flags); + saveg_write16(li->special); + saveg_write16(li->tag); for (j=0 ; j<2 ; j++) { if (li->sidenum[j] == -1) @@ -148,15 +1515,13 @@ void P_ArchiveWorld (void) si = &sides[li->sidenum[j]]; - *put++ = si->textureoffset >> FRACBITS; - *put++ = si->rowoffset >> FRACBITS; - *put++ = si->toptexture; - *put++ = si->bottomtexture; - *put++ = si->midtexture; + saveg_write16(si->textureoffset >> FRACBITS); + saveg_write16(si->rowoffset >> FRACBITS); + saveg_write16(si->toptexture); + saveg_write16(si->bottomtexture); + saveg_write16(si->midtexture); } } - - save_p = (byte *)put; } @@ -171,20 +1536,17 @@ void P_UnArchiveWorld (void) sector_t* sec; line_t* li; side_t* si; - short* get; - - get = (short *)save_p; // do sectors for (i=0, sec = sectors ; ifloorheight = *get++ << FRACBITS; - sec->ceilingheight = *get++ << FRACBITS; - sec->floorpic = *get++; - sec->ceilingpic = *get++; - sec->lightlevel = *get++; - sec->special = *get++; // needed? - sec->tag = *get++; // needed? + sec->floorheight = saveg_read16() << FRACBITS; + sec->ceilingheight = saveg_read16() << FRACBITS; + sec->floorpic = saveg_read16(); + sec->ceilingpic = saveg_read16(); + sec->lightlevel = saveg_read16(); + sec->special = saveg_read16(); // needed? + sec->tag = saveg_read16(); // needed? sec->specialdata = 0; sec->soundtarget = 0; } @@ -192,22 +1554,21 @@ void P_UnArchiveWorld (void) // do lines for (i=0, li = lines ; iflags = *get++; - li->special = *get++; - li->tag = *get++; + li->flags = saveg_read16(); + li->special = saveg_read16(); + li->tag = saveg_read16(); for (j=0 ; j<2 ; j++) { if (li->sidenum[j] == -1) continue; si = &sides[li->sidenum[j]]; - si->textureoffset = *get++ << FRACBITS; - si->rowoffset = *get++ << FRACBITS; - si->toptexture = *get++; - si->bottomtexture = *get++; - si->midtexture = *get++; + si->textureoffset = saveg_read16() << FRACBITS; + si->rowoffset = saveg_read16() << FRACBITS; + si->toptexture = saveg_read16(); + si->bottomtexture = saveg_read16(); + si->midtexture = saveg_read16(); } } - save_p = (byte *)get; } @@ -225,29 +1586,22 @@ typedef enum } thinkerclass_t; - // // P_ArchiveThinkers // void P_ArchiveThinkers (void) { thinker_t* th; - mobj_t* mobj; - + // save off the current thinkers for (th = thinkercap.next ; th != &thinkercap ; th=th->next) { if (th->function.acp1 == (actionf_p1)P_MobjThinker) { - *save_p++ = tc_mobj; - PADSAVEP(); - mobj = (mobj_t *)save_p; - memcpy (mobj, th, sizeof(*mobj)); - save_p += sizeof(*mobj); - mobj->state = (state_t *)(mobj->state - states); - - if (mobj->player) - mobj->player = (player_t *)((mobj->player-players) + 1); + saveg_write8(tc_mobj); + saveg_write_pad(); + saveg_write_mobj_t((mobj_t *) th); + continue; } @@ -255,7 +1609,7 @@ void P_ArchiveThinkers (void) } // add a terminating marker - *save_p++ = tc_end; + saveg_write8(tc_end); } @@ -284,28 +1638,23 @@ void P_UnArchiveThinkers (void) currentthinker = next; } P_InitThinkers (); - + // read in saved thinkers while (1) { - tclass = *save_p++; + tclass = saveg_read8(); switch (tclass) { case tc_end: return; // end of list case tc_mobj: - PADSAVEP(); + saveg_read_pad(); mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL); - memcpy (mobj, save_p, sizeof(*mobj)); - save_p += sizeof(*mobj); - mobj->state = &states[(int)mobj->state]; + saveg_read_mobj_t(mobj); + mobj->target = NULL; - if (mobj->player) - { - mobj->player = &players[(int)mobj->player-1]; - mobj->player->mo = mobj; - } + mobj->tracer = NULL; P_SetThingPosition (mobj); mobj->info = &mobjinfo[mobj->type]; mobj->floorz = mobj->subsector->sector->floorheight; @@ -313,7 +1662,7 @@ void P_UnArchiveThinkers (void) mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker; P_AddThinker (&mobj->thinker); break; - + default: I_Error ("Unknown tclass %i in savegame",tclass); } @@ -355,13 +1704,6 @@ enum void P_ArchiveSpecials (void) { thinker_t* th; - ceiling_t* ceiling; - vldoor_t* door; - floormove_t* floor; - plat_t* plat; - lightflash_t* flash; - strobe_t* strobe; - glow_t* glow; int i; // save off the current thinkers @@ -375,96 +1717,72 @@ void P_ArchiveSpecials (void) if (isector = (sector_t *)(ceiling->sector - sectors); + saveg_write8(tc_ceiling); + saveg_write_pad(); + saveg_write_ceiling_t((ceiling_t *) th); } continue; } if (th->function.acp1 == (actionf_p1)T_MoveCeiling) { - *save_p++ = tc_ceiling; - PADSAVEP(); - ceiling = (ceiling_t *)save_p; - memcpy (ceiling, th, sizeof(*ceiling)); - save_p += sizeof(*ceiling); - ceiling->sector = (sector_t *)(ceiling->sector - sectors); + saveg_write8(tc_ceiling); + saveg_write_pad(); + saveg_write_ceiling_t((ceiling_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_VerticalDoor) { - *save_p++ = tc_door; - PADSAVEP(); - door = (vldoor_t *)save_p; - memcpy (door, th, sizeof(*door)); - save_p += sizeof(*door); - door->sector = (sector_t *)(door->sector - sectors); + saveg_write8(tc_door); + saveg_write_pad(); + saveg_write_vldoor_t((vldoor_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_MoveFloor) { - *save_p++ = tc_floor; - PADSAVEP(); - floor = (floormove_t *)save_p; - memcpy (floor, th, sizeof(*floor)); - save_p += sizeof(*floor); - floor->sector = (sector_t *)(floor->sector - sectors); + saveg_write8(tc_floor); + saveg_write_pad(); + saveg_write_floormove_t((floormove_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_PlatRaise) { - *save_p++ = tc_plat; - PADSAVEP(); - plat = (plat_t *)save_p; - memcpy (plat, th, sizeof(*plat)); - save_p += sizeof(*plat); - plat->sector = (sector_t *)(plat->sector - sectors); + saveg_write8(tc_plat); + saveg_write_pad(); + saveg_write_plat_t((plat_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_LightFlash) { - *save_p++ = tc_flash; - PADSAVEP(); - flash = (lightflash_t *)save_p; - memcpy (flash, th, sizeof(*flash)); - save_p += sizeof(*flash); - flash->sector = (sector_t *)(flash->sector - sectors); + saveg_write8(tc_flash); + saveg_write_pad(); + saveg_write_lightflash_t((lightflash_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_StrobeFlash) { - *save_p++ = tc_strobe; - PADSAVEP(); - strobe = (strobe_t *)save_p; - memcpy (strobe, th, sizeof(*strobe)); - save_p += sizeof(*strobe); - strobe->sector = (sector_t *)(strobe->sector - sectors); + saveg_write8(tc_strobe); + saveg_write_pad(); + saveg_write_strobe_t((strobe_t *) th); continue; } if (th->function.acp1 == (actionf_p1)T_Glow) { - *save_p++ = tc_glow; - PADSAVEP(); - glow = (glow_t *)save_p; - memcpy (glow, th, sizeof(*glow)); - save_p += sizeof(*glow); - glow->sector = (sector_t *)(glow->sector - sectors); + saveg_write8(tc_glow); + saveg_write_pad(); + saveg_write_glow_t((glow_t *) th); continue; } } // add a terminating marker - *save_p++ = tc_endspecials; + saveg_write8(tc_endspecials); } @@ -487,18 +1805,17 @@ void P_UnArchiveSpecials (void) // read in saved thinkers while (1) { - tclass = *save_p++; + tclass = saveg_read8(); + switch (tclass) { case tc_endspecials: return; // end of list case tc_ceiling: - PADSAVEP(); + saveg_read_pad(); ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVEL, NULL); - memcpy (ceiling, save_p, sizeof(*ceiling)); - save_p += sizeof(*ceiling); - ceiling->sector = §ors[(int)ceiling->sector]; + saveg_read_ceiling_t(ceiling); ceiling->sector->specialdata = ceiling; if (ceiling->thinker.function.acp1) @@ -509,33 +1826,27 @@ void P_UnArchiveSpecials (void) break; case tc_door: - PADSAVEP(); + saveg_read_pad(); door = Z_Malloc (sizeof(*door), PU_LEVEL, NULL); - memcpy (door, save_p, sizeof(*door)); - save_p += sizeof(*door); - door->sector = §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) @@ -546,31 +1857,25 @@ void P_UnArchiveSpecials (void) break; case tc_flash: - PADSAVEP(); + saveg_read_pad(); flash = Z_Malloc (sizeof(*flash), PU_LEVEL, NULL); - memcpy (flash, save_p, sizeof(*flash)); - save_p += sizeof(*flash); - flash->sector = §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; diff --git a/frosted-doom/p_saveg.h b/frosted-doom/p_saveg.h index 4caf6ed..2d7beba 100644 --- a/frosted-doom/p_saveg.h +++ b/frosted-doom/p_saveg.h @@ -1,33 +1,48 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Savegame I/O, archiving, persistence. // -//----------------------------------------------------------------------------- #ifndef __P_SAVEG__ #define __P_SAVEG__ +#include -#ifdef __GNUG__ -#pragma interface -#endif +// maximum size of a savegame description +#define SAVESTRINGSIZE 24 + +// temporary filename to use while saving. + +char *P_TempSaveGameFile(void); + +// filename to use for a savegame slot + +char *P_SaveGameFile(int slot); + +// Savegame file header read/write functions + +boolean P_ReadSaveGameHeader(void); +void P_WriteSaveGameHeader(char *description); + +// Savegame end-of-file read/write functions + +boolean P_ReadSaveGameEOF(void); +void P_WriteSaveGameEOF(void); // Persistent storage/archiving. // These are the load / save game routines. @@ -40,12 +55,8 @@ void P_UnArchiveThinkers (void); void P_ArchiveSpecials (void); void P_UnArchiveSpecials (void); -extern byte* save_p; +extern FILE *save_stream; +extern boolean savegame_error; #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/p_setup.c b/frosted-doom/p_setup.c index e5d3667..00306e8 100644 --- a/frosted-doom/p_setup.c +++ b/frosted-doom/p_setup.c @@ -1,36 +1,31 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Do all the WAD I/O, get map description, // set up initial state and misc. LUTs. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: p_setup.c,v 1.5 1997/02/03 22:45:12 b1 Exp $"; #include #include "z_zone.h" -#include "m_swap.h" +#include "deh_main.h" +#include "i_swap.h" +#include "m_argv.h" #include "m_bbox.h" #include "g_game.h" @@ -74,6 +69,7 @@ line_t* lines; int numsides; side_t* sides; +static int totallines; // BLOCKMAP // Created from axis aligned bounding box @@ -134,7 +130,7 @@ void P_LoadVertexes (int lump) vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0); // Load data into cache. - data = W_CacheLumpNum (lump,PU_STATIC); + data = W_CacheLumpNum (lump, PU_STATIC); ml = (mapvertex_t *)data; li = vertexes; @@ -148,10 +144,27 @@ void P_LoadVertexes (int lump) } // Free buffer memory. - Z_Free (data); + W_ReleaseLumpNum(lump); } +// +// GetSectorAtNullAddress +// +sector_t* GetSectorAtNullAddress(void) +{ + static boolean null_sector_is_initialized = false; + static sector_t null_sector; + if (!null_sector_is_initialized) + { + memset(&null_sector, 0, sizeof(null_sector)); + I_GetMemoryValue(0, &null_sector.floorheight, 4); + I_GetMemoryValue(4, &null_sector.ceilingheight, 4); + null_sector_is_initialized = true; + } + + return &null_sector; +} // // P_LoadSegs @@ -165,6 +178,7 @@ void P_LoadSegs (int lump) line_t* ldef; int linedef; int side; + int sidenum; numsegs = W_LumpLength (lump) / sizeof(mapseg_t); segs = Z_Malloc (numsegs*sizeof(seg_t),PU_LEVEL,0); @@ -177,7 +191,7 @@ void P_LoadSegs (int lump) { li->v1 = &vertexes[SHORT(ml->v1)]; li->v2 = &vertexes[SHORT(ml->v2)]; - + li->angle = (SHORT(ml->angle))<<16; li->offset = (SHORT(ml->offset))<<16; linedef = SHORT(ml->linedef); @@ -186,13 +200,33 @@ void P_LoadSegs (int lump) side = SHORT(ml->side); li->sidedef = &sides[ldef->sidenum[side]]; li->frontsector = sides[ldef->sidenum[side]].sector; - if (ldef-> flags & ML_TWOSIDED) - li->backsector = sides[ldef->sidenum[side^1]].sector; - else + + if (ldef-> flags & ML_TWOSIDED) + { + sidenum = ldef->sidenum[side ^ 1]; + + // If the sidenum is out of range, this may be a "glass hack" + // impassible window. Point at side #0 (this may not be + // the correct Vanilla behavior; however, it seems to work for + // OTTAWAU.WAD, which is the one place I've seen this trick + // used). + + if (sidenum < 0 || sidenum >= numsides) + { + li->backsector = GetSectorAtNullAddress(); + } + else + { + li->backsector = sides[sidenum].sector; + } + } + else + { li->backsector = 0; + } } - Z_Free (data); + W_ReleaseLumpNum(lump); } @@ -220,7 +254,7 @@ void P_LoadSubsectors (int lump) ss->firstline = SHORT(ms->firstseg); } - Z_Free (data); + W_ReleaseLumpNum(lump); } @@ -254,7 +288,7 @@ void P_LoadSectors (int lump) ss->thinglist = NULL; } - Z_Free (data); + W_ReleaseLumpNum(lump); } @@ -291,7 +325,7 @@ void P_LoadNodes (int lump) } } - Z_Free (data); + W_ReleaseLumpNum(lump); } @@ -300,12 +334,13 @@ void P_LoadNodes (int lump) // void P_LoadThings (int lump) { - byte* data; + byte *data; int i; - mapthing_t* mt; + mapthing_t *mt; + mapthing_t spawnthing; int numthings; boolean spawn; - + data = W_CacheLumpNum (lump,PU_STATIC); numthings = W_LumpLength (lump) / sizeof(mapthing_t); @@ -315,9 +350,9 @@ void P_LoadThings (int lump) spawn = true; // Do not spawn cool, new monsters if !commercial - if ( gamemode != commercial) + if (gamemode != commercial) { - switch(mt->type) + switch (SHORT(mt->type)) { case 68: // Arachnotron case 64: // Archvile @@ -337,16 +372,16 @@ void P_LoadThings (int lump) break; // Do spawn all other stuff. - mt->x = SHORT(mt->x); - mt->y = SHORT(mt->y); - mt->angle = SHORT(mt->angle); - mt->type = SHORT(mt->type); - mt->options = SHORT(mt->options); + spawnthing.x = SHORT(mt->x); + spawnthing.y = SHORT(mt->y); + spawnthing.angle = SHORT(mt->angle); + spawnthing.type = SHORT(mt->type); + spawnthing.options = SHORT(mt->options); - P_SpawnMapThing (mt); + P_SpawnMapThing(&spawnthing); } - - Z_Free (data); + + W_ReleaseLumpNum(lump); } @@ -427,8 +462,8 @@ void P_LoadLineDefs (int lump) else ld->backsector = 0; } - - Z_Free (data); + + W_ReleaseLumpNum(lump); } @@ -458,8 +493,8 @@ void P_LoadSideDefs (int lump) sd->midtexture = R_TextureNumForName(msd->midtexture); sd->sector = §ors[SHORT(msd->sector)]; } - - Z_Free (data); + + W_ReleaseLumpNum(lump); } @@ -468,25 +503,36 @@ void P_LoadSideDefs (int lump) // void P_LoadBlockMap (int lump) { - int i; - int count; - - blockmaplump = W_CacheLumpNum (lump,PU_LEVEL); - blockmap = blockmaplump+4; - count = W_LumpLength (lump)/2; + int i; + int count; + int lumplen; - for (i=0 ; ifrontsector->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; ifrontsector != 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 ; ilines = linebuffer; - li = lines; - for (j=0 ; jlinecount; j++) { - if (li->frontsector == sector || li->backsector == sector) - { - *linebuffer++ = li; - M_AddToBox (bbox, li->v1->x, li->v1->y); - M_AddToBox (bbox, li->v2->x, li->v2->y); - } + li = sector->lines[j]; + + M_AddToBox (bbox, li->v1->x, li->v1->y); + M_AddToBox (bbox, li->v2->x, li->v2->y); } - if (linebuffer - sector->lines != sector->linecount) - I_Error ("P_GroupLines: miscounted"); - + // set the degenmobj_t to the middle of the bounding box sector->soundorg.x = (bbox[BOXRIGHT]+bbox[BOXLEFT])/2; sector->soundorg.y = (bbox[BOXTOP]+bbox[BOXBOTTOM])/2; @@ -576,6 +655,87 @@ void P_GroupLines (void) } +// Pad the REJECT lump with extra data when the lump is too small, +// to simulate a REJECT buffer overflow in Vanilla Doom. + +static void PadRejectArray(byte *array, unsigned int len) +{ + unsigned int i; + unsigned int byte_num; + byte *dest; + unsigned int padvalue; + + // Values to pad the REJECT array with: + + unsigned int rejectpad[4] = + { + ((totallines * 4 + 3) & ~3) + 24, // Size + 0, // Part of z_zone block header + 50, // PU_LEVEL + 0x1d4a11 // DOOM_CONST_ZONEID + }; + + // Copy values from rejectpad into the destination array. + + dest = array; + + for (i=0; i> (byte_num * 8)) & 0xff; + ++dest; + } + + // We only have a limited pad size. Print a warning if the + // REJECT lump is too small. + + if (len > sizeof(rejectpad)) + { + fprintf(stderr, "PadRejectArray: REJECT lump too short to pad! (%i > %i)\n", + len, (int) sizeof(rejectpad)); + + // Pad remaining space with 0 (or 0xff, if specified on command line). + + if (M_CheckParm("-reject_pad_with_ff")) + { + padvalue = 0xff; + } + else + { + padvalue = 0xf00; + } + + memset(array + sizeof(rejectpad), padvalue, len - sizeof(rejectpad)); + } +} + +static void P_LoadReject(int lumpnum) +{ + int minlength; + int lumplen; + + // Calculate the size that the REJECT lump *should* be. + + minlength = (numsectors * numsectors + 7) / 8; + + // If the lump meets the minimum length, it can be loaded directly. + // Otherwise, we need to allocate a buffer of the correct size + // and pad it with appropriate data. + + lumplen = W_LumpLength(lumpnum); + + if (lumplen >= minlength) + { + rejectmatrix = W_CacheLumpNum(lumpnum, PU_LEVEL); + } + else + { + rejectmatrix = Z_Malloc(minlength, PU_LEVEL, &rejectmatrix); + W_ReadLump(lumpnum, rejectmatrix); + + PadRejectArray(rejectmatrix + lumplen, minlength - lumplen); + } +} // // P_SetupLevel @@ -606,31 +766,18 @@ P_SetupLevel // Make sure all sounds are stopped before Z_FreeTags. S_Start (); - -#if 0 // UNUSED - if (debugfile) - { - Z_FreeTags (PU_LEVEL, MAXINT); - Z_FileDumpHeap (debugfile); - } - else -#endif - Z_FreeTags (PU_LEVEL, PU_PURGELEVEL-1); - + Z_FreeTags (PU_LEVEL, PU_PURGELEVEL-1); // UNUSED W_Profile (); P_InitThinkers (); - - // if working with a devlopment map, reload it - W_Reload (); // find map name if ( gamemode == commercial) { if (map<10) - sprintf (lumpname,"map0%i", map); + DEH_snprintf(lumpname, 9, "map0%i", map); else - sprintf (lumpname,"map%i", map); + DEH_snprintf(lumpname, 9, "map%i", map); } else { @@ -655,9 +802,9 @@ P_SetupLevel P_LoadSubsectors (lumpnum+ML_SSECTORS); P_LoadNodes (lumpnum+ML_NODES); P_LoadSegs (lumpnum+ML_SEGS); - - rejectmatrix = W_CacheLumpNum (lumpnum+ML_REJECT,PU_LEVEL); + P_GroupLines (); + P_LoadReject (lumpnum+ML_REJECT); bodyqueslot = 0; deathmatch_p = deathmatchstarts; diff --git a/frosted-doom/p_setup.h b/frosted-doom/p_setup.h index 92b7f36..9df7416 100644 --- a/frosted-doom/p_setup.h +++ b/frosted-doom/p_setup.h @@ -1,32 +1,26 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Setup a game, startup stuff. // -//----------------------------------------------------------------------------- #ifndef __P_SETUP__ #define __P_SETUP__ -#ifdef __GNUG__ -#pragma interface -#endif // NOT called by W_Ticker. Fixme. @@ -41,8 +35,3 @@ P_SetupLevel void P_Init (void); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/p_sight.c b/frosted-doom/p_sight.c index 6aaba6e..48ba683 100644 --- a/frosted-doom/p_sight.c +++ b/frosted-doom/p_sight.c @@ -1,28 +1,21 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // LineOfSight/Visibility checks, uses REJECT Lookup Table. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: p_sight.c,v 1.3 1997/01/28 22:08:28 b1 Exp $"; #include "doomdef.h" @@ -172,7 +165,7 @@ boolean P_CrossSubsector (int num) continue; line->validcount = validcount; - + v1 = line->v1; v2 = line->v2; s1 = P_DivlineSide (v1->x,v1->y, &strace); @@ -193,6 +186,14 @@ boolean P_CrossSubsector (int num) if (s1 == s2) continue; + // Backsector may be NULL if this is an "impassible + // glass" hack line. + + if (line->backsector == NULL) + { + return false; + } + // stop because it is not two sided anyway // might do this after updating validcount? if ( !(line->flags & ML_TWOSIDED) ) diff --git a/frosted-doom/p_spec.c b/frosted-doom/p_spec.c index ba33460..17446b5 100644 --- a/frosted-doom/p_spec.c +++ b/frosted-doom/p_spec.c @@ -1,20 +1,16 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Implements special effects: @@ -23,19 +19,18 @@ // 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 #include "doomdef.h" #include "doomstat.h" +#include "deh_main.h" #include "i_system.h" #include "z_zone.h" #include "m_argv.h" +#include "m_misc.h" #include "m_random.h" #include "w_wad.h" @@ -72,7 +67,7 @@ typedef struct // typedef struct { - int istexture; // if false, it is a flat + int istexture; // if false, it is a flat char endname[9]; char startname[9]; int speed; @@ -128,7 +123,7 @@ animdef_t animdefs[] = {true, "WFALL4", "WFALL1", 8}, {true, "DBRAIN4", "DBRAIN1", 8}, - {-1, "", "", 0} + {-1, "", "", 0}, }; anim_t anims[MAXANIMS]; @@ -149,26 +144,32 @@ void P_InitPicAnims (void) { int i; + // Init animation lastanim = anims; for (i=0 ; animdefs[i].istexture != -1 ; i++) { + char *startname, *endname; + + startname = DEH_String(animdefs[i].startname); + endname = DEH_String(animdefs[i].endname); + if (animdefs[i].istexture) { // different episode ? - if (R_CheckTextureNumForName(animdefs[i].startname) == -1) + if (R_CheckTextureNumForName(startname) == -1) continue; - lastanim->picnum = R_TextureNumForName (animdefs[i].endname); - lastanim->basepic = R_TextureNumForName (animdefs[i].startname); + lastanim->picnum = R_TextureNumForName(endname); + lastanim->basepic = R_TextureNumForName(startname); } else { - if (W_CheckNumForName(animdefs[i].startname) == -1) + if (W_CheckNumForName(startname) == -1) continue; - lastanim->picnum = R_FlatNumForName (animdefs[i].endname); - lastanim->basepic = R_FlatNumForName (animdefs[i].startname); + lastanim->picnum = R_FlatNumForName(endname); + lastanim->basepic = R_FlatNumForName(startname); } lastanim->istexture = animdefs[i].istexture; @@ -176,8 +177,7 @@ void P_InitPicAnims (void) if (lastanim->numpics < 2) I_Error ("P_InitPicAnims: bad cycle from %s to %s", - animdefs[i].startname, - animdefs[i].endname); + startname, endname); lastanim->speed = animdefs[i].speed; lastanim++; @@ -321,59 +321,70 @@ fixed_t P_FindHighestFloorSurrounding(sector_t *sec) // FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS // Note: this should be doable w/o a fixed array. +// Thanks to entryway for the Vanilla overflow emulation. + // 20 adjoining sectors max! -#define MAX_ADJOINING_SECTORS 20 +#define MAX_ADJOINING_SECTORS 20 fixed_t P_FindNextHighestFloor -( sector_t* sec, - int currentheight ) +( sector_t* sec, + int currentheight ) { - int i; - int h; - int min; - line_t* check; - sector_t* other; - fixed_t height = currentheight; + int i; + int h; + int min; + line_t* check; + sector_t* other; + fixed_t height = currentheight; + fixed_t heightlist[MAX_ADJOINING_SECTORS + 2]; - - fixed_t heightlist[MAX_ADJOINING_SECTORS]; - - for (i=0, h=0 ;i < sec->linecount ; i++) + for (i=0, h=0; i < sec->linecount; i++) { - check = sec->lines[i]; - other = getNextSector(check,sec); + check = sec->lines[i]; + other = getNextSector(check,sec); - if (!other) - continue; - - if (other->floorheight > height) - heightlist[h++] = other->floorheight; + 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"); + } - // Check for overflow. Exit. - if ( h >= MAX_ADJOINING_SECTORS ) - { - fprintf( stderr, - "Sector with more than 20 adjoining sectors\n" ); - break; - } + heightlist[h++] = other->floorheight; + } } // Find lowest height in list if (!h) - return currentheight; - + { + return currentheight; + } + min = heightlist[0]; // Range checking? - for (i = 1;i < h;i++) - if (heightlist[i] < min) - min = heightlist[i]; - + for (i = 1; i < h; i++) + { + if (heightlist[i] < min) + { + min = heightlist[i]; + } + } + return min; } - // // FIND LOWEST CEILING IN THE SURROUNDING SECTORS // @@ -383,7 +394,7 @@ P_FindLowestCeilingSurrounding(sector_t* sec) int i; line_t* check; sector_t* other; - fixed_t height = MAXINT; + fixed_t height = INT_MAX; for (i=0 ;i < sec->linecount ; i++) { @@ -541,19 +552,19 @@ P_CrossSpecialLine // All from here to RETRIGGERS. case 2: // Open Door - EV_DoDoor(line,open); + EV_DoDoor(line,vld_open); line->special = 0; break; case 3: // Close Door - EV_DoDoor(line,close); + EV_DoDoor(line,vld_close); line->special = 0; break; case 4: // Raise Door - EV_DoDoor(line,normal); + EV_DoDoor(line,vld_normal); line->special = 0; break; @@ -595,7 +606,7 @@ P_CrossSpecialLine case 16: // Close Door 30 - EV_DoDoor(line,close30ThenOpen); + EV_DoDoor(line,vld_close30ThenOpen); line->special = 0; break; @@ -722,13 +733,13 @@ P_CrossSpecialLine case 108: // Blazing Door Raise (faster than TURBO!) - EV_DoDoor (line,blazeRaise); + EV_DoDoor (line,vld_blazeRaise); line->special = 0; break; case 109: // Blazing Door Open (faster than TURBO!) - EV_DoDoor (line,blazeOpen); + EV_DoDoor (line,vld_blazeOpen); line->special = 0; break; @@ -740,7 +751,7 @@ P_CrossSpecialLine case 110: // Blazing Door Close (faster than TURBO!) - EV_DoDoor (line,blazeClose); + EV_DoDoor (line,vld_blazeClose); line->special = 0; break; @@ -800,12 +811,12 @@ P_CrossSpecialLine case 75: // Close Door - EV_DoDoor(line,close); + EV_DoDoor(line,vld_close); break; case 76: // Close Door 30 - EV_DoDoor(line,close30ThenOpen); + EV_DoDoor(line,vld_close30ThenOpen); break; case 77: @@ -845,7 +856,7 @@ P_CrossSpecialLine case 86: // Open Door - EV_DoDoor(line,open); + EV_DoDoor(line,vld_open); break; case 87: @@ -865,7 +876,7 @@ P_CrossSpecialLine case 90: // Raise Door - EV_DoDoor(line,normal); + EV_DoDoor(line,vld_normal); break; case 91: @@ -912,17 +923,17 @@ P_CrossSpecialLine case 105: // Blazing Door Raise (faster than TURBO!) - EV_DoDoor (line,blazeRaise); + EV_DoDoor (line,vld_blazeRaise); break; case 106: // Blazing Door Open (faster than TURBO!) - EV_DoDoor (line,blazeOpen); + EV_DoDoor (line,vld_blazeOpen); break; case 107: // Blazing Door Close (faster than TURBO!) - EV_DoDoor (line,blazeClose); + EV_DoDoor (line,vld_blazeClose); break; case 120: @@ -986,7 +997,7 @@ P_ShootSpecialLine case 46: // OPEN DOOR - EV_DoDoor(line,open); + EV_DoDoor(line,vld_open); P_ChangeSwitchTexture(line,1); break; @@ -1147,14 +1158,98 @@ void P_UpdateSpecials (void) buttonlist[i].btexture; break; } - S_StartSound((mobj_t *)&buttonlist[i].soundorg,sfx_swtchn); + S_StartSound(&buttonlist[i].soundorg,sfx_swtchn); memset(&buttonlist[i],0,sizeof(button_t)); } } - } +// +// Donut overrun emulation +// +// Derived from the code from PrBoom+. Thanks go to Andrey Budko (entryway) +// as usual :-) +// + +#define DONUT_FLOORHEIGHT_DEFAULT 0x00000000 +#define DONUT_FLOORPIC_DEFAULT 0x16 + +static void DonutOverrun(fixed_t *s3_floorheight, short *s3_floorpic, + line_t *line, sector_t *pillar_sector) +{ + static int first = 1; + static int tmp_s3_floorheight; + static int tmp_s3_floorpic; + + extern int numflats; + + if (first) + { + int p; + + // This is the first time we have had an overrun. + first = 0; + + // Default values + tmp_s3_floorheight = DONUT_FLOORHEIGHT_DEFAULT; + tmp_s3_floorpic = DONUT_FLOORPIC_DEFAULT; + + //! + // @category compat + // @arg + // + // Use the specified magic values when emulating behavior caused + // by memory overruns from improperly constructed donuts. + // In Vanilla Doom this can differ depending on the operating + // system. The default (if this option is not specified) is to + // emulate the behavior when running under Windows 98. + + p = M_CheckParmWithArgs("-donut", 2); + + if (p > 0) + { + // Dump of needed memory: (fixed_t)0000:0000 and (short)0000:0008 + // + // C:\>debug + // -d 0:0 + // + // DOS 6.22: + // 0000:0000 (57 92 19 00) F4 06 70 00-(16 00) + // DOS 7.1: + // 0000:0000 (9E 0F C9 00) 65 04 70 00-(16 00) + // Win98: + // 0000:0000 (00 00 00 00) 65 04 70 00-(16 00) + // DOSBox under XP: + // 0000:0000 (00 00 00 F1) ?? ?? ?? 00-(07 00) + + M_StrToInt(myargv[p + 1], &tmp_s3_floorheight); + M_StrToInt(myargv[p + 2], &tmp_s3_floorpic); + + if (tmp_s3_floorpic >= numflats) + { + fprintf(stderr, + "DonutOverrun: The second parameter for \"-donut\" " + "switch should be greater than 0 and less than number " + "of flats (%d). Using default value (%d) instead. \n", + numflats, DONUT_FLOORPIC_DEFAULT); + tmp_s3_floorpic = DONUT_FLOORPIC_DEFAULT; + } + } + } + + /* + fprintf(stderr, + "Linedef: %d; Sector: %d; " + "New floor height: %d; New floor pic: %d\n", + line->iLineID, pillar_sector->iSectorID, + tmp_s3_floorheight >> 16, tmp_s3_floorpic); + */ + + *s3_floorheight = (fixed_t) tmp_s3_floorheight; + *s3_floorpic = (short) tmp_s3_floorpic; +} + // // Special Stuff that can not be categorized @@ -1168,26 +1263,67 @@ int EV_DoDonut(line_t* line) int rtn; int i; floormove_t* floor; - + fixed_t s3_floorheight; + short s3_floorpic; + secnum = -1; rtn = 0; while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { s1 = §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); @@ -1198,9 +1334,9 @@ int EV_DoDonut(line_t* line) floor->direction = 1; floor->sector = s2; floor->speed = FLOORSPEED / 2; - floor->texture = s3->floorpic; + floor->texture = s3_floorpic; floor->newspecial = 0; - floor->floordestheight = s3->floorheight; + floor->floordestheight = s3_floorheight; // Spawn lowering donut-hole floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); @@ -1212,7 +1348,7 @@ int EV_DoDonut(line_t* line) floor->direction = -1; floor->sector = s1; floor->speed = FLOORSPEED / 2; - floor->floordestheight = s3->floorheight; + floor->floordestheight = s3_floorheight; break; } } @@ -1239,32 +1375,19 @@ void P_SpawnSpecials (void) { sector_t* sector; int i; - //int episode; - //episode = 1; - if (W_CheckNumForName("texture2") >= 0) - //episode = 2; + // See if -TIMER was specified. - - // See if -TIMER needs to be used. - levelTimer = false; - - i = M_CheckParm("-avg"); - if (i && deathmatch) + if (timelimit > 0 && deathmatch) { - levelTimer = true; - levelTimeCount = 20 * 60 * 35; + levelTimer = true; + levelTimeCount = timelimit * 60 * TICRATE; } - - i = M_CheckParm("-timer"); - if (i && deathmatch) + else { - int time; - time = atoi(myargv[i+1]) * 60 * 35; - levelTimer = true; - levelTimeCount = time; + levelTimer = false; } - + // Init special SECTORs. sector = sectors; for (i=0 ; i= MAXLINEANIMS) + { + I_Error("Too many scrolling wall linedefs! " + "(Vanilla limit is 64)"); + } // EFFECT FIRSTCOL SCROLL+ linespeciallist[numlinespecials] = &lines[i]; numlinespecials++; diff --git a/frosted-doom/p_spec.h b/frosted-doom/p_spec.h index 39155bf..a1343bf 100644 --- a/frosted-doom/p_spec.h +++ b/frosted-doom/p_spec.h @@ -1,18 +1,16 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: none // Implements special effects: @@ -20,7 +18,6 @@ // according to adjacent sectors, respective // utility functions, etc. // -//----------------------------------------------------------------------------- #ifndef __P_SPEC__ @@ -230,7 +227,7 @@ typedef struct bwhere_e where; int btexture; int btimer; - mobj_t* soundorg; + degenmobj_t *soundorg; } button_t; @@ -327,14 +324,14 @@ void P_ActivateInStasis(int tag); // typedef enum { - normal, - close30ThenOpen, - close, - open, - raiseIn5Mins, - blazeRaise, - blazeOpen, - blazeClose + vld_normal, + vld_close30ThenOpen, + vld_close, + vld_open, + vld_raiseIn5Mins, + vld_blazeRaise, + vld_blazeOpen, + vld_blazeClose } vldoor_e; @@ -638,8 +635,3 @@ EV_Teleport mobj_t* thing ); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/p_switch.c b/frosted-doom/p_switch.c index 5880732..ed4feec 100644 --- a/frosted-doom/p_switch.c +++ b/frosted-doom/p_switch.c @@ -1,32 +1,26 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // -// $Log:$ -// // DESCRIPTION: // Switches, buttons. Two-state animation. Exits. // -//----------------------------------------------------------------------------- - -static const char -rcsid[] = "$Id: p_switch.c,v 1.3 1997/01/28 22:08:29 b1 Exp $"; +#include #include "i_system.h" +#include "deh_main.h" #include "doomdef.h" #include "p_local.h" @@ -112,7 +106,7 @@ void P_InitSwitchList(void) episode = 1; - if (gamemode == registered) + if (gamemode == registered || gamemode == retail) episode = 2; else if ( gamemode == commercial ) @@ -141,8 +135,8 @@ void P_InitSwitchList(void) value = R_TextureNumForName(alphSwitchList[i].name1); #endif - switchlist[index++] = R_TextureNumForName(alphSwitchList[i].name1); - switchlist[index++] = R_TextureNumForName(alphSwitchList[i].name2); + switchlist[index++] = R_TextureNumForName(DEH_String(alphSwitchList[i].name1)); + switchlist[index++] = R_TextureNumForName(DEH_String(alphSwitchList[i].name2)); } } } @@ -181,7 +175,7 @@ P_StartButton buttonlist[i].where = w; buttonlist[i].btexture = texture; buttonlist[i].btimer = time; - buttonlist[i].soundorg = (mobj_t *)&line->frontsector->soundorg; + buttonlist[i].soundorg = &line->frontsector->soundorg; return; } } @@ -400,7 +394,7 @@ P_UseSpecialLine case 29: // Raise Door - if (EV_DoDoor(line,normal)) + if (EV_DoDoor(line,vld_normal)) P_ChangeSwitchTexture(line,0); break; @@ -424,7 +418,7 @@ P_UseSpecialLine case 50: // Close Door - if (EV_DoDoor(line,close)) + if (EV_DoDoor(line,vld_close)) P_ChangeSwitchTexture(line,0); break; @@ -454,25 +448,25 @@ P_UseSpecialLine case 103: // Open Door - if (EV_DoDoor(line,open)) + if (EV_DoDoor(line,vld_open)) P_ChangeSwitchTexture(line,0); break; case 111: // Blazing Door Raise (faster than TURBO!) - if (EV_DoDoor (line,blazeRaise)) + if (EV_DoDoor (line,vld_blazeRaise)) P_ChangeSwitchTexture(line,0); break; case 112: // Blazing Door Open (faster than TURBO!) - if (EV_DoDoor (line,blazeOpen)) + if (EV_DoDoor (line,vld_blazeOpen)) P_ChangeSwitchTexture(line,0); break; case 113: // Blazing Door Close (faster than TURBO!) - if (EV_DoDoor (line,blazeClose)) + if (EV_DoDoor (line,vld_blazeClose)) P_ChangeSwitchTexture(line,0); break; @@ -500,7 +494,7 @@ P_UseSpecialLine // BlzOpenDoor RED case 137: // BlzOpenDoor YELLOW - if (EV_DoLockedDoor (line,blazeOpen,thing)) + if (EV_DoLockedDoor (line,vld_blazeOpen,thing)) P_ChangeSwitchTexture(line,0); break; @@ -513,7 +507,7 @@ P_UseSpecialLine // BUTTONS case 42: // Close Door - if (EV_DoDoor(line,close)) + if (EV_DoDoor(line,vld_close)) P_ChangeSwitchTexture(line,1); break; @@ -537,7 +531,7 @@ P_UseSpecialLine case 61: // Open Door - if (EV_DoDoor(line,open)) + if (EV_DoDoor(line,vld_open)) P_ChangeSwitchTexture(line,1); break; @@ -549,7 +543,7 @@ P_UseSpecialLine case 63: // Raise Door - if (EV_DoDoor(line,normal)) + if (EV_DoDoor(line,vld_normal)) P_ChangeSwitchTexture(line,1); break; @@ -597,19 +591,19 @@ P_UseSpecialLine case 114: // Blazing Door Raise (faster than TURBO!) - if (EV_DoDoor (line,blazeRaise)) + if (EV_DoDoor (line,vld_blazeRaise)) P_ChangeSwitchTexture(line,1); break; case 115: // Blazing Door Open (faster than TURBO!) - if (EV_DoDoor (line,blazeOpen)) + if (EV_DoDoor (line,vld_blazeOpen)) P_ChangeSwitchTexture(line,1); break; case 116: // Blazing Door Close (faster than TURBO!) - if (EV_DoDoor (line,blazeClose)) + if (EV_DoDoor (line,vld_blazeClose)) P_ChangeSwitchTexture(line,1); break; @@ -631,7 +625,7 @@ P_UseSpecialLine // BlzOpenDoor RED case 136: // BlzOpenDoor YELLOW - if (EV_DoLockedDoor (line,blazeOpen,thing)) + if (EV_DoLockedDoor (line,vld_blazeOpen,thing)) P_ChangeSwitchTexture(line,1); break; diff --git a/frosted-doom/p_telept.c b/frosted-doom/p_telept.c index 56ba3d7..45cdfb0 100644 --- a/frosted-doom/p_telept.c +++ b/frosted-doom/p_telept.c @@ -1,32 +1,26 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Teleportation. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: p_telept.c,v 1.3 1997/01/28 22:08:29 b1 Exp $"; #include "doomdef.h" +#include "doomstat.h" #include "s_sound.h" @@ -102,11 +96,18 @@ EV_Teleport if (!P_TeleportMove (thing, m->x, m->y)) return 0; - - thing->z = thing->floorz; //fixme: not needed? + + // The first Final Doom executable does not set thing->z + // when teleporting. This quirk is unique to this + // particular version; the later version included in + // some versions of the Id Anthology fixed this. + + if (gameversion != exe_final) + thing->z = thing->floorz; + if (thing->player) thing->player->viewz = thing->z+thing->player->viewheight; - + // spawn teleport fog at source and destination fog = P_SpawnMobj (oldx, oldy, oldz, MT_TFOG); S_StartSound (fog, sfx_telept); diff --git a/frosted-doom/p_tick.c b/frosted-doom/p_tick.c index 9b16a6d..2289350 100644 --- a/frosted-doom/p_tick.c +++ b/frosted-doom/p_tick.c @@ -1,29 +1,22 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Archiving: SaveGame I/O. // Thinker, Ticker. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: p_tick.c,v 1.4 1997/02/03 16:47:55 b1 Exp $"; #include "z_zone.h" #include "p_local.h" diff --git a/frosted-doom/p_tick.h b/frosted-doom/p_tick.h index 0841998..ddfcd74 100644 --- a/frosted-doom/p_tick.h +++ b/frosted-doom/p_tick.h @@ -1,32 +1,26 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // ? // -//----------------------------------------------------------------------------- #ifndef __P_TICK__ #define __P_TICK__ -#ifdef __GNUG__ -#pragma interface -#endif // Called by C_Ticker, @@ -37,8 +31,3 @@ void P_Ticker (void); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/p_user.c b/frosted-doom/p_user.c index 22fd6ed..73c0dc9 100644 --- a/frosted-doom/p_user.c +++ b/frosted-doom/p_user.c @@ -1,31 +1,24 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Player related stuff. // Bobbing POV/weapon, movement. // Pending weapon. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: p_user.c,v 1.3 1997/01/28 22:08:29 b1 Exp $"; #include "doomdef.h" diff --git a/frosted-doom/r_bsp.c b/frosted-doom/r_bsp.c index adc9f75..9a78812 100644 --- a/frosted-doom/r_bsp.c +++ b/frosted-doom/r_bsp.c @@ -1,29 +1,22 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // BSP traversal, handling of LineSegs for rendering. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: r_bsp.c,v 1.4 1997/02/03 22:45:12 b1 Exp $"; #include "doomdef.h" diff --git a/frosted-doom/r_bsp.h b/frosted-doom/r_bsp.h index 743adb9..1723e68 100644 --- a/frosted-doom/r_bsp.h +++ b/frosted-doom/r_bsp.h @@ -1,31 +1,25 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Refresh module, BSP traversal and handling. // -//----------------------------------------------------------------------------- #ifndef __R_BSP__ #define __R_BSP__ -#ifdef __GNUG__ -#pragma interface -#endif extern seg_t* curline; @@ -65,8 +59,3 @@ void R_RenderBSPNode (int bspnum); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/r_data.c b/frosted-doom/r_data.c index cb29313..2d4b65b 100644 --- a/frosted-doom/r_data.c +++ b/frosted-doom/r_data.c @@ -1,51 +1,40 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // -// $Log:$ -// -// Revision 1.3 1997/01/29 20:10 // DESCRIPTION: // Preparation of data for rendering, // generation of lookups, caching, retrieval by name. // -//----------------------------------------------------------------------------- +#include -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 -#endif -#include - #include "r_data.h" @@ -74,7 +63,7 @@ typedef struct short patch; short stepdir; short colormap; -} mappatch_t; +} PACKEDATTR mappatch_t; // @@ -85,13 +74,13 @@ typedef struct typedef struct { char name[8]; - boolean masked; + int masked; short width; short height; - void **columndirectory; // OBSOLETE + int obsolete; short patchcount; mappatch_t patches[1]; -} maptexture_t; +} PACKEDATTR maptexture_t; // A single patch from a texture definition, @@ -102,8 +91,8 @@ typedef struct // Block origin (allways UL), // which has allready accounted // for the internal origin of the patch. - int originx; - int originy; + short originx; + short originy; int patch; } texpatch_t; @@ -111,19 +100,29 @@ typedef struct // A maptexturedef_t describes a rectangular texture, // which is composed of one or more mappatch_t structures // that arrange graphic patches. -typedef struct + +typedef struct texture_s texture_t; + +struct texture_s { // Keep name for switch changing, etc. char name[8]; short width; short height; + + // Index in textures list + + int index; + + // Next in hash table chain + + texture_t *next; // All the patches[patchcount] // are drawn back to front into the cached texture. short patchcount; texpatch_t patches[1]; - -} texture_t; +}; @@ -141,6 +140,7 @@ int numspritelumps; int numtextures; texture_t** textures; +texture_t** textures_hashtable; int* texturewidthmask; @@ -192,10 +192,7 @@ R_DrawColumnInCache int count; int position; byte* source; - //byte* dest; - // - //dest = (byte *)cache + 3; - + while (patch->topdelta != 0xff) { source = (byte *)patch + 3; @@ -298,7 +295,6 @@ void R_GenerateLookup (int texnum) { texture_t* texture; byte* patchcount; // patchcount[texture->width] - byte* patchcount_alloc; texpatch_t* patch; patch_t* realpatch; int x; @@ -321,14 +317,10 @@ void R_GenerateLookup (int texnum) // that are covered by more than one patch. // Fill in the lump / offset, so columns // with only a single patch are all done. - //XXX patchcount = (byte *)alloca (texture->width); - patchcount = (byte *)malloc (texture->width); - patchcount_alloc = patchcount; - if (!patchcount) - return; + patchcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &patchcount); memset (patchcount, 0, texture->width); patch = texture->patches; - + for (i=0 , patch = texture->patches; ipatchcount; i++, patch++) @@ -378,7 +370,7 @@ void R_GenerateLookup (int texnum) } } - free(patchcount_alloc); + Z_Free(patchcount); } @@ -409,6 +401,46 @@ R_GetColumn } +static void GenerateTextureHashTable(void) +{ + texture_t **rover; + int i; + int key; + + textures_hashtable + = Z_Malloc(sizeof(texture_t *) * numtextures, PU_STATIC, 0); + + memset(textures_hashtable, 0, sizeof(texture_t *) * numtextures); + + // Add all textures to hash table + + for (i=0; iindex = i; + + // Vanilla Doom does a linear search of the texures array + // and stops at the first entry it finds. If there are two + // entries with the same name, the first one in the array + // wins. The new entry must therefore be added at the end + // of the hash chain, so that earlier entries win. + + key = W_LumpNameHash(textures[i]->name) % numtextures; + + rover = &textures_hashtable[key]; + + while (*rover != NULL) + { + rover = &(*rover)->next; + } + + // Hook into hash table + + textures[i]->next = NULL; + *rover = textures[i]; + } +} // @@ -435,7 +467,6 @@ void R_InitTextures (void) char* name_p; int* patchlookup; - int* patchlookup_alloc; int totalwidth; int nummappatches; @@ -453,36 +484,32 @@ void R_InitTextures (void) // Load the patch names from pnames.lmp. - name[8] = 0; - names = W_CacheLumpName ("PNAMES", PU_STATIC); + name[8] = 0; + names = W_CacheLumpName (DEH_String("PNAMES"), PU_STATIC); nummappatches = LONG ( *((int *)names) ); - name_p = names+4; - //XXX patchlookup = alloca (nummappatches*sizeof(*patchlookup)); - patchlookup = malloc (nummappatches*sizeof(*patchlookup)); - patchlookup_alloc = patchlookup; - if (!patchlookup) - return; - - for (i=0 ; iwidth = SHORT(mtexture->width); texture->height = SHORT(mtexture->height); texture->patchcount = SHORT(mtexture->patchcount); - + memcpy (texture->name, mtexture->name, sizeof(texture->name)); mpatch = &mtexture->patches[0]; patch = &texture->patches[0]; @@ -558,8 +592,8 @@ void R_InitTextures (void) texture->name); } } - texturecolumnlump[i] = Z_Malloc (texture->width*2, PU_STATIC,0); - texturecolumnofs[i] = Z_Malloc (texture->width*2, PU_STATIC,0); + texturecolumnlump[i] = Z_Malloc (texture->width*sizeof(**texturecolumnlump), PU_STATIC,0); + texturecolumnofs[i] = Z_Malloc (texture->width*sizeof(**texturecolumnofs), PU_STATIC,0); j = 1; while (j*2 <= texture->width) @@ -571,21 +605,24 @@ void R_InitTextures (void) totalwidth += texture->width; } - Z_Free (maptex1); + Z_Free(patchlookup); + + W_ReleaseLumpName(DEH_String("TEXTURE1")); if (maptex2) - Z_Free (maptex2); + W_ReleaseLumpName(DEH_String("TEXTURE2")); // Precalculate whatever possible. + for (i=0 ; iname, name, 8) ) - return i; - + key = W_LumpNameHash(name) % numtextures; + + texture=textures_hashtable[key]; + + while (texture != NULL) + { + if (!strncasecmp (texture->name, name, 8) ) + return texture->index; + + texture = texture->next; + } + return -1; } @@ -758,11 +800,8 @@ int spritememory; void R_PrecacheLevel (void) { char* flatpresent; - char* flatpresent_alloc; char* texturepresent; - char* texturepresent_alloc; char* spritepresent; - char* spritepresent_alloc; int i; int j; @@ -777,11 +816,7 @@ void R_PrecacheLevel (void) return; // Precache flats. - //XXX flatpresent = alloca(numflats); - flatpresent = malloc(numflats); - flatpresent_alloc = flatpresent; - if (!flatpresent) - return; + flatpresent = Z_Malloc(numflats, PU_STATIC, NULL); memset (flatpresent,0,numflats); for (i=0 ; inext) @@ -877,7 +904,7 @@ void R_PrecacheLevel (void) } } - free(spritepresent_alloc); + Z_Free(spritepresent); } diff --git a/frosted-doom/r_data.h b/frosted-doom/r_data.h index 7f5a23d..66425af 100644 --- a/frosted-doom/r_data.h +++ b/frosted-doom/r_data.h @@ -1,24 +1,21 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Refresh module, data I/O, caching, retrieval of graphics // by name. // -//----------------------------------------------------------------------------- #ifndef __R_DATA__ @@ -27,9 +24,6 @@ #include "r_defs.h" #include "r_state.h" -#ifdef __GNUG__ -#pragma interface -#endif // Retrieve column data for span blitting. byte* @@ -55,8 +49,3 @@ int R_TextureNumForName (char *name); int R_CheckTextureNumForName (char *name); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/r_defs.h b/frosted-doom/r_defs.h index 6c842a5..a64ac84 100644 --- a/frosted-doom/r_defs.h +++ b/frosted-doom/r_defs.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Refresh/rendering module, shared data struct definitions. // -//----------------------------------------------------------------------------- #ifndef __R_DEFS__ @@ -37,11 +34,10 @@ // SECTORS do store MObjs anyway. #include "p_mobj.h" +#include "i_video.h" +#include "v_patch.h" -#ifdef __GNUG__ -#pragma interface -#endif @@ -281,18 +277,6 @@ typedef struct -// posts are runs of non masked source pixels -typedef struct -{ - byte topdelta; // -1 is the last post in a column - byte length; // length data bytes follows -} post_t; - -// column_t is a list of 0 or more post_t, (byte)-1 terminated -typedef post_t column_t; - - - // PC direct to screen pointers //B UNUSED - keep till detailshift in r_draw.c resolved //extern byte* destview; @@ -348,27 +332,6 @@ typedef struct drawseg_s -// Patches. -// A patch holds one or more columns. -// Patches are used for sprites and all masked pictures, -// and we compose textures from the TEXTURE1/2 lists -// of patches. -typedef struct -{ - short width; // bounding box size - short height; - short leftoffset; // pixels to the left of origin - short topoffset; // pixels below the origin - int columnofs[8]; // only [width] used - // the [0] is &columnofs[width] -} patch_t; - - - - - - - // A vissprite_t is a thing // that will be drawn during a refresh. // I.e. a sprite object that is partly visible. @@ -483,8 +446,3 @@ typedef struct #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/r_draw.c b/frosted-doom/r_draw.c index 0145044..9271bcd 100644 --- a/frosted-doom/r_draw.c +++ b/frosted-doom/r_draw.c @@ -1,34 +1,28 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // The actual span/column drawing functions. // Here find the main potential for optimization, // e.g. inline assembly, different algorithms. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: r_draw.c,v 1.4 1997/02/03 16:47:55 b1 Exp $"; #include "doomdef.h" +#include "deh_main.h" #include "i_system.h" #include "z_zone.h" @@ -75,7 +69,10 @@ int columnofs[MAXWIDTH]; // byte translations[3][256]; - +// Backing buffer containing the bezel drawn around the screen and +// surrounding background. + +static byte *background_buffer = NULL; // @@ -215,6 +212,7 @@ void R_DrawColumnLow (void) byte* dest2; fixed_t frac; fixed_t fracstep; + int x; count = dc_yh - dc_yl; @@ -233,10 +231,10 @@ void R_DrawColumnLow (void) // dccount++; #endif // Blocky mode, need to multiply by 2. - dc_x <<= 1; + x = dc_x << 1; - dest = ylookup[dc_yl] + columnofs[dc_x]; - dest2 = ylookup[dc_yl] + columnofs[dc_x+1]; + dest = ylookup[dc_yl] + columnofs[x]; + dest2 = ylookup[dc_yl] + columnofs[x+1]; fracstep = dc_iscale; frac = dc_texturemid + (dc_yl-centery)*fracstep; @@ -303,7 +301,6 @@ void R_DrawFuzzColumn (void) if (count < 0) return; - #ifdef RANGECHECK if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT) @@ -312,34 +309,7 @@ void R_DrawFuzzColumn (void) dc_yl, dc_yh, dc_x); } #endif - - - // 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 - { - 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); - }*/ - - // Does not work with blocky mode. dest = ylookup[dc_yl] + columnofs[dc_x]; // Looks familiar. @@ -366,7 +336,76 @@ void R_DrawFuzzColumn (void) 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 + + 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; + frac = dc_texturemid + (dc_yl-centery)*fracstep; + + // Looks like an attempt at dithering, + // using the colormap #6 (of 0-31, a bit + // brighter than average). + do + { + // 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]]]; + *dest2 = colormaps[6*256+dest2[fuzzoffset[fuzzpos]]]; + + // Clamp table lookup index. + if (++fuzzpos == FUZZTABLE) + fuzzpos = 0; + + dest += SCREENWIDTH; + dest2 += SCREENWIDTH; + + frac += fracstep; + } while (count--); +} + + @@ -405,26 +444,6 @@ void R_DrawTranslatedColumn (void) #endif - // WATCOM VGA specific. - /* Keep for fixing. - if (detailshift) - { - if (dc_x & 1) - outp (SC_INDEX+1,12); - else - outp (SC_INDEX+1,3); - - dest = destview + dc_yl*80 + (dc_x>>1); - } - else - { - outp (SC_INDEX+1,1<<(dc_x&3)); - - dest = destview + dc_yl*80 + (dc_x>>2); - }*/ - - - // FIXME. As above. dest = ylookup[dc_yl] + columnofs[dc_x]; // Looks familiar. @@ -446,6 +465,58 @@ void R_DrawTranslatedColumn (void) } while (count--); } +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); + } + +#endif + + + dest = ylookup[dc_yl] + columnofs[x]; + dest2 = ylookup[dc_yl] + columnofs[x+1]; + + // Looks familiar. + fracstep = dc_iscale; + frac = dc_texturemid + (dc_yl-centery)*fracstep; + + // Here we do an additional index re-mapping. + do + { + // 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]]]; + *dest2 = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]; + dest += SCREENWIDTH; + dest2 += SCREENWIDTH; + + frac += fracstep; + } while (count--); +} + @@ -460,8 +531,7 @@ void R_InitTranslationTables (void) { int i; - translationtables = Z_Malloc (256*3+255, PU_STATIC, 0); - translationtables = (byte *)(( (int)translationtables + 255 )& ~255); + translationtables = Z_Malloc (256*3, PU_STATIC, 0); // translate just the 16 green colors for (i=0 ; i<256 ; i++) @@ -519,48 +589,54 @@ int dscount; // Draws the actual span. void R_DrawSpan (void) { - fixed_t xfrac; - fixed_t yfrac; - byte* dest; - int count; - int spot; - -#ifdef RANGECHECK + unsigned int position, step; + byte *dest; + int count; + int spot; + unsigned int xtemp, ytemp; + +#ifdef RANGECHECK if (ds_x2 < ds_x1 || ds_x1<0 - || ds_x2>=SCREENWIDTH + || ds_x2>=SCREENWIDTH || (unsigned)ds_y>SCREENHEIGHT) { I_Error( "R_DrawSpan: %i to %i at %i", ds_x1,ds_x2,ds_y); } -// dscount++; -#endif +// dscount++; +#endif + + // Pack position and step variables into a single 32-bit integer, + // with x in the top 16 bits and y in the bottom 16 bits. For + // each 16-bit part, the top 6 bits are the integer part and the + // bottom 10 bits are the fractional part of the pixel position. + + position = ((ds_xfrac << 10) & 0xffff0000) + | ((ds_yfrac >> 6) & 0x0000ffff); + step = ((ds_xstep << 10) & 0xffff0000) + | ((ds_ystep >> 6) & 0x0000ffff); - - xfrac = ds_xfrac; - yfrac = ds_yfrac; - dest = ylookup[ds_y] + columnofs[ds_x1]; // We do not check for zero spans here? - count = ds_x2 - ds_x1; + count = ds_x2 - ds_x1; - do + do { - // Current texture index in u,v. - spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63); + // Calculate current texture index in u,v. + ytemp = (position >> 4) & 0x0fc0; + xtemp = (position >> 26); + spot = xtemp | ytemp; // Lookup pixel from flat texture tile, // re-index using light/colormap. *dest++ = ds_colormap[ds_source[spot]]; - // Next step in u,v. - xfrac += ds_xstep; - yfrac += ds_ystep; - - } while (count--); -} + position += step; + + } while (count--); +} @@ -640,49 +716,54 @@ void R_DrawSpan (void) // // Again.. // -void R_DrawSpanLow (void) -{ - fixed_t xfrac; - fixed_t yfrac; - byte* dest; - int count; - int spot; - -#ifdef RANGECHECK +void R_DrawSpanLow (void) +{ + unsigned int position, step; + unsigned int xtemp, ytemp; + byte *dest; + int count; + int spot; + +#ifdef RANGECHECK if (ds_x2 < ds_x1 || ds_x1<0 - || ds_x2>=SCREENWIDTH + || ds_x2>=SCREENWIDTH || (unsigned)ds_y>SCREENHEIGHT) { I_Error( "R_DrawSpan: %i to %i at %i", ds_x1,ds_x2,ds_y); } // dscount++; -#endif - - xfrac = ds_xfrac; - yfrac = ds_yfrac; +#endif + + position = ((ds_xfrac << 10) & 0xffff0000) + | ((ds_yfrac >> 6) & 0x0000ffff); + step = ((ds_xstep << 10) & 0xffff0000) + | ((ds_ystep >> 6) & 0x0000ffff); + + count = (ds_x2 - ds_x1); // Blocky mode, need to multiply by 2. ds_x1 <<= 1; ds_x2 <<= 1; - + dest = ylookup[ds_y] + columnofs[ds_x1]; - - - count = ds_x2 - ds_x1; - do - { - spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63); + + do + { + // Calculate current texture index in u,v. + ytemp = (position >> 4) & 0x0fc0; + xtemp = (position >> 26); + spot = xtemp | ytemp; + // Lowres/blocky mode does it twice, // while scale is adjusted appropriately. - *dest++ = ds_colormap[ds_source[spot]]; *dest++ = ds_colormap[ds_source[spot]]; - - xfrac += ds_xstep; - yfrac += ds_ystep; + *dest++ = ds_colormap[ds_source[spot]]; - } while (count--); + position += step; + + } while (count--); } // @@ -716,7 +797,7 @@ R_InitBuffer // Preclaculate all row offsets. for (i=0 ; i>DBITS ]+ANG90) >> ANGLETOFINESHIFT; + angle = (tantoangle[frac>>DBITS]+ANG90) >> ANGLETOFINESHIFT; // use as cosine dist = FixedDiv (dx, finesine[angle] ); @@ -453,8 +449,8 @@ void R_InitPointToAngle (void) fixed_t R_ScaleFromGlobalAngle (angle_t visangle) { fixed_t scale; - int anglea; - int angleb; + angle_t anglea; + angle_t angleb; int sinea; int sineb; fixed_t num; @@ -709,8 +705,8 @@ void R_ExecuteSetViewSize (void) else { colfunc = basecolfunc = R_DrawColumnLow; - fuzzcolfunc = R_DrawFuzzColumn; - transcolfunc = R_DrawTranslatedColumn; + fuzzcolfunc = R_DrawFuzzColumnLow; + transcolfunc = R_DrawTranslatedColumnLow; spanfunc = R_DrawSpanLow; } @@ -765,30 +761,27 @@ void R_ExecuteSetViewSize (void) // // R_Init // -extern int detailLevel; -extern int screenblocks; void R_Init (void) { R_InitData (); - printf ("\nR_InitData"); + printf ("."); R_InitPointToAngle (); - printf ("\nR_InitPointToAngle"); + printf ("."); R_InitTables (); // viewwidth / viewheight / detailLevel are set by the defaults - printf ("\nR_InitTables"); + printf ("."); R_SetViewSize (screenblocks, detailLevel); R_InitPlanes (); - printf ("\nR_InitPlanes"); + printf ("."); R_InitLightTables (); - printf ("\nR_InitLightTables"); + printf ("."); R_InitSkyMap (); - printf ("\nR_InitSkyMap"); R_InitTranslationTables (); - printf ("\nR_InitTranslationsTables"); + printf ("."); framecount = 0; } diff --git a/frosted-doom/r_main.h b/frosted-doom/r_main.h index dff69d8..c05a9a0 100644 --- a/frosted-doom/r_main.h +++ b/frosted-doom/r_main.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // System specific interface stuff. // -//----------------------------------------------------------------------------- #ifndef __R_MAIN__ @@ -27,9 +24,6 @@ #include "r_data.h" -#ifdef __GNUG__ -#pragma interface -#endif // @@ -38,8 +32,6 @@ extern fixed_t viewcos; extern fixed_t viewsin; -extern int viewwidth; -extern int viewheight; extern int viewwindowx; extern int viewwindowy; @@ -98,6 +90,7 @@ extern int detailshift; // Used to select shadow mode etc. // extern void (*colfunc) (void); +extern void (*transcolfunc) (void); extern void (*basecolfunc) (void); extern void (*fuzzcolfunc) (void); // No shadow effects on floors. @@ -165,8 +158,3 @@ void R_Init (void); void R_SetViewSize (int blocks, int detail); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/r_plane.c b/frosted-doom/r_plane.c index f6ac8e2..ea1611c 100644 --- a/frosted-doom/r_plane.c +++ b/frosted-doom/r_plane.c @@ -1,32 +1,25 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Here is a core component: drawing the floors and ceilings, // while maintaining a per column clipping list only. // Moreover, the sky areas have to be determined. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: r_plane.c,v 1.4 1997/02/03 16:47:55 b1 Exp $"; - +#include #include #include "i_system.h" @@ -130,9 +123,9 @@ R_MapPlane #ifdef RANGECHECK if (x2 < x1 - || x1<0 - || x2>=viewwidth - || (unsigned)y>viewheight) + || x1 < 0 + || x2 >= viewwidth + || y > viewheight) { I_Error ("R_MapPlane: %i, %i at %i",x1,x2,y); } @@ -371,6 +364,7 @@ void R_DrawPlanes (void) int x; int stop; int angle; + int lumpnum; #ifdef RANGECHECK if (ds_p - drawsegs > MAXDRAWSEGS) @@ -420,9 +414,8 @@ void R_DrawPlanes (void) } // regular flat - ds_source = W_CacheLumpNum(firstflat + - flattranslation[pl->picnum], - PU_STATIC); + lumpnum = firstflat + flattranslation[pl->picnum]; + ds_source = W_CacheLumpNum(lumpnum, PU_STATIC); planeheight = abs(pl->height-viewz); light = (pl->lightlevel >> LIGHTSEGSHIFT)+extralight; @@ -448,6 +441,6 @@ void R_DrawPlanes (void) pl->bottom[x]); } - Z_ChangeTag (ds_source, PU_CACHE); + W_ReleaseLumpNum(lumpnum); } } diff --git a/frosted-doom/r_plane.h b/frosted-doom/r_plane.h index d266233..57b50e5 100644 --- a/frosted-doom/r_plane.h +++ b/frosted-doom/r_plane.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Refresh, visplane stuff (floor, ceilings). // -//----------------------------------------------------------------------------- #ifndef __R_PLANE__ @@ -26,9 +23,6 @@ #include "r_data.h" -#ifdef __GNUG__ -#pragma interface -#endif // Visplane related. @@ -80,8 +74,3 @@ R_CheckPlane #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/r_segs.c b/frosted-doom/r_segs.c index 1962d92..9b4e413 100644 --- a/frosted-doom/r_segs.c +++ b/frosted-doom/r_segs.c @@ -1,34 +1,27 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // All the clipping: columns, horizontal spans, sky columns. // -//----------------------------------------------------------------------------- - - -static const char -rcsid[] = "$Id: r_segs.c,v 1.3 1997/01/29 20:10:19 b1 Exp $"; + +#include #include #include "i_system.h" @@ -162,7 +155,7 @@ R_RenderMaskedSegRange for (dc_x = x1 ; dc_x <= x2 ; dc_x++) { // calculate lighting - if (maskedtexturecol[dc_x] != MAXSHORT) + if (maskedtexturecol[dc_x] != SHRT_MAX) { if (!fixedcolormap) { @@ -182,7 +175,7 @@ R_RenderMaskedSegRange (byte *)R_GetColumn(texnum,maskedtexturecol[dc_x]) -3); R_DrawMaskedColumn (col); - maskedtexturecol[dc_x] = MAXSHORT; + maskedtexturecol[dc_x] = SHRT_MAX; } spryscale += rw_scalestep; } @@ -214,8 +207,6 @@ void R_RenderSegLoop (void) int top; int bottom; - //texturecolumn = 0; // shut up compiler warning - for ( ; rw_x < rw_stopx ; rw_x++) { // mark floor / ceiling areas @@ -275,6 +266,12 @@ void R_RenderSegLoop (void) dc_x = rw_x; dc_iscale = 0xffffffffu / (unsigned)rw_scale; } + else + { + // purely to shut up the compiler + + texturecolumn = 0; + } // draw the wall tiers if (midtexture) @@ -476,8 +473,8 @@ R_StoreWallRange ds_p->silhouette = SIL_BOTH; ds_p->sprtopclip = screenheightarray; ds_p->sprbottomclip = negonearray; - ds_p->bsilheight = MAXINT; - ds_p->tsilheight = MININT; + ds_p->bsilheight = INT_MAX; + ds_p->tsilheight = INT_MIN; } else { @@ -493,7 +490,7 @@ R_StoreWallRange else if (backsector->floorheight > viewz) { ds_p->silhouette = SIL_BOTTOM; - ds_p->bsilheight = MAXINT; + ds_p->bsilheight = INT_MAX; // ds_p->sprbottomclip = negonearray; } @@ -505,21 +502,21 @@ R_StoreWallRange else if (backsector->ceilingheight < viewz) { ds_p->silhouette |= SIL_TOP; - ds_p->tsilheight = MININT; + ds_p->tsilheight = INT_MIN; // ds_p->sprtopclip = screenheightarray; } if (backsector->ceilingheight <= frontsector->floorheight) { ds_p->sprbottomclip = negonearray; - ds_p->bsilheight = MAXINT; + ds_p->bsilheight = INT_MAX; ds_p->silhouette |= SIL_BOTTOM; } if (backsector->floorheight >= frontsector->ceilingheight) { ds_p->sprtopclip = screenheightarray; - ds_p->tsilheight = MININT; + ds_p->tsilheight = INT_MIN; ds_p->silhouette |= SIL_TOP; } @@ -734,12 +731,12 @@ R_StoreWallRange if (maskedtexture && !(ds_p->silhouette&SIL_TOP)) { ds_p->silhouette |= SIL_TOP; - ds_p->tsilheight = MININT; + ds_p->tsilheight = INT_MIN; } if (maskedtexture && !(ds_p->silhouette&SIL_BOTTOM)) { ds_p->silhouette |= SIL_BOTTOM; - ds_p->bsilheight = MAXINT; + ds_p->bsilheight = INT_MAX; } ds_p++; } diff --git a/frosted-doom/r_segs.h b/frosted-doom/r_segs.h index 1c37650..d4a4d89 100644 --- a/frosted-doom/r_segs.h +++ b/frosted-doom/r_segs.h @@ -1,32 +1,26 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Refresh module, drawing LineSegs from BSP. // -//----------------------------------------------------------------------------- #ifndef __R_SEGS__ #define __R_SEGS__ -#ifdef __GNUG__ -#pragma interface -#endif void @@ -37,8 +31,3 @@ R_RenderMaskedSegRange #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/r_sky.c b/frosted-doom/r_sky.c index b090ec0..667c88d 100644 --- a/frosted-doom/r_sky.c +++ b/frosted-doom/r_sky.c @@ -1,20 +1,16 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Sky rendering. The DOOM sky is a texture map like any @@ -23,10 +19,7 @@ // on a 320 screen? // // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $"; // Needed for FRACUNIT. @@ -36,9 +29,6 @@ rcsid[] = "$Id: m_bbox.c,v 1.1 1997/02/03 22:45:10 b1 Exp $"; #include "r_data.h" -#ifdef __GNUG__ -#pragma implementation "r_sky.h" -#endif #include "r_sky.h" // diff --git a/frosted-doom/r_sky.h b/frosted-doom/r_sky.h index 663f007..8ad6680 100644 --- a/frosted-doom/r_sky.h +++ b/frosted-doom/r_sky.h @@ -1,32 +1,26 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Sky rendering. // -//----------------------------------------------------------------------------- #ifndef __R_SKY__ #define __R_SKY__ -#ifdef __GNUG__ -#pragma interface -#endif // SKY, store the number for name. #define SKYFLATNAME "F_SKY1" @@ -41,8 +35,3 @@ extern int skytexturemid; void R_InitSkyMap (void); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/r_state.h b/frosted-doom/r_state.h index 1fb6bf9..2a60e2f 100644 --- a/frosted-doom/r_state.h +++ b/frosted-doom/r_state.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Refresh/render internal state variables (global). // -//----------------------------------------------------------------------------- #ifndef __R_STATE__ @@ -29,9 +26,6 @@ -#ifdef __GNUG__ -#pragma interface -#endif @@ -131,8 +125,3 @@ extern visplane_t* ceilingplane; #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/r_things.c b/frosted-doom/r_things.c index 09c3653..74e7369 100644 --- a/frosted-doom/r_things.c +++ b/frosted-doom/r_things.c @@ -1,38 +1,32 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Refresh of things, i.e. objects represented by sprites. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: r_things.c,v 1.5 1997/02/03 16:47:56 b1 Exp $"; #include #include +#include "deh_main.h" #include "doomdef.h" -#include "m_swap.h" +#include "i_swap.h" #include "i_system.h" #include "z_zone.h" #include "w_wad.h" @@ -179,7 +173,6 @@ void R_InitSpriteDefs (char** namelist) char** check; int i; int l; - int intname; int frame; int rotation; int start; @@ -189,7 +182,7 @@ void R_InitSpriteDefs (char** namelist) // count the number of sprite names check = namelist; while (*check != NULL) - check++; + check++; numsprites = check-namelist; @@ -206,17 +199,16 @@ void R_InitSpriteDefs (char** namelist) // Just compare 4 characters as ints for (i=0 ; imobjflags & MF_TRANSLATION) { - colfunc = R_DrawTranslatedColumn; + colfunc = transcolfunc; dc_translation = translationtables - 256 + ( (vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT-8) ); } @@ -504,7 +496,7 @@ void R_ProjectSprite (mobj_t* thing) // decide which patch to use for sprite relative to player #ifdef RANGECHECK - if ((unsigned)thing->sprite >= numsprites) + if ((unsigned int) thing->sprite >= (unsigned int) numsprites) I_Error ("R_ProjectSprite: invalid sprite number %i ", thing->sprite); #endif @@ -657,7 +649,7 @@ void R_DrawPSprite (pspdef_t* psp) // decide which patch to use #ifdef RANGECHECK - if ( (unsigned)psp->state->sprite >= numsprites) + if ( (unsigned)psp->state->sprite >= (unsigned int) numsprites) I_Error ("R_ProjectSprite: invalid sprite number %i ", psp->state->sprite); #endif @@ -812,11 +804,12 @@ void R_SortVisSprites (void) unsorted.prev = vissprite_p-1; // pull the vissprites out by scale - //best = 0; // shut up the compiler warning + vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead; for (i=0 ; inext) { if (ds->scale < bestscale) @@ -839,9 +832,8 @@ void R_SortVisSprites (void) // // R_DrawSprite // -// -short clipbot[SCREENWIDTH]; -short cliptop[SCREENWIDTH]; +static short clipbot[SCREENWIDTH]; +static short cliptop[SCREENWIDTH]; void R_DrawSprite (vissprite_t* spr) { drawseg_t* ds; diff --git a/frosted-doom/r_things.h b/frosted-doom/r_things.h index 299361d..256a5eb 100644 --- a/frosted-doom/r_things.h +++ b/frosted-doom/r_things.h @@ -1,32 +1,26 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Rendering of moving objects, sprites. // -//----------------------------------------------------------------------------- #ifndef __R_THINGS__ #define __R_THINGS__ -#ifdef __GNUG__ -#pragma interface -#endif #define MAXVISSPRITES 128 @@ -69,8 +63,3 @@ R_ClipVisSprite #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/s_sound.c b/frosted-doom/s_sound.c index b0cdd68..f6d8be1 100644 --- a/frosted-doom/s_sound.c +++ b/frosted-doom/s_sound.c @@ -1,868 +1,307 @@ -// 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 #include -#include "i_system.h" #include "i_sound.h" +#include "i_system.h" + +#include "doomfeatures.h" +#include "deh_str.h" + +#include "doomstat.h" +#include "doomtype.h" + #include "sounds.h" #include "s_sound.h" -#include "z_zone.h" +#include "m_misc.h" #include "m_random.h" -#include "w_wad.h" +#include "m_argv.h" -#include "doomdef.h" #include "p_local.h" - -#include "doomstat.h" - - -// Purpose? -const char snd_prefixen[] -= { 'P', 'P', 'A', 'S', 'S', 'S', 'M', 'M', 'M', 'S', 'S', 'S' }; - -#define S_MAX_VOLUME 127 +#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) +// In the source code release: (160*FRACUNIT). Changed back to the +// Vanilla value of 200 (why was this changed?) +#define S_CLOSE_DIST (200 * FRACUNIT) -#define S_ATTENUATOR ((S_CLIPPING_DIST-S_CLOSE_DIST)>>FRACBITS) +// The range over which sound attenuates -// Adjustable by menu. -#define NORM_VOLUME snd_MaxVolume +#define S_ATTENUATOR ((S_CLIPPING_DIST - S_CLOSE_DIST) >> FRACBITS) -#define NORM_PITCH 128 -#define NORM_PRIORITY 64 -#define NORM_SEP 128 - -#define S_PITCH_PERTURB 1 -#define S_STEREO_SWING (96*0x10000) - -// percent attenuation from front to back -#define S_IFRACVOL 30 - -#define NA 0 -#define S_NUMCHANNELS 2 - - -// 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; +// Stereo separation +#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; +int sfxVolume = 8; +// Maximum volume of music. +int musicVolume = 8; -// whether songs are mus_paused -static boolean mus_paused; +// Internal volume level, ranging from 0-127 -// music currently being played -static musicinfo_t* mus_playing=0; +static int snd_SfxVolume; -// following is set -// by the defaults code in M_misc: -// number of channels available -int numChannels; +// Whether songs are mus_paused -static int nextcleanup; +static boolean mus_paused; +// Music currently being played +static musicinfo_t *mus_playing = NULL; -// -// Internals. -// -int -S_getChannel -( void* origin, - sfxinfo_t* sfxinfo ); - - -int -S_AdjustSoundParams -( mobj_t* listener, - mobj_t* source, - int* vol, - int* sep, - int* pitch ); - -void S_StopChannel(int cnum); - +// 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; + int i; - fprintf( stderr, "S_Init: default sfx volume %d\n", sfxVolume); + I_PrecacheSounds(S_sfx, NUMSFX); - // Whatever these did with DMX, these are rather dummies now. - I_SetChannels(); - - S_SetSfxVolume(sfxVolume); - // No music with Linux - another dummy. - S_SetMusicVolume(musicVolume); + S_SetSfxVolume(sfxVolume); + 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 ; isfxinfo) + { + // 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; isfxinfo == 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; + int cnum; + int mnum; - // kill all playing sounds at start of level - // (trust me - a good idea) - for (cnum=0 ; cnum mus_e3m9) - // mnum -= mus_e3m9; - - S_ChangeMusic(mnum, true); - - nextcleanup = 15; -} - - - - - -void -S_StartSoundAtVolume -( void* origin_p, - int sfx_id, - int volume ) -{ - - 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; - - 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 (!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); - - - // 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; i1) - { - for (i=0; ihandle); - mus_paused = true; - } -} - -void S_ResumeSound(void) -{ - if (mus_playing && mus_paused) - { - I_ResumeSong(mus_playing->handle); - mus_paused = false; - } -} - - -// -// Updates music & sounds -// -void S_UpdateSounds(void* listener_p) -{ - int audible; - int cnum; - int volume; - int sep; - int pitch; - sfxinfo_t* sfx; - channel_t* c; - - mobj_t* listener = (mobj_t*)listener_p; - - - - // Clean up unused data. - // This is currently not done for 16bit (sounds cached static). - // DOS 8bit remains. - /*if (gametic > nextcleanup) - { - for (i=1 ; i -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 ; cnumsfxinfo; - - 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); - } - } - } - // 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_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); - - 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 ) -{ - musicinfo_t* music; - char namebuf[9]; - - if ( (musicnum <= mus_None) - || (musicnum >= NUMMUSIC) ) - { - I_Error("Bad music number %d", musicnum); - } - else - music = &S_music[musicnum]; - - if (mus_playing == music) - return; - - // shutdown old music - S_StopMusic(); - - // get lumpnum if neccessary - if (!music->lumpnum) - { - sprintf(namebuf, "d_%s", 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); - - // play it - I_PlaySong(music->handle, looping); - - mus_playing = music; -} - - -void S_StopMusic(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 ; isfxinfo == channels[i].sfxinfo) - { - break; - } - } - - // degrade usefulness of sound data - c->sfxinfo->usefulness--; - - c->sfxinfo = 0; - } -} - - - -// -// 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 ) -{ - 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 - { - // distance effect - *vol = (snd_SfxVolume - * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) - / S_ATTENUATOR; - } - - return (*vol > 0); -} - - - - -// -// S_getChannel : +// S_GetChannel : // If none available, return -1. Otherwise channel #. // -int -S_getChannel -( void* origin, - sfxinfo_t* sfxinfo ) + +static int S_GetChannel(mobj_t *origin, sfxinfo_t *sfxinfo) { // channel number to use - int cnum; + int cnum; - channel_t* c; + channel_t* c; // Find an open channel - for (cnum=0 ; cnumpriority >= sfxinfo->priority) break; + // Look for lower priority + for (cnum=0 ; cnumpriority >= sfxinfo->priority) + { + break; + } + } - if (cnum == numChannels) - { - // FUCK! No lower priority. Sorry, Charlie. - return -1; - } - else - { - // Otherwise, kick out lower priority. - S_StopChannel(cnum); - } + if (cnum == snd_channels) + { + // FUCK! No lower priority. Sorry, Charlie. + return -1; + } + else + { + // Otherwise, kick out lower priority. + S_StopChannel(cnum); + } } c = &channels[cnum]; @@ -874,6 +313,358 @@ S_getChannel return cnum; } +// +// 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; + + // 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 + { + // distance effect + *vol = (snd_SfxVolume + * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) + / S_ATTENUATOR; + } + + return (*vol > 0); +} + +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; + + // 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) + { + 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_paused = true; + } +} + +void S_ResumeSound(void) +{ + if (mus_playing && mus_paused) + { + I_ResumeSong(); + mus_paused = false; + } +} + +// +// Updates music & sounds +// + +void S_UpdateSounds(mobj_t *listener) +{ + int audible; + int cnum; + int volume; + int sep; + sfxinfo_t* sfx; + channel_t* c; + + I_UpdateSound(); + + for (cnum=0; cnumsfxinfo; + + 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); + } + } + } +} + +void S_SetMusicVolume(int volume) +{ + if (volume < 0 || volume > 127) + { + I_Error("Attempt to set music volume at %d", + volume); + } + + I_SetMusicVolume(volume); +} + +void S_SetSfxVolume(int volume) +{ + if (volume < 0 || volume > 127) + { + 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) +{ + 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) + { + I_Error("Bad music number %d", musicnum); + } + else + { + music = &S_music[musicnum]; + } + + if (mus_playing == music) + { + return; + } + + // shutdown old music + S_StopMusic(); + + // get lumpnum if neccessary + if (!music->lumpnum) + { + M_snprintf(namebuf, sizeof(namebuf), "d_%s", DEH_String(music->name)); + music->lumpnum = W_GetNumForName(namebuf); + } + + music->data = W_CacheLumpNum(music->lumpnum, PU_STATIC); + + handle = I_RegisterSong(music->data, W_LumpLength(music->lumpnum)); + music->handle = handle; + I_PlaySong(handle, looping); + + mus_playing = music; +} + +boolean S_MusicPlaying(void) +{ + return I_MusicIsPlaying(); +} + +void S_StopMusic(void) +{ + if (mus_playing) + { + if (mus_paused) + { + I_ResumeSong(); + } + + I_StopSong(); + I_UnRegisterSong(mus_playing->handle); + W_ReleaseLumpNum(mus_playing->lumpnum); + mus_playing->data = NULL; + mus_playing = NULL; + } +} diff --git a/frosted-doom/s_sound.h b/frosted-doom/s_sound.h index ff95bcc..bbd100a 100644 --- a/frosted-doom/s_sound.h +++ b/frosted-doom/s_sound.h @@ -1,45 +1,40 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // The not so system specific sound interface. // -//----------------------------------------------------------------------------- #ifndef __S_SOUND__ #define __S_SOUND__ - -#ifdef __GNUG__ -#pragma interface -#endif - - +#include "p_mobj.h" +#include "sounds.h" // // Initializes sound stuff, including volume // Sets channels, SFX and music volume, // allocates channel buffer, sets S_sfx lookup. // -void -S_Init -( int sfxVolume, - int musicVolume ); +void S_Init(int sfxVolume, int musicVolume); + + +// Shut down sound + +void S_Shutdown(void); @@ -48,30 +43,18 @@ S_Init // Kills playing sounds at start of level, // determines music if any, changes music. // -void S_Start(void); +void S_Start(void); // // Start sound for thing at // using 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 -void S_StopSound(void* origin); +void S_StopSound(mobj_t *origin); // Start music using from sounds.h @@ -79,10 +62,10 @@ void S_StartMusic(int music_id); // Start music using from sounds.h, // and set whether looping -void -S_ChangeMusic -( int music_id, - int looping ); +void S_ChangeMusic(int music_id, int looping); + +// query if music is playing +boolean S_MusicPlaying(void); // Stops the music fer sure. void S_StopMusic(void); @@ -95,15 +78,12 @@ void S_ResumeSound(void); // // Updates music & sounds // -void S_UpdateSounds(void* listener); +void S_UpdateSounds(mobj_t *listener); void S_SetMusicVolume(int volume); void S_SetSfxVolume(int volume); +extern int snd_channels; #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- + diff --git a/frosted-doom/sha1.c b/frosted-doom/sha1.c new file mode 100644 index 0000000..06ab40a --- /dev/null +++ b/frosted-doom/sha1.c @@ -0,0 +1,319 @@ +/* sha1.c - SHA1 hash function + * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + * + * Please see below for more legal information! + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + + +/* 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 +#include +#include +#include + +#include "i_swap.h" +#include "sha1.h" + +void SHA1_Init(sha1_context_t *hd) +{ + hd->h0 = 0x67452301; + hd->h1 = 0xefcdab89; + hd->h2 = 0x98badcfe; + hd->h3 = 0x10325476; + hd->h4 = 0xc3d2e1f0; + hd->nblocks = 0; + hd->count = 0; +} + + +/**************** + * Transform the message X which consists of 16 32-bit-words + */ +static void Transform(sha1_context_t *hd, byte *data) +{ + uint32_t a,b,c,d,e,tm; + uint32_t x[16]; + + /* get values from the chaining vars */ + a = hd->h0; + b = hd->h1; + c = hd->h2; + d = hd->h3; + e = hd->h4; + +#ifdef SYS_BIG_ENDIAN + memcpy(x, data, 64); +#else + { + int i; + byte *p2; + for(i=0, p2=(byte*)x; i < 16; i++, p2 += 4 ) + { + p2[3] = *data++; + p2[2] = *data++; + p2[1] = *data++; + p2[0] = *data++; + } + } +#endif + + +#define K1 0x5A827999L +#define K2 0x6ED9EBA1L +#define K3 0x8F1BBCDCL +#define K4 0xCA62C1D6L +#define F1(x,y,z) ( z ^ ( x & ( y ^ z ) ) ) +#define F2(x,y,z) ( x ^ y ^ z ) +#define F3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) ) +#define F4(x,y,z) ( x ^ y ^ z ) + +#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) + +#define M(i) ( tm = x[i&0x0f] ^ x[(i-14)&0x0f] \ + ^ x[(i-8)&0x0f] ^ x[(i-3)&0x0f] \ + , (x[i&0x0f] = rol(tm,1)) ) + +#define R(a,b,c,d,e,f,k,m) do { e += rol( a, 5 ) \ + + f( b, c, d ) \ + + k \ + + m; \ + b = rol( b, 30 ); \ + } while(0) + R( a, b, c, d, e, F1, K1, x[ 0] ); + R( e, a, b, c, d, F1, K1, x[ 1] ); + R( d, e, a, b, c, F1, K1, x[ 2] ); + R( c, d, e, a, b, F1, K1, x[ 3] ); + R( b, c, d, e, a, F1, K1, x[ 4] ); + R( a, b, c, d, e, F1, K1, x[ 5] ); + R( e, a, b, c, d, F1, K1, x[ 6] ); + R( d, e, a, b, c, F1, K1, x[ 7] ); + R( c, d, e, a, b, F1, K1, x[ 8] ); + R( b, c, d, e, a, F1, K1, x[ 9] ); + R( a, b, c, d, e, F1, K1, x[10] ); + R( e, a, b, c, d, F1, K1, x[11] ); + R( d, e, a, b, c, F1, K1, x[12] ); + R( c, d, e, a, b, F1, K1, x[13] ); + R( b, c, d, e, a, F1, K1, x[14] ); + R( a, b, c, d, e, F1, K1, x[15] ); + R( e, a, b, c, d, F1, K1, M(16) ); + R( d, e, a, b, c, F1, K1, M(17) ); + R( c, d, e, a, b, F1, K1, M(18) ); + R( b, c, d, e, a, F1, K1, M(19) ); + R( a, b, c, d, e, F2, K2, M(20) ); + R( e, a, b, c, d, F2, K2, M(21) ); + R( d, e, a, b, c, F2, K2, M(22) ); + R( c, d, e, a, b, F2, K2, M(23) ); + R( b, c, d, e, a, F2, K2, M(24) ); + R( a, b, c, d, e, F2, K2, M(25) ); + R( e, a, b, c, d, F2, K2, M(26) ); + R( d, e, a, b, c, F2, K2, M(27) ); + R( c, d, e, a, b, F2, K2, M(28) ); + R( b, c, d, e, a, F2, K2, M(29) ); + R( a, b, c, d, e, F2, K2, M(30) ); + R( e, a, b, c, d, F2, K2, M(31) ); + R( d, e, a, b, c, F2, K2, M(32) ); + R( c, d, e, a, b, F2, K2, M(33) ); + R( b, c, d, e, a, F2, K2, M(34) ); + R( a, b, c, d, e, F2, K2, M(35) ); + R( e, a, b, c, d, F2, K2, M(36) ); + R( d, e, a, b, c, F2, K2, M(37) ); + R( c, d, e, a, b, F2, K2, M(38) ); + R( b, c, d, e, a, F2, K2, M(39) ); + R( a, b, c, d, e, F3, K3, M(40) ); + R( e, a, b, c, d, F3, K3, M(41) ); + R( d, e, a, b, c, F3, K3, M(42) ); + R( c, d, e, a, b, F3, K3, M(43) ); + R( b, c, d, e, a, F3, K3, M(44) ); + R( a, b, c, d, e, F3, K3, M(45) ); + R( e, a, b, c, d, F3, K3, M(46) ); + R( d, e, a, b, c, F3, K3, M(47) ); + R( c, d, e, a, b, F3, K3, M(48) ); + R( b, c, d, e, a, F3, K3, M(49) ); + R( a, b, c, d, e, F3, K3, M(50) ); + R( e, a, b, c, d, F3, K3, M(51) ); + R( d, e, a, b, c, F3, K3, M(52) ); + R( c, d, e, a, b, F3, K3, M(53) ); + R( b, c, d, e, a, F3, K3, M(54) ); + R( a, b, c, d, e, F3, K3, M(55) ); + R( e, a, b, c, d, F3, K3, M(56) ); + R( d, e, a, b, c, F3, K3, M(57) ); + R( c, d, e, a, b, F3, K3, M(58) ); + R( b, c, d, e, a, F3, K3, M(59) ); + R( a, b, c, d, e, F4, K4, M(60) ); + R( e, a, b, c, d, F4, K4, M(61) ); + R( d, e, a, b, c, F4, K4, M(62) ); + R( c, d, e, a, b, F4, K4, M(63) ); + R( b, c, d, e, a, F4, K4, M(64) ); + R( a, b, c, d, e, F4, K4, M(65) ); + R( e, a, b, c, d, F4, K4, M(66) ); + R( d, e, a, b, c, F4, K4, M(67) ); + R( c, d, e, a, b, F4, K4, M(68) ); + R( b, c, d, e, a, F4, K4, M(69) ); + R( a, b, c, d, e, F4, K4, M(70) ); + R( e, a, b, c, d, F4, K4, M(71) ); + R( d, e, a, b, c, F4, K4, M(72) ); + R( c, d, e, a, b, F4, K4, M(73) ); + R( b, c, d, e, a, F4, K4, M(74) ); + R( a, b, c, d, e, F4, K4, M(75) ); + R( e, a, b, c, d, F4, K4, M(76) ); + R( d, e, a, b, c, F4, K4, M(77) ); + R( c, d, e, a, b, F4, K4, M(78) ); + R( b, c, d, e, a, F4, K4, M(79) ); + + /* update chainig vars */ + hd->h0 += a; + hd->h1 += b; + hd->h2 += c; + hd->h3 += d; + hd->h4 += e; +} + + +/* Update the message digest with the contents + * of INBUF with length INLEN. + */ +void SHA1_Update(sha1_context_t *hd, byte *inbuf, size_t inlen) +{ + if (hd->count == 64) + { + /* flush the buffer */ + Transform(hd, hd->buf); + hd->count = 0; + hd->nblocks++; + } + if (!inbuf) + return; + if (hd->count) + { + for (; inlen && hd->count < 64; inlen--) + hd->buf[hd->count++] = *inbuf++; + SHA1_Update(hd, NULL, 0); + if (!inlen) + return; + } + + while (inlen >= 64) + { + Transform(hd, inbuf); + hd->count = 0; + hd->nblocks++; + inlen -= 64; + inbuf += 64; + } + for (; inlen && hd->count < 64; inlen--) + hd->buf[hd->count++] = *inbuf++; +} + + +/* The routine final terminates the computation and + * returns the digest. + * The handle is prepared for a new cycle, but adding bytes to the + * handle will the destroy the returned buffer. + * Returns: 20 bytes representing the digest. + */ + +void SHA1_Final(sha1_digest_t digest, sha1_context_t *hd) +{ + uint32_t t, msb, lsb; + byte *p; + + SHA1_Update(hd, NULL, 0); /* flush */; + + t = hd->nblocks; + /* multiply by 64 to make a byte count */ + lsb = t << 6; + msb = t >> 26; + /* add the count */ + t = lsb; + if ((lsb += hd->count) < t) + msb++; + /* multiply by 8 to make a bit count */ + t = lsb; + lsb <<= 3; + msb <<= 3; + msb |= t >> 29; + + if (hd->count < 56) + { + /* enough room */ + hd->buf[hd->count++] = 0x80; /* pad */ + while (hd->count < 56) + hd->buf[hd->count++] = 0; /* pad */ + } + else + { + /* need one extra block */ + hd->buf[hd->count++] = 0x80; /* pad character */ + while (hd->count < 64) + hd->buf[hd->count++] = 0; + SHA1_Update(hd, NULL, 0); /* flush */; + memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ + } + /* append the 64 bit count */ + hd->buf[56] = msb >> 24; + hd->buf[57] = msb >> 16; + hd->buf[58] = msb >> 8; + hd->buf[59] = msb ; + hd->buf[60] = lsb >> 24; + hd->buf[61] = lsb >> 16; + hd->buf[62] = lsb >> 8; + hd->buf[63] = lsb ; + Transform(hd, hd->buf); + + p = hd->buf; +#ifdef SYS_BIG_ENDIAN +#define X(a) do { *(uint32_t*)p = hd->h##a ; p += 4; } while(0) +#else /* little endian */ +#define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \ + *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while(0) +#endif + X(0); + X(1); + X(2); + X(3); + X(4); +#undef X + + memcpy(digest, hd->buf, sizeof(sha1_digest_t)); +} + +void SHA1_UpdateInt32(sha1_context_t *context, unsigned int val) +{ + byte buf[4]; + + buf[0] = (val >> 24) & 0xff; + buf[1] = (val >> 16) & 0xff; + buf[2] = (val >> 8) & 0xff; + buf[3] = val & 0xff; + + SHA1_Update(context, buf, 4); +} + +void SHA1_UpdateString(sha1_context_t *context, char *str) +{ + SHA1_Update(context, (byte *) str, strlen(str) + 1); +} + diff --git a/frosted-doom/sha1.h b/frosted-doom/sha1.h new file mode 100644 index 0000000..249571b --- /dev/null +++ b/frosted-doom/sha1.h @@ -0,0 +1,40 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// SHA-1 digest. +// + +#ifndef __SHA1_H__ +#define __SHA1_H__ + +#include "doomtype.h" + +typedef struct sha1_context_s sha1_context_t; +typedef byte sha1_digest_t[20]; + +struct sha1_context_s { + uint32_t h0,h1,h2,h3,h4; + uint32_t nblocks; + byte buf[64]; + int count; +}; + +void SHA1_Init(sha1_context_t *context); +void SHA1_Update(sha1_context_t *context, byte *buf, size_t len); +void SHA1_Final(sha1_digest_t digest, sha1_context_t *context); +void SHA1_UpdateInt32(sha1_context_t *context, unsigned int val); +void SHA1_UpdateString(sha1_context_t *context, char *str); + +#endif /* #ifndef __SHA1_H__ */ + diff --git a/frosted-doom/sounds.c b/frosted-doom/sounds.c index 0fea8a2..e976bc8 100644 --- a/frosted-doom/sounds.c +++ b/frosted-doom/sounds.c @@ -1,30 +1,24 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Created by a sound utility. // Kept as a sample, DOOM2 sounds. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: sounds.c,v 1.3 1997/01/29 22:40:44 b1 Exp $"; +#include #include "doomtype.h" @@ -34,76 +28,79 @@ rcsid[] = "$Id: sounds.c,v 1.3 1997/01/29 22:40:44 b1 Exp $"; // Information about all the music // +#define MUSIC(name) \ + { name, 0, NULL, NULL } + musicinfo_t S_music[] = { - { 0 }, - { "e1m1", 0 }, - { "e1m2", 0 }, - { "e1m3", 0 }, - { "e1m4", 0 }, - { "e1m5", 0 }, - { "e1m6", 0 }, - { "e1m7", 0 }, - { "e1m8", 0 }, - { "e1m9", 0 }, - { "e2m1", 0 }, - { "e2m2", 0 }, - { "e2m3", 0 }, - { "e2m4", 0 }, - { "e2m5", 0 }, - { "e2m6", 0 }, - { "e2m7", 0 }, - { "e2m8", 0 }, - { "e2m9", 0 }, - { "e3m1", 0 }, - { "e3m2", 0 }, - { "e3m3", 0 }, - { "e3m4", 0 }, - { "e3m5", 0 }, - { "e3m6", 0 }, - { "e3m7", 0 }, - { "e3m8", 0 }, - { "e3m9", 0 }, - { "inter", 0 }, - { "intro", 0 }, - { "bunny", 0 }, - { "victor", 0 }, - { "introa", 0 }, - { "runnin", 0 }, - { "stalks", 0 }, - { "countd", 0 }, - { "betwee", 0 }, - { "doom", 0 }, - { "the_da", 0 }, - { "shawn", 0 }, - { "ddtblu", 0 }, - { "in_cit", 0 }, - { "dead", 0 }, - { "stlks2", 0 }, - { "theda2", 0 }, - { "doom2", 0 }, - { "ddtbl2", 0 }, - { "runni2", 0 }, - { "dead2", 0 }, - { "stlks3", 0 }, - { "romero", 0 }, - { "shawn2", 0 }, - { "messag", 0 }, - { "count2", 0 }, - { "ddtbl3", 0 }, - { "ampie", 0 }, - { "theda3", 0 }, - { "adrian", 0 }, - { "messg2", 0 }, - { "romer2", 0 }, - { "tense", 0 }, - { "shawn3", 0 }, - { "openin", 0 }, - { "evil", 0 }, - { "ultima", 0 }, - { "read_m", 0 }, - { "dm2ttl", 0 }, - { "dm2int", 0 } + MUSIC(NULL), + MUSIC("e1m1"), + MUSIC("e1m2"), + MUSIC("e1m3"), + MUSIC("e1m4"), + MUSIC("e1m5"), + MUSIC("e1m6"), + MUSIC("e1m7"), + MUSIC("e1m8"), + MUSIC("e1m9"), + MUSIC("e2m1"), + MUSIC("e2m2"), + MUSIC("e2m3"), + MUSIC("e2m4"), + MUSIC("e2m5"), + MUSIC("e2m6"), + MUSIC("e2m7"), + MUSIC("e2m8"), + MUSIC("e2m9"), + MUSIC("e3m1"), + MUSIC("e3m2"), + MUSIC("e3m3"), + MUSIC("e3m4"), + MUSIC("e3m5"), + MUSIC("e3m6"), + MUSIC("e3m7"), + MUSIC("e3m8"), + MUSIC("e3m9"), + MUSIC("inter"), + MUSIC("intro"), + MUSIC("bunny"), + MUSIC("victor"), + MUSIC("introa"), + MUSIC("runnin"), + MUSIC("stalks"), + MUSIC("countd"), + MUSIC("betwee"), + MUSIC("doom"), + MUSIC("the_da"), + MUSIC("shawn"), + MUSIC("ddtblu"), + MUSIC("in_cit"), + MUSIC("dead"), + MUSIC("stlks2"), + MUSIC("theda2"), + MUSIC("doom2"), + MUSIC("ddtbl2"), + MUSIC("runni2"), + MUSIC("dead2"), + MUSIC("stlks3"), + MUSIC("romero"), + MUSIC("shawn2"), + MUSIC("messag"), + MUSIC("count2"), + MUSIC("ddtbl3"), + MUSIC("ampie"), + MUSIC("theda3"), + MUSIC("adrian"), + MUSIC("messg2"), + MUSIC("romer2"), + MUSIC("tense"), + MUSIC("shawn3"), + MUSIC("openin"), + MUSIC("evil"), + MUSIC("ultima"), + MUSIC("read_m"), + MUSIC("dm2ttl"), + MUSIC("dm2int") }; @@ -111,118 +108,122 @@ musicinfo_t S_music[] = // Information about all the sfx // +#define SOUND(name, priority) \ + { NULL, name, priority, NULL, -1, -1, 0, 0, -1, NULL } +#define SOUND_LINK(name, priority, link_id, pitch, volume) \ + { NULL, name, priority, &S_sfx[link_id], pitch, volume, 0, 0, -1, NULL } + sfxinfo_t S_sfx[] = { // S_sfx[0] needs to be a dummy for odd reasons. - { "none", false, 0, 0, -1, -1, 0 }, - - { "pistol", false, 64, 0, -1, -1, 0 }, - { "shotgn", false, 64, 0, -1, -1, 0 }, - { "sgcock", false, 64, 0, -1, -1, 0 }, - { "dshtgn", false, 64, 0, -1, -1, 0 }, - { "dbopn", false, 64, 0, -1, -1, 0 }, - { "dbcls", false, 64, 0, -1, -1, 0 }, - { "dbload", false, 64, 0, -1, -1, 0 }, - { "plasma", false, 64, 0, -1, -1, 0 }, - { "bfg", false, 64, 0, -1, -1, 0 }, - { "sawup", false, 64, 0, -1, -1, 0 }, - { "sawidl", false, 118, 0, -1, -1, 0 }, - { "sawful", false, 64, 0, -1, -1, 0 }, - { "sawhit", false, 64, 0, -1, -1, 0 }, - { "rlaunc", false, 64, 0, -1, -1, 0 }, - { "rxplod", false, 70, 0, -1, -1, 0 }, - { "firsht", false, 70, 0, -1, -1, 0 }, - { "firxpl", false, 70, 0, -1, -1, 0 }, - { "pstart", false, 100, 0, -1, -1, 0 }, - { "pstop", false, 100, 0, -1, -1, 0 }, - { "doropn", false, 100, 0, -1, -1, 0 }, - { "dorcls", false, 100, 0, -1, -1, 0 }, - { "stnmov", false, 119, 0, -1, -1, 0 }, - { "swtchn", false, 78, 0, -1, -1, 0 }, - { "swtchx", false, 78, 0, -1, -1, 0 }, - { "plpain", false, 96, 0, -1, -1, 0 }, - { "dmpain", false, 96, 0, -1, -1, 0 }, - { "popain", false, 96, 0, -1, -1, 0 }, - { "vipain", false, 96, 0, -1, -1, 0 }, - { "mnpain", false, 96, 0, -1, -1, 0 }, - { "pepain", false, 96, 0, -1, -1, 0 }, - { "slop", false, 78, 0, -1, -1, 0 }, - { "itemup", true, 78, 0, -1, -1, 0 }, - { "wpnup", true, 78, 0, -1, -1, 0 }, - { "oof", false, 96, 0, -1, -1, 0 }, - { "telept", false, 32, 0, -1, -1, 0 }, - { "posit1", true, 98, 0, -1, -1, 0 }, - { "posit2", true, 98, 0, -1, -1, 0 }, - { "posit3", true, 98, 0, -1, -1, 0 }, - { "bgsit1", true, 98, 0, -1, -1, 0 }, - { "bgsit2", true, 98, 0, -1, -1, 0 }, - { "sgtsit", true, 98, 0, -1, -1, 0 }, - { "cacsit", true, 98, 0, -1, -1, 0 }, - { "brssit", true, 94, 0, -1, -1, 0 }, - { "cybsit", true, 92, 0, -1, -1, 0 }, - { "spisit", true, 90, 0, -1, -1, 0 }, - { "bspsit", true, 90, 0, -1, -1, 0 }, - { "kntsit", true, 90, 0, -1, -1, 0 }, - { "vilsit", true, 90, 0, -1, -1, 0 }, - { "mansit", true, 90, 0, -1, -1, 0 }, - { "pesit", true, 90, 0, -1, -1, 0 }, - { "sklatk", false, 70, 0, -1, -1, 0 }, - { "sgtatk", false, 70, 0, -1, -1, 0 }, - { "skepch", false, 70, 0, -1, -1, 0 }, - { "vilatk", false, 70, 0, -1, -1, 0 }, - { "claw", false, 70, 0, -1, -1, 0 }, - { "skeswg", false, 70, 0, -1, -1, 0 }, - { "pldeth", false, 32, 0, -1, -1, 0 }, - { "pdiehi", false, 32, 0, -1, -1, 0 }, - { "podth1", false, 70, 0, -1, -1, 0 }, - { "podth2", false, 70, 0, -1, -1, 0 }, - { "podth3", false, 70, 0, -1, -1, 0 }, - { "bgdth1", false, 70, 0, -1, -1, 0 }, - { "bgdth2", false, 70, 0, -1, -1, 0 }, - { "sgtdth", false, 70, 0, -1, -1, 0 }, - { "cacdth", false, 70, 0, -1, -1, 0 }, - { "skldth", false, 70, 0, -1, -1, 0 }, - { "brsdth", false, 32, 0, -1, -1, 0 }, - { "cybdth", false, 32, 0, -1, -1, 0 }, - { "spidth", false, 32, 0, -1, -1, 0 }, - { "bspdth", false, 32, 0, -1, -1, 0 }, - { "vildth", false, 32, 0, -1, -1, 0 }, - { "kntdth", false, 32, 0, -1, -1, 0 }, - { "pedth", false, 32, 0, -1, -1, 0 }, - { "skedth", false, 32, 0, -1, -1, 0 }, - { "posact", true, 120, 0, -1, -1, 0 }, - { "bgact", true, 120, 0, -1, -1, 0 }, - { "dmact", true, 120, 0, -1, -1, 0 }, - { "bspact", true, 100, 0, -1, -1, 0 }, - { "bspwlk", true, 100, 0, -1, -1, 0 }, - { "vilact", true, 100, 0, -1, -1, 0 }, - { "noway", false, 78, 0, -1, -1, 0 }, - { "barexp", false, 60, 0, -1, -1, 0 }, - { "punch", false, 64, 0, -1, -1, 0 }, - { "hoof", false, 70, 0, -1, -1, 0 }, - { "metal", false, 70, 0, -1, -1, 0 }, - { "chgun", false, 64, &S_sfx[sfx_pistol], 150, 0, 0 }, - { "tink", false, 60, 0, -1, -1, 0 }, - { "bdopn", false, 100, 0, -1, -1, 0 }, - { "bdcls", false, 100, 0, -1, -1, 0 }, - { "itmbk", false, 100, 0, -1, -1, 0 }, - { "flame", false, 32, 0, -1, -1, 0 }, - { "flamst", false, 32, 0, -1, -1, 0 }, - { "getpow", false, 60, 0, -1, -1, 0 }, - { "bospit", false, 70, 0, -1, -1, 0 }, - { "boscub", false, 70, 0, -1, -1, 0 }, - { "bossit", false, 70, 0, -1, -1, 0 }, - { "bospn", false, 70, 0, -1, -1, 0 }, - { "bosdth", false, 70, 0, -1, -1, 0 }, - { "manatk", false, 70, 0, -1, -1, 0 }, - { "mandth", false, 70, 0, -1, -1, 0 }, - { "sssit", false, 70, 0, -1, -1, 0 }, - { "ssdth", false, 70, 0, -1, -1, 0 }, - { "keenpn", false, 70, 0, -1, -1, 0 }, - { "keendt", false, 70, 0, -1, -1, 0 }, - { "skeact", false, 70, 0, -1, -1, 0 }, - { "skesit", false, 70, 0, -1, -1, 0 }, - { "skeatk", false, 70, 0, -1, -1, 0 }, - { "radio", false, 60, 0, -1, -1, 0 } + SOUND("none", 0), + SOUND("pistol", 64), + SOUND("shotgn", 64), + SOUND("sgcock", 64), + SOUND("dshtgn", 64), + SOUND("dbopn", 64), + SOUND("dbcls", 64), + SOUND("dbload", 64), + SOUND("plasma", 64), + SOUND("bfg", 64), + SOUND("sawup", 64), + SOUND("sawidl", 118), + SOUND("sawful", 64), + SOUND("sawhit", 64), + SOUND("rlaunc", 64), + SOUND("rxplod", 70), + SOUND("firsht", 70), + SOUND("firxpl", 70), + SOUND("pstart", 100), + SOUND("pstop", 100), + SOUND("doropn", 100), + SOUND("dorcls", 100), + SOUND("stnmov", 119), + SOUND("swtchn", 78), + SOUND("swtchx", 78), + SOUND("plpain", 96), + SOUND("dmpain", 96), + SOUND("popain", 96), + SOUND("vipain", 96), + SOUND("mnpain", 96), + SOUND("pepain", 96), + SOUND("slop", 78), + SOUND("itemup", 78), + SOUND("wpnup", 78), + SOUND("oof", 96), + SOUND("telept", 32), + SOUND("posit1", 98), + SOUND("posit2", 98), + SOUND("posit3", 98), + SOUND("bgsit1", 98), + SOUND("bgsit2", 98), + SOUND("sgtsit", 98), + SOUND("cacsit", 98), + SOUND("brssit", 94), + SOUND("cybsit", 92), + SOUND("spisit", 90), + SOUND("bspsit", 90), + SOUND("kntsit", 90), + SOUND("vilsit", 90), + SOUND("mansit", 90), + SOUND("pesit", 90), + SOUND("sklatk", 70), + SOUND("sgtatk", 70), + SOUND("skepch", 70), + SOUND("vilatk", 70), + SOUND("claw", 70), + SOUND("skeswg", 70), + SOUND("pldeth", 32), + SOUND("pdiehi", 32), + SOUND("podth1", 70), + SOUND("podth2", 70), + SOUND("podth3", 70), + SOUND("bgdth1", 70), + SOUND("bgdth2", 70), + SOUND("sgtdth", 70), + SOUND("cacdth", 70), + SOUND("skldth", 70), + SOUND("brsdth", 32), + SOUND("cybdth", 32), + SOUND("spidth", 32), + SOUND("bspdth", 32), + SOUND("vildth", 32), + SOUND("kntdth", 32), + SOUND("pedth", 32), + SOUND("skedth", 32), + SOUND("posact", 120), + SOUND("bgact", 120), + SOUND("dmact", 120), + SOUND("bspact", 100), + SOUND("bspwlk", 100), + SOUND("vilact", 100), + SOUND("noway", 78), + SOUND("barexp", 60), + SOUND("punch", 64), + SOUND("hoof", 70), + SOUND("metal", 70), + SOUND_LINK("chgun", 64, sfx_pistol, 150, 0), + SOUND("tink", 60), + SOUND("bdopn", 100), + SOUND("bdcls", 100), + SOUND("itmbk", 100), + SOUND("flame", 32), + SOUND("flamst", 32), + SOUND("getpow", 60), + SOUND("bospit", 70), + SOUND("boscub", 70), + SOUND("bossit", 70), + SOUND("bospn", 70), + SOUND("bosdth", 70), + SOUND("manatk", 70), + SOUND("mandth", 70), + SOUND("sssit", 70), + SOUND("ssdth", 70), + SOUND("keenpn", 70), + SOUND("keendt", 70), + SOUND("skeact", 70), + SOUND("skesit", 70), + SOUND("skeatk", 70), + SOUND("radio", 60), }; diff --git a/frosted-doom/sounds.h b/frosted-doom/sounds.h index 02ceedf..1e8afc4 100644 --- a/frosted-doom/sounds.h +++ b/frosted-doom/sounds.h @@ -1,90 +1,26 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Created by the sound utility written by Dave Taylor. // Kept as a sample, DOOM2 sounds. Frozen. // -//----------------------------------------------------------------------------- #ifndef __SOUNDS__ #define __SOUNDS__ - -// -// SoundFX struct. -// -typedef struct sfxinfo_struct sfxinfo_t; - -struct sfxinfo_struct -{ - // up to 6-character name - char* name; - - // Sfx singularity (only one at a time) - int singularity; - - // Sfx priority - int priority; - - // referenced sound if a link - sfxinfo_t* link; - - // pitch if a link - int pitch; - - // volume if a link - int volume; - - // sound data - void* data; - - // this is checked every second to see if sound - // can be thrown out (if 0, then decrement, if -1, - // then throw out, if > 0, then it is in use) - int usefulness; - - // lump number of sfx - int lumpnum; -}; - - - - -// -// MusicInfo struct. -// -typedef struct -{ - // up to 6-character name - char* name; - - // lump number of music - int lumpnum; - - // music data - void* data; - - // music handle once registered - int handle; - -} musicinfo_t; - - - +#include "i_sound.h" // the complete set of sound effects extern sfxinfo_t S_sfx[]; @@ -289,9 +225,3 @@ typedef enum } sfxenum_t; #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- - diff --git a/frosted-doom/st_lib.c b/frosted-doom/st_lib.c index 1f060cf..7ce978d 100644 --- a/frosted-doom/st_lib.c +++ b/frosted-doom/st_lib.c @@ -1,39 +1,32 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // The status bar widget code. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: st_lib.c,v 1.4 1997/02/03 16:47:56 b1 Exp $"; - +#include #include +#include "deh_main.h" #include "doomdef.h" #include "z_zone.h" #include "v_video.h" -#include "m_swap.h" - +#include "i_swap.h" #include "i_system.h" #include "w_wad.h" @@ -57,7 +50,7 @@ patch_t* sttminus; void STlib_init(void) { - sttminus = (patch_t *) W_CacheLumpName("STTMINUS", PU_STATIC); + sttminus = (patch_t *) W_CacheLumpName(DEH_String("STTMINUS"), PU_STATIC); } @@ -122,7 +115,7 @@ STlib_drawNum if (n->y - ST_Y < 0) I_Error("drawNum: n->y - ST_Y < 0"); - V_CopyRect(x, n->y - ST_Y, BG, w*numdigits, h, x, n->y, FG); + V_CopyRect(x, n->y - ST_Y, st_backing_screen, w*numdigits, h, x, n->y); // if non-number, do not draw it if (num == 1994) @@ -132,19 +125,19 @@ STlib_drawNum // in the special case of 0, you draw 0 if (!num) - V_DrawPatch(x - w, n->y, FG, n->p[ 0 ]); + V_DrawPatch(x - w, n->y, n->p[ 0 ]); // draw the new number while (num && numdigits--) { x -= w; - V_DrawPatch(x, n->y, FG, n->p[ num % 10 ]); + V_DrawPatch(x, n->y, n->p[ num % 10 ]); num /= 10; } // draw a minus sign if necessary if (neg) - V_DrawPatch(x - 8, n->y, FG, sttminus); + V_DrawPatch(x - 8, n->y, sttminus); } @@ -182,7 +175,7 @@ STlib_updatePercent int refresh ) { if (refresh && *per->n.on) - V_DrawPatch(per->n.x, per->n.y, FG, per->p); + V_DrawPatch(per->n.x, per->n.y, per->p); STlib_updateNum(&per->n, refresh); } @@ -218,9 +211,7 @@ STlib_updateMultIcon int x; int y; - if (*mi->on - && (mi->oldinum != *mi->inum || refresh) - && (*mi->inum!=-1)) + if (*mi->on && (mi->oldinum != *mi->inum || refresh) && (*mi->inum != -1)) { if (mi->oldinum != -1) { @@ -232,9 +223,9 @@ STlib_updateMultIcon if (y - ST_Y < 0) I_Error("updateMultIcon: y - ST_Y < 0"); - V_CopyRect(x, y-ST_Y, BG, w, h, x, y, FG); + V_CopyRect(x, y-ST_Y, st_backing_screen, w, h, x, y); } - V_DrawPatch(mi->x, mi->y, FG, mi->p[*mi->inum]); + V_DrawPatch(mi->x, mi->y, mi->p[*mi->inum]); mi->oldinum = *mi->inum; } } @@ -252,7 +243,7 @@ STlib_initBinIcon { b->x = x; b->y = y; - b->oldval = 0; + b->oldval = false; b->val = val; b->on = on; b->p = i; @@ -271,7 +262,7 @@ STlib_updateBinIcon int h; if (*bi->on - && (bi->oldval != *bi->val || refresh)) + && (bi->oldval != *bi->val || refresh)) { x = bi->x - SHORT(bi->p->leftoffset); y = bi->y - SHORT(bi->p->topoffset); @@ -282,9 +273,9 @@ STlib_updateBinIcon I_Error("updateBinIcon: y - ST_Y < 0"); if (*bi->val) - V_DrawPatch(bi->x, bi->y, FG, bi->p); + V_DrawPatch(bi->x, bi->y, bi->p); else - V_CopyRect(x, y-ST_Y, BG, w, h, x, y, FG); + V_CopyRect(x, y-ST_Y, st_backing_screen, w, h, x, y); bi->oldval = *bi->val; } diff --git a/frosted-doom/st_lib.h b/frosted-doom/st_lib.h index de06977..3a8f521 100644 --- a/frosted-doom/st_lib.h +++ b/frosted-doom/st_lib.h @@ -1,23 +1,20 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // The status bar widget code. // -//----------------------------------------------------------------------------- #ifndef __STLIB__ #define __STLIB__ @@ -26,15 +23,6 @@ // We are referring to patches. #include "r_defs.h" - -// -// Background and foreground screen numbers -// -#define BG 4 -#define FG 0 - - - // // Typedefs of widgets // @@ -122,7 +110,7 @@ typedef struct int y; // last icon value - int oldval; + boolean oldval; // pointer to current icon status boolean* val; @@ -219,8 +207,3 @@ STlib_updateBinIcon boolean refresh ); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/st_stuff.c b/frosted-doom/st_stuff.c index 16f2e3f..e25accc 100644 --- a/frosted-doom/st_stuff.c +++ b/frosted-doom/st_stuff.c @@ -1,30 +1,23 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Status bar code. // Does the face/direction indicator animatin. // Does palette indicators as well (red pain/berserk, bright pickup) // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: st_stuff.c,v 1.6 1997/02/03 22:45:13 b1 Exp $"; #include @@ -32,10 +25,14 @@ rcsid[] = "$Id: st_stuff.c,v 1.6 1997/02/03 22:45:13 b1 Exp $"; #include "i_system.h" #include "i_video.h" #include "z_zone.h" +#include "m_misc.h" #include "m_random.h" #include "w_wad.h" +#include "deh_main.h" +#include "deh_misc.h" #include "doomdef.h" +#include "doomkeys.h" #include "g_game.h" @@ -256,15 +253,14 @@ rcsid[] = "$Id: st_stuff.c,v 1.6 1997/02/03 22:45:13 b1 Exp $"; // Height, in lines. #define ST_OUTHEIGHT 1 -#define ST_MAPWIDTH \ - (strlen(mapnames[(gameepisode-1)*9+(gamemap-1)])) - #define ST_MAPTITLEX \ (SCREENWIDTH - ST_MAPWIDTH * ST_CHATFONTWIDTH) #define ST_MAPTITLEY 0 #define ST_MAPHEIGHT 1 +// graphics are drawn to a backing screen and blitted to the real screen +byte *st_backing_screen; // main player in game static player_t* plyr; @@ -272,9 +268,6 @@ static player_t* plyr; // ST_Start() has just been called static boolean st_firsttime; -// used to execute ST_Init() only once -static int veryfirsttime = 1; - // lump number for PLAYPAL static int lu_palette; @@ -392,103 +385,27 @@ static int keyboxes[3]; // a random number per tick static int st_randomnumber; - - -// Massive bunches of cheat shit -// to keep it from being easy to figure them out. -// Yeah, right... -unsigned char cheat_mus_seq[] = -{ - 0xb2, 0x26, 0xb6, 0xae, 0xea, 1, 0, 0, 0xff -}; - -unsigned char cheat_choppers_seq[] = -{ - 0xb2, 0x26, 0xe2, 0x32, 0xf6, 0x2a, 0x2a, 0xa6, 0x6a, 0xea, 0xff // id... -}; - -unsigned char cheat_god_seq[] = -{ - 0xb2, 0x26, 0x26, 0xaa, 0x26, 0xff // iddqd -}; - -unsigned char cheat_ammo_seq[] = -{ - 0xb2, 0x26, 0xf2, 0x66, 0xa2, 0xff // idkfa -}; - -unsigned char cheat_ammonokey_seq[] = -{ - 0xb2, 0x26, 0x66, 0xa2, 0xff // idfa -}; - - -// Smashing Pumpkins Into Samml Piles Of Putried Debris. -unsigned char cheat_noclip_seq[] = -{ - 0xb2, 0x26, 0xea, 0x2a, 0xb2, // idspispopd - 0xea, 0x2a, 0xf6, 0x2a, 0x26, 0xff -}; - -// -unsigned char cheat_commercial_noclip_seq[] = -{ - 0xb2, 0x26, 0xe2, 0x36, 0xb2, 0x2a, 0xff // idclip -}; - - - -unsigned char cheat_powerup_seq[7][10] = -{ - { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0x6e, 0xff }, // beholdv - { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0xea, 0xff }, // beholds - { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0xb2, 0xff }, // beholdi - { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0x6a, 0xff }, // beholdr - { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0xa2, 0xff }, // beholda - { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0x36, 0xff }, // beholdl - { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0xff } // behold -}; - - -unsigned char cheat_clev_seq[] = -{ - 0xb2, 0x26, 0xe2, 0x36, 0xa6, 0x6e, 1, 0, 0, 0xff // idclev -}; - - -// my position cheat -unsigned char cheat_mypos_seq[] = -{ - 0xb2, 0x26, 0xb6, 0xba, 0x2a, 0xf6, 0xea, 0xff // idmypos -}; - - -// Now what? -cheatseq_t cheat_mus = { cheat_mus_seq, 0 }; -cheatseq_t cheat_god = { cheat_god_seq, 0 }; -cheatseq_t cheat_ammo = { cheat_ammo_seq, 0 }; -cheatseq_t cheat_ammonokey = { cheat_ammonokey_seq, 0 }; -cheatseq_t cheat_noclip = { cheat_noclip_seq, 0 }; -cheatseq_t cheat_commercial_noclip = { cheat_commercial_noclip_seq, 0 }; +cheatseq_t cheat_mus = CHEAT("idmus", 2); +cheatseq_t cheat_god = CHEAT("iddqd", 0); +cheatseq_t cheat_ammo = CHEAT("idkfa", 0); +cheatseq_t cheat_ammonokey = CHEAT("idfa", 0); +cheatseq_t cheat_noclip = CHEAT("idspispopd", 0); +cheatseq_t cheat_commercial_noclip = CHEAT("idclip", 0); cheatseq_t cheat_powerup[7] = { - { cheat_powerup_seq[0], 0 }, - { cheat_powerup_seq[1], 0 }, - { cheat_powerup_seq[2], 0 }, - { cheat_powerup_seq[3], 0 }, - { cheat_powerup_seq[4], 0 }, - { cheat_powerup_seq[5], 0 }, - { cheat_powerup_seq[6], 0 } + CHEAT("idbeholdv", 0), + CHEAT("idbeholds", 0), + CHEAT("idbeholdi", 0), + CHEAT("idbeholdr", 0), + CHEAT("idbeholda", 0), + CHEAT("idbeholdl", 0), + CHEAT("idbehold", 0), }; -cheatseq_t cheat_choppers = { cheat_choppers_seq, 0 }; -cheatseq_t cheat_clev = { cheat_clev_seq, 0 }; -cheatseq_t cheat_mypos = { cheat_mypos_seq, 0 }; - - -// -extern char* mapnames[]; +cheatseq_t cheat_choppers = CHEAT("idchoppers", 0); +cheatseq_t cheat_clev = CHEAT("idclev", 2); +cheatseq_t cheat_mypos = CHEAT("idmypos", 0); // @@ -501,12 +418,16 @@ void ST_refreshBackground(void) if (st_statusbaron) { - V_DrawPatch(ST_X, 0, BG, sbar); + V_UseBuffer(st_backing_screen); + + V_DrawPatch(ST_X, 0, sbar); if (netgame) - V_DrawPatch(ST_FX, 0, BG, faceback); + V_DrawPatch(ST_FX, 0, faceback); - V_CopyRect(ST_X, 0, BG, ST_WIDTH, ST_HEIGHT, ST_X, ST_Y, FG); + V_RestoreBuffer(); + + V_CopyRect(ST_X, 0, st_backing_screen, ST_WIDTH, ST_HEIGHT, ST_X, ST_Y); } } @@ -540,13 +461,10 @@ ST_Responder (event_t* ev) // if a user keypress... else if (ev->type == ev_keydown) { - if (!netgame) + if (!netgame && gameskill != sk_nightmare) { - // b. - enabled for more debug fun. - // if (gameskill != sk_nightmare) { - // 'dqd' cheat for toggleable god mode - if (cht_CheckCheat(&cheat_god, ev->data1)) + if (cht_CheckCheat(&cheat_god, ev->data2)) { plyr->cheats ^= CF_GODMODE; if (plyr->cheats & CF_GODMODE) @@ -554,17 +472,17 @@ ST_Responder (event_t* ev) if (plyr->mo) plyr->mo->health = 100; - plyr->health = 100; - plyr->message = STSTR_DQDON; + plyr->health = deh_god_mode_health; + plyr->message = DEH_String(STSTR_DQDON); } else - plyr->message = STSTR_DQDOFF; + plyr->message = DEH_String(STSTR_DQDOFF); } // 'fa' cheat for killer fucking arsenal - else if (cht_CheckCheat(&cheat_ammonokey, ev->data1)) + else if (cht_CheckCheat(&cheat_ammonokey, ev->data2)) { - plyr->armorpoints = 200; - plyr->armortype = 2; + plyr->armorpoints = deh_idfa_armor; + plyr->armortype = deh_idfa_armor_class; for (i=0;iweaponowned[i] = true; @@ -572,13 +490,13 @@ ST_Responder (event_t* ev) for (i=0;iammo[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;iweaponowned[i] = true; @@ -589,24 +507,29 @@ ST_Responder (event_t* ev) for (i=0;icards[i] = true; - plyr->message = STSTR_KFAADDED; + plyr->message = DEH_String(STSTR_KFAADDED); } // 'mus' cheat for changing music - else if (cht_CheckCheat(&cheat_mus, ev->data1)) + else if (cht_CheckCheat(&cheat_mus, ev->data2)) { char buf[3]; int musnum; - plyr->message = STSTR_MUS; + plyr->message = DEH_String(STSTR_MUS); cht_GetParam(&cheat_mus, buf); - - if (gamemode == commercial) + + // Note: The original v1.9 had a bug that tried to play back + // the Doom II music regardless of gamemode. This was fixed + // in the Ultimate Doom executable so that it would work for + // the Doom 1 music as well. + + if (gamemode == commercial || gameversion < exe_ultimate) { musnum = mus_runnin + (buf[0]-'0')*10 + buf[1]-'0' - 1; if (((buf[0]-'0')*10 + buf[1]-'0') > 35) - plyr->message = STSTR_NOMUS; + plyr->message = DEH_String(STSTR_NOMUS); else S_ChangeMusic(musnum, 1); } @@ -615,27 +538,31 @@ ST_Responder (event_t* ev) musnum = mus_e1m1 + (buf[0]-'1')*9 + (buf[1]-'1'); if (((buf[0]-'1')*9 + buf[1]-'1') > 31) - plyr->message = STSTR_NOMUS; + plyr->message = DEH_String(STSTR_NOMUS); else S_ChangeMusic(musnum, 1); } } - // Simplified, accepting both "noclip" and "idspispopd". - // no clipping mode cheat - else if ( cht_CheckCheat(&cheat_noclip, ev->data1) - || cht_CheckCheat(&cheat_commercial_noclip,ev->data1) ) + else if ( (logical_gamemission == doom + && cht_CheckCheat(&cheat_noclip, ev->data2)) + || (logical_gamemission != doom + && cht_CheckCheat(&cheat_commercial_noclip,ev->data2))) { + // Noclip cheat. + // For Doom 1, use the idspipsopd cheat; for all others, use + // idclip + plyr->cheats ^= CF_NOCLIP; if (plyr->cheats & CF_NOCLIP) - plyr->message = STSTR_NCON; + plyr->message = DEH_String(STSTR_NCON); else - plyr->message = STSTR_NCOFF; + plyr->message = DEH_String(STSTR_NCOFF); } // 'behold?' power-up cheats for (i=0;i<6;i++) { - if (cht_CheckCheat(&cheat_powerup[i], ev->data1)) + if (cht_CheckCheat(&cheat_powerup[i], ev->data2)) { if (!plyr->powers[i]) P_GivePower( plyr, i); @@ -644,36 +571,36 @@ ST_Responder (event_t* ev) else plyr->powers[i] = 0; - plyr->message = STSTR_BEHOLDX; + plyr->message = DEH_String(STSTR_BEHOLDX); } } // 'behold' power-up menu - if (cht_CheckCheat(&cheat_powerup[6], ev->data1)) + if (cht_CheckCheat(&cheat_powerup[6], ev->data2)) { - plyr->message = STSTR_BEHOLD; + plyr->message = DEH_String(STSTR_BEHOLD); } // 'choppers' invulnerability & chainsaw - else if (cht_CheckCheat(&cheat_choppers, ev->data1)) + else if (cht_CheckCheat(&cheat_choppers, ev->data2)) { plyr->weaponowned[wp_chainsaw] = true; plyr->powers[pw_invulnerability] = true; - plyr->message = STSTR_CHOPPERS; + plyr->message = DEH_String(STSTR_CHOPPERS); } // 'mypos' for player position - else if (cht_CheckCheat(&cheat_mypos, ev->data1)) + else if (cht_CheckCheat(&cheat_mypos, ev->data2)) { - static char buf[ST_MSGWIDTH]; - sprintf(buf, "ang=0x%x;x,y=(0x%x,0x%x)", - players[consoleplayer].mo->angle, - players[consoleplayer].mo->x, - players[consoleplayer].mo->y); - plyr->message = buf; + static char buf[ST_MSGWIDTH]; + M_snprintf(buf, sizeof(buf), "ang=0x%x;x,y=(0x%x,0x%x)", + players[consoleplayer].mo->angle, + players[consoleplayer].mo->x, + players[consoleplayer].mo->y); + plyr->message = buf; } } // 'clev' change-level cheat - if (cht_CheckCheat(&cheat_clev, ev->data1)) + if (!netgame && cht_CheckCheat(&cheat_clev, ev->data2)) { char buf[3]; int epsd; @@ -683,7 +610,7 @@ ST_Responder (event_t* ev) if (gamemode == commercial) { - epsd = 0; + epsd = 1; map = (buf[0] - '0')*10 + buf[1] - '0'; } else @@ -692,13 +619,20 @@ ST_Responder (event_t* ev) map = buf[1] - '0'; } + // Chex.exe always warps to episode 1. + + if (gameversion == exe_chex) + { + epsd = 1; + } + // Catch invalid maps. if (epsd < 1) return false; if (map < 1) return false; - + // Ohmygod - this is not going to work. if ((gamemode == retail) && ((epsd > 4) || (map > 9))) @@ -712,14 +646,16 @@ ST_Responder (event_t* ev) && ((epsd > 1) || (map > 9))) return false; + // The source release has this check as map > 34. However, Vanilla + // Doom allows IDCLEV up to MAP40 even though it normally crashes. if ((gamemode == commercial) - && (( epsd > 1) || (map > 34))) + && (( epsd > 1) || (map > 40))) return false; // So be it. - plyr->message = STSTR_CLEV; + plyr->message = DEH_String(STSTR_CLEV); G_DeferedInitNew(gameskill, epsd, map); - } + } } return false; } @@ -1042,6 +978,17 @@ void ST_doPaletteStuff(void) else palette = 0; + // In Chex Quest, the player never sees red. Instead, the + // radiation suit palette is used to tint the screen green, + // as though the player is being covered in goo by an + // attacking flemoid. + + if (gameversion == exe_chex + && palette >= STARTREDPALS && palette < STARTREDPALS + NUMREDPALS) + { + palette = RADIATIONPAL; + } + if (palette != st_palette) { st_palette = palette; @@ -1121,7 +1068,12 @@ void ST_Drawer (boolean fullscreen, boolean refresh) } -void ST_loadGraphics(void) +typedef void (*load_callback_t)(char *lumpname, patch_t **variable); + +// Iterates through all graphics to be loaded or unloaded, along with +// the variable they use, invoking the specified callback function. + +static void ST_loadUnloadGraphics(load_callback_t callback) { int i; @@ -1133,112 +1085,105 @@ void ST_loadGraphics(void) // Load the numbers, tall and short for (i=0;i<10;i++) { - sprintf(namebuf, "STTNUM%d", i); - tallnum[i] = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC); + DEH_snprintf(namebuf, 9, "STTNUM%d", i); + callback(namebuf, &tallnum[i]); - sprintf(namebuf, "STYSNUM%d", i); - shortnum[i] = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC); + DEH_snprintf(namebuf, 9, "STYSNUM%d", i); + callback(namebuf, &shortnum[i]); } // Load percent key. //Note: why not load STMINUS here, too? - tallpercent = (patch_t *) W_CacheLumpName("STTPRCNT", PU_STATIC); + + callback(DEH_String("STTPRCNT"), &tallpercent); // key cards for (i=0;i +#include +#include + +#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 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; iplyr[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; xplyr[x].in) + { + continue; + } + + fprintf(stream, "%s\t", player_colors[x]); + } + + fprintf(stream, "\n"); + + fprintf(stream, "\t\t-------------------------------- VICTIMS\n"); + + /* Print table */ + + for (y=0; yplyr[y].in) + { + continue; + } + + fprintf(stream, "\t%s\t|", player_colors[y]); + + for (x=0; xplyr[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; iplyr[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 + // + // Dump statistics information to the specified file on the levels + // that were played. The output from this option matches the output + // from statdump.exe (see ctrlapi.zip in the /idgames archive). + // + + i = M_CheckParmWithArgs("-statdump", 1); + + if (i > 0) + { + printf("Statistics captured for %i level(s)\n", num_captured_stats); + + // We actually know what the real gamemission is, but this has + // to match the output from statdump.exe. + + DiscoverGamemode(captured_stats, num_captured_stats); + + // Allow "-" as output file, for stdout. + + if (strcmp(myargv[i + 1], "-") != 0) + { + dumpfile = fopen(myargv[i + 1], "w"); + } + else + { + dumpfile = NULL; + } + + for (i = 0; i < num_captured_stats; ++i) + { + PrintStats(dumpfile, &captured_stats[i]); + } + + if (dumpfile != NULL) + { + fclose(dumpfile); + } + } +#endif +} + diff --git a/frosted-doom/statdump.h b/frosted-doom/statdump.h new file mode 100644 index 0000000..48db2ad --- /dev/null +++ b/frosted-doom/statdump.h @@ -0,0 +1,23 @@ + /* + + Copyright(C) 2005-2014 Simon Howard + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + */ + +#ifndef DOOM_STATDUMP_H +#define DOOM_STATDUMP_H + +void StatCopy(wbstartstruct_t *stats); +void StatDump(void); + +#endif /* #ifndef DOOM_STATDUMP_H */ diff --git a/frosted-doom/tables.c b/frosted-doom/tables.c index 9c5aa83..c221e9a 100644 --- a/frosted-doom/tables.c +++ b/frosted-doom/tables.c @@ -1,20 +1,16 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Lookup tables. @@ -33,38 +29,39 @@ // 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; + { + return SLOPERANGE; + } + else + { + ans = (num << 3) / (den >> 8); - ans = (num<<3)/(den>>8); - - return ans <= SLOPERANGE ? ans : SLOPERANGE; + if (ans <= SLOPERANGE) + { + return ans; + } + else + { + return SLOPERANGE; + } + } } - - - -int finetangent[4096] = +const int finetangent[4096] = { -170910304,-56965752,-34178904,-24413316,-18988036,-15535599,-13145455,-11392683, -10052327,-8994149,-8137527,-7429880,-6835455,-6329090,-5892567,-5512368, @@ -581,7 +578,7 @@ int finetangent[4096] = }; -int finesine[10240] = +const int finesine[10240] = { 25,75,125,175,226,276,326,376, 427,477,527,578,628,678,728,779, @@ -1865,9 +1862,9 @@ int finesine[10240] = 65534,65535,65535,65535,65535,65535,65535,65535 }; +const fixed_t *finecosine = &finesine[FINEANGLES/4]; - -angle_t tantoangle[2049] = +const angle_t tantoangle[2049] = { 0,333772,667544,1001315,1335086,1668857,2002626,2336395, 2670163,3003929,3337694,3671457,4005219,4338979,4672736,5006492, @@ -2128,3 +2125,103 @@ angle_t tantoangle[2049] = 536870912 }; +// Now where did these came from? +const byte gammatable[5][256] = +{ + { + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, + 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, + 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, + 49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64, + 65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80, + 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96, + 97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112, + 113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 + }, + + { + 2,4,5,7,8,10,11,12,14,15,16,18,19,20,21,23, + 24,25,26,27,29,30,31,32,33,34,36,37,38,39,40,41, + 42,44,45,46,47,48,49,50,51,52,54,55,56,57,58,59, + 60,61,62,63,64,65,66,67,69,70,71,72,73,74,75,76, + 77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92, + 93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108, + 109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124, + 125,126,127,128,129,129,130,131,132,133,134,135,136,137,138,139, + 140,141,142,143,144,145,146,147,148,148,149,150,151,152,153,154, + 155,156,157,158,159,160,161,162,163,163,164,165,166,167,168,169, + 170,171,172,173,174,175,175,176,177,178,179,180,181,182,183,184, + 185,186,186,187,188,189,190,191,192,193,194,195,196,196,197,198, + 199,200,201,202,203,204,205,205,206,207,208,209,210,211,212,213, + 214,214,215,216,217,218,219,220,221,222,222,223,224,225,226,227, + 228,229,230,230,231,232,233,234,235,236,237,237,238,239,240,241, + 242,243,244,245,245,246,247,248,249,250,251,252,252,253,254,255 + }, + + { + 4,7,9,11,13,15,17,19,21,22,24,26,27,29,30,32, + 33,35,36,38,39,40,42,43,45,46,47,48,50,51,52,54, + 55,56,57,59,60,61,62,63,65,66,67,68,69,70,72,73, + 74,75,76,77,78,79,80,82,83,84,85,86,87,88,89,90, + 91,92,93,94,95,96,97,98,100,101,102,103,104,105,106,107, + 108,109,110,111,112,113,114,114,115,116,117,118,119,120,121,122, + 123,124,125,126,127,128,129,130,131,132,133,133,134,135,136,137, + 138,139,140,141,142,143,144,144,145,146,147,148,149,150,151,152, + 153,153,154,155,156,157,158,159,160,160,161,162,163,164,165,166, + 166,167,168,169,170,171,172,172,173,174,175,176,177,178,178,179, + 180,181,182,183,183,184,185,186,187,188,188,189,190,191,192,193, + 193,194,195,196,197,197,198,199,200,201,201,202,203,204,205,206, + 206,207,208,209,210,210,211,212,213,213,214,215,216,217,217,218, + 219,220,221,221,222,223,224,224,225,226,227,228,228,229,230,231, + 231,232,233,234,235,235,236,237,238,238,239,240,241,241,242,243, + 244,244,245,246,247,247,248,249,250,251,251,252,253,254,254,255 + }, + + { + 8,12,16,19,22,24,27,29,31,34,36,38,40,41,43,45, + 47,49,50,52,53,55,57,58,60,61,63,64,65,67,68,70, + 71,72,74,75,76,77,79,80,81,82,84,85,86,87,88,90, + 91,92,93,94,95,96,98,99,100,101,102,103,104,105,106,107, + 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123, + 124,125,126,127,128,129,130,131,132,133,134,135,135,136,137,138, + 139,140,141,142,143,143,144,145,146,147,148,149,150,150,151,152, + 153,154,155,155,156,157,158,159,160,160,161,162,163,164,165,165, + 166,167,168,169,169,170,171,172,173,173,174,175,176,176,177,178, + 179,180,180,181,182,183,183,184,185,186,186,187,188,189,189,190, + 191,192,192,193,194,195,195,196,197,197,198,199,200,200,201,202, + 202,203,204,205,205,206,207,207,208,209,210,210,211,212,212,213, + 214,214,215,216,216,217,218,219,219,220,221,221,222,223,223,224, + 225,225,226,227,227,228,229,229,230,231,231,232,233,233,234,235, + 235,236,237,237,238,238,239,240,240,241,242,242,243,244,244,245, + 246,246,247,247,248,249,249,250,251,251,252,253,253,254,254,255 + }, + + + { + 16,23,28,32,36,39,42,45,48,50,53,55,57,60,62,64, + 66,68,69,71,73,75,76,78,80,81,83,84,86,87,89,90, + 92,93,94,96,97,98,100,101,102,103,105,106,107,108,109,110, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,128, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 143,144,145,146,147,148,149,150,150,151,152,153,154,155,155,156, + 157,158,159,159,160,161,162,163,163,164,165,166,166,167,168,169, + 169,170,171,172,172,173,174,175,175,176,177,177,178,179,180,180, + 181,182,182,183,184,184,185,186,187,187,188,189,189,190,191,191, + 192,193,193,194,195,195,196,196,197,198,198,199,200,200,201,202, + 202,203,203,204,205,205,206,207,207,208,208,209,210,210,211,211, + 212,213,213,214,214,215,216,216,217,217,218,219,219,220,220,221, + 221,222,223,223,224,224,225,225,226,227,227,228,228,229,229,230, + 230,231,232,232,233,233,234,234,235,235,236,236,237,237,238,239, + 239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247, + 247,248,248,249,249,250,250,251,251,252,252,253,254,254,255,255 + } +}; + diff --git a/frosted-doom/tables.h b/frosted-doom/tables.h index 060fe5b..495fd53 100644 --- a/frosted-doom/tables.h +++ b/frosted-doom/tables.h @@ -1,18 +1,17 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 1993-2008 Raven Software +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Lookup tables. @@ -30,20 +29,12 @@ // int tantoangle[2049] - ArcTan LUT, // maps tan(angle) to angle fast. Gotta search. // -//----------------------------------------------------------------------------- #ifndef __TABLES__ #define __TABLES__ - - -#ifdef LINUX -#include -#else -#define PI 3.141592657 -#endif - +#include "doomtype.h" #include "m_fixed.h" @@ -55,21 +46,33 @@ #define ANGLETOFINESHIFT 19 // Effective size is 10240. -extern fixed_t finesine[5*FINEANGLES/4]; +extern const fixed_t finesine[5*FINEANGLES/4]; // Re-use data, is just PI/2 pahse shift. -extern fixed_t* finecosine; +extern const fixed_t *finecosine; // Effective size is 4096. -extern fixed_t finetangent[FINEANGLES/2]; +extern const fixed_t finetangent[FINEANGLES/2]; + +// Gamma correction tables. +extern const byte gammatable[5][256]; // Binary Angle Measument, BAM. -#define ANG45 0x20000000 -#define ANG90 0x40000000 -#define ANG180 0x80000000 -#define ANG270 0xc0000000 +#define ANG45 0x20000000 +#define ANG90 0x40000000 +#define ANG180 0x80000000 +#define ANG270 0xc0000000 +#define ANG_MAX 0xffffffff + +#define ANG1 (ANG45 / 45) +#define ANG60 (ANG180 / 3) + +// Heretic code uses this definition as though it represents one +// degree, but it is not! This is actually ~1.40 degrees. + +#define ANG1_X 0x01000000 #define SLOPERANGE 2048 #define SLOPEBITS 11 @@ -81,20 +84,13 @@ typedef unsigned angle_t; // Effective size is 2049; // The +1 size is to handle the case when x==y // without additional checking. -extern angle_t tantoangle[SLOPERANGE+1]; +extern const angle_t tantoangle[SLOPERANGE+1]; // Utility function, // called by R_PointToAngle. -int -SlopeDiv -( unsigned num, - unsigned den); +int SlopeDiv(unsigned int num, unsigned int den); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- + diff --git a/frosted-doom/v_patch.h b/frosted-doom/v_patch.h new file mode 100644 index 0000000..687dca1 --- /dev/null +++ b/frosted-doom/v_patch.h @@ -0,0 +1,50 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Refresh/rendering module, shared data struct definitions. +// + + +#ifndef V_PATCH_H +#define V_PATCH_H + +// Patches. +// A patch holds one or more columns. +// Patches are used for sprites and all masked pictures, +// and we compose textures from the TEXTURE1/2 lists +// of patches. + +typedef struct +{ + short width; // bounding box size + short height; + short leftoffset; // pixels to the left of origin + short topoffset; // pixels below the origin + int columnofs[8]; // only [width] used + // the [0] is &columnofs[width] +} PACKEDATTR patch_t; + +// posts are runs of non masked source pixels +typedef struct +{ + byte topdelta; // -1 is the last post in a column + byte length; // length data bytes follows +} PACKEDATTR post_t; + +// column_t is a list of 0 or more post_t, (byte)-1 terminated +typedef post_t column_t; + +#endif + diff --git a/frosted-doom/v_video.c b/frosted-doom/v_video.c index 9b30e64..6db28aa 100644 --- a/frosted-doom/v_video.c +++ b/frosted-doom/v_video.c @@ -1,423 +1,514 @@ -// 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 +#include +#include #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 +#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; -// 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}, +// villsa [STRIFE] Blending table used for Strife +byte *xlatab = NULL; - {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}, +// The screen buffer that the v_video.c code draws to. - {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}, +static byte *dest_screen = NULL; - {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}, +int dirtybox[4]; - {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} -}; +// 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; - - -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) + 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"); + 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; - 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) + y -= SHORT(patch->topoffset); + x -= SHORT(patch->leftoffset); + + // haleyjd 08/28/10: Strife needs silent error checking here. + if(patchclip_callback) { - 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; + if(!patchclip_callback(patch, x, y)) + return; } -#endif - - if (!scrn) - V_MarkRect (x, y, SHORT(patch->width), SHORT(patch->height)); - col = 0; - desttop = screens[scrn]+y*SCREENWIDTH+x; - - w = SHORT(patch->width); +#ifdef RANGECHECK + if (x < 0 + || x + SHORT(patch->width) > SCREENWIDTH + || y < 0 + || y + SHORT(patch->height) > SCREENHEIGHT) + { + 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 + + V_MarkRect(x, y, SHORT(patch->width), SHORT(patch->height)); + + col = 0; + desttop = dest_screen + y * SCREENWIDTH + x; + + w = SHORT(patch->width); for ( ; colcolumnofs[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); -#ifdef RANGECHECK - if (x<0 - ||x+SHORT(patch->width) >SCREENWIDTH - || y<0 - || y+SHORT(patch->height)>SCREENHEIGHT - || (unsigned)scrn>4) + + // haleyjd 08/28/10: Strife needs silent error checking here. + if(patchclip_callback) { - fprintf( stderr, "Patch origin %d,%d exceeds LFB\n", x,y ); - I_Error ("Bad V_DrawPatch in V_DrawPatchFlipped"); + if(!patchclip_callback(patch, x, y)) + return; } -#endif - - if (!scrn) - V_MarkRect (x, y, SHORT(patch->width), SHORT(patch->height)); - col = 0; - desttop = screens[scrn]+y*SCREENWIDTH+x; - - w = SHORT(patch->width); +#ifdef RANGECHECK + if (x < 0 + || x + SHORT(patch->width) > SCREENWIDTH + || y < 0 + || y + SHORT(patch->height) > SCREENHEIGHT) + { + I_Error("Bad V_DrawPatchFlipped"); + } +#endif + + V_MarkRect (x, y, SHORT(patch->width), SHORT(patch->height)); + + col = 0; + desttop = dest_screen + y * SCREENWIDTH + x; + + w = SHORT(patch->width); + + for ( ; colcolumnofs[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 ( ; colcolumnofs[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); - -#ifdef RANGECHECK - if (x<0 - ||x+SHORT(patch->width) >SCREENWIDTH - || y<0 - || y+SHORT(patch->height)>SCREENHEIGHT - || (unsigned)scrn>4) - { - I_Error ("Bad V_DrawPatchDirect"); - } -#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 ; colcolumnofs[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 - }*/ + V_DrawPatch(x, y, patch); } - +// +// 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_DrawTLPatch"); + } + + col = 0; + desttop = dest_screen + y * SCREENWIDTH + x; + + w = SHORT(patch->width); + for (; col < w; x++, col++, desttop++) + { + column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col])); + + // step through the posts in a column + + while (column->topdelta != 0xff) + { + source = (byte *) column + 3; + dest = desttop + column->topdelta * SCREENWIDTH; + count = column->length; + + while (count--) + { + *dest = tinttable[((*dest) << 8) + *source++]; + dest += SCREENWIDTH; + } + column = (column_t *) ((byte *) column + column->length + 4); + } + } +} + +// +// V_DrawXlaPatch +// +// villsa [STRIFE] Masks a column based translucent masked pic to the screen. +// + +void V_DrawXlaPatch(int x, int y, patch_t * patch) +{ + int count, col; + column_t *column; + byte *desttop, *dest, *source; + int w; + + y -= SHORT(patch->topoffset); + x -= SHORT(patch->leftoffset); + + if(patchclip_callback) + { + if(!patchclip_callback(patch, x, y)) + return; + } + + col = 0; + desttop = dest_screen + y * SCREENWIDTH + x; + + w = SHORT(patch->width); + for(; col < w; x++, col++, desttop++) + { + column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col])); + + // step through the posts in a column + + while(column->topdelta != 0xff) + { + source = (byte *) column + 3; + dest = desttop + column->topdelta * SCREENWIDTH; + count = column->length; + + while(count--) + { + *dest = xlatab[*dest + ((*source) << 8)]; + source++; + dest += SCREENWIDTH; + } + column = (column_t *) ((byte *) column + column->length + 4); + } + } +} + +// +// V_DrawAltTLPatch +// +// Masks a column based translucent masked pic to the screen. +// + +void V_DrawAltTLPatch(int x, int y, patch_t * patch) +{ + int count, col; + column_t *column; + byte *desttop, *dest, *source; + int w; + + y -= SHORT(patch->topoffset); + x -= SHORT(patch->leftoffset); + + if (x < 0 + || x + SHORT(patch->width) > SCREENWIDTH + || y < 0 + || y + SHORT(patch->height) > SCREENHEIGHT) + { + I_Error("Bad V_DrawAltTLPatch"); + } + + col = 0; + desttop = dest_screen + y * SCREENWIDTH + x; + + w = SHORT(patch->width); + for (; col < w; x++, col++, desttop++) + { + column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col])); + + // step through the posts in a column + + while (column->topdelta != 0xff) + { + source = (byte *) column + 3; + dest = desttop + column->topdelta * SCREENWIDTH; + count = column->length; + + while (count--) + { + *dest = tinttable[((*dest) << 8) + *source++]; + dest += SCREENWIDTH; + } + column = (column_t *) ((byte *) column + column->length + 4); + } + } +} + +// +// V_DrawShadowedPatch +// +// Masks a column based masked pic to the screen. +// + +void V_DrawShadowedPatch(int x, int y, patch_t *patch) +{ + int count, col; + column_t *column; + byte *desttop, *dest, *source; + byte *desttop2, *dest2; + int w; + + y -= SHORT(patch->topoffset); + x -= SHORT(patch->leftoffset); + + if (x < 0 + || x + SHORT(patch->width) > SCREENWIDTH + || y < 0 + || y + SHORT(patch->height) > SCREENHEIGHT) + { + I_Error("Bad V_DrawShadowedPatch"); + } + + col = 0; + desttop = dest_screen + y * SCREENWIDTH + x; + desttop2 = dest_screen + (y + 2) * SCREENWIDTH + x + 2; + + w = SHORT(patch->width); + for (; col < w; x++, col++, desttop++, desttop2++) + { + column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col])); + + // step through the posts in a column + + while (column->topdelta != 0xff) + { + source = (byte *) column + 3; + dest = desttop + column->topdelta * SCREENWIDTH; + dest2 = desttop2 + column->topdelta * SCREENWIDTH; + count = column->length; + + while (count--) + { + *dest2 = tinttable[((*dest2) << 8)]; + dest2 += SCREENWIDTH; + *dest = *source++; + dest += SCREENWIDTH; + + } + column = (column_t *) ((byte *) column + column->length + 4); + } + } +} + +// +// Load tint table from TINTTAB lump. +// + +void V_LoadTintTable(void) +{ + tinttable = W_CacheLumpName("TINTTAB", PU_STATIC); +} + +// +// V_LoadXlaTable +// +// villsa [STRIFE] Load xla table from XLATAB lump. +// + +void V_LoadXlaTable(void) +{ + xlatab = W_CacheLumpName("XLATAB", PU_STATIC); +} // // V_DrawBlock // Draw a linear block of pixels into the view buffer. // -void -V_DrawBlock -( int x, - int y, - int scrn, - int width, - int height, - byte* src ) + +void V_DrawBlock(int x, int y, int width, int height, byte *src) { - byte* dest; - + byte *dest; + #ifdef RANGECHECK - if (x<0 - ||x+width >SCREENWIDTH - || y<0 - || y+height>SCREENHEIGHT - || (unsigned)scrn>4 ) + if (x < 0 + || x + width >SCREENWIDTH + || y < 0 + || y + height > SCREENHEIGHT) { I_Error ("Bad V_DrawBlock"); } @@ -425,7 +516,7 @@ V_DrawBlock V_MarkRect (x, y, width, height); - dest = screens[scrn] + y*SCREENWIDTH+x; + dest = dest_screen + y * SCREENWIDTH + x; while (height--) { @@ -434,60 +525,408 @@ V_DrawBlock dest += SCREENWIDTH; } } - +void V_DrawFilledBox(int x, int y, int w, int h, int c) +{ + uint8_t *buf, *buf1; + int x1, y1; -// -// V_GetBlock -// Gets a linear block of pixels from the view buffer. -// -void -V_GetBlock -( int x, - int y, - int scrn, - int width, - int height, - byte* dest ) -{ - byte* src; - -#ifdef RANGECHECK - if (x<0 - ||x+width >SCREENWIDTH - || y<0 - || y+height>SCREENHEIGHT - || (unsigned)scrn>4 ) + buf = I_VideoBuffer + SCREENWIDTH * y + x; + + for (y1 = 0; y1 < h; ++y1) { - I_Error ("Bad V_DrawBlock"); + buf1 = buf; + + for (x1 = 0; x1 < w; ++x1) + { + *buf1++ = c; + } + + buf += SCREENWIDTH; } -#endif +} + +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) +// - src = screens[scrn] + y*SCREENWIDTH+x; - - while (height--) - { - memcpy (dest, src, width); - src += SCREENWIDTH; - dest += width; - } -} - - - +void V_DrawRawScreen(byte *raw) +{ + memcpy(dest_screen, raw, SCREENWIDTH * SCREENHEIGHT); +} // // V_Init // void V_Init (void) { - int i; - byte* base; - - // stick these in low dos memory on PCs - - base = I_AllocLow (SCREENWIDTH*SCREENHEIGHT*4); - - for (i=0 ; i<4 ; i++) - screens[i] = base + i*SCREENWIDTH*SCREENHEIGHT; + // 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; + 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 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); +} + diff --git a/frosted-doom/v_video.h b/frosted-doom/v_video.h index cc2aca5..a970c71 100644 --- a/frosted-doom/v_video.h +++ b/frosted-doom/v_video.h @@ -1,25 +1,22 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Gamma correction LUT. // Functions to draw patches (by post) directly to screen. // Functions to blit a block to the screen. // -//----------------------------------------------------------------------------- #ifndef __V_VIDEO__ @@ -27,10 +24,8 @@ #include "doomtype.h" -#include "doomdef.h" - // Needed because we are refering to patches. -#include "r_data.h" +#include "v_patch.h" // // VIDEO @@ -39,81 +34,75 @@ #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; - -extern byte* screens[5]; - -extern int dirtybox[4]; - -extern byte gammatable[5][256]; -extern int usegamma; - +// 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); // Allocates buffer screens, call before R_Init. void V_Init (void); +// Draw a block from the specified source screen to the screen. -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_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); // 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_DrawBlock(int x, int y, int width, int height, byte *src); +void V_MarkRect(int x, int y, int width, int height); -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 raw screen lump + +void V_DrawRawScreen(byte *raw); + +// Temporarily switch to using a different buffer to draw graphics, etc. + +void V_UseBuffer(byte *buffer); + +// Return to using the normal screen buffer to draw graphics. + +void V_RestoreBuffer(void); + +// Save a screenshot of the current screen to a file, named in the +// format described in the string passed to the function, eg. +// "DOOM%02i.pcx" + +void V_ScreenShot(char *format); + +// Load the lookup table for translucency calculations from the TINTTAB +// lump. + +void V_LoadTintTable(void); + +// villsa [STRIFE] +// Load the lookup table for translucency calculations from the XLATAB +// lump. + +void V_LoadXlaTable(void); + +void V_DrawMouseSpeedBox(int speed); #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//----------------------------------------------------------------------------- + diff --git a/frosted-doom/w_checksum.c b/frosted-doom/w_checksum.c new file mode 100644 index 0000000..5933fdf --- /dev/null +++ b/frosted-doom/w_checksum.c @@ -0,0 +1,87 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Generate a checksum of the WAD directory. +// + +#include +#include +#include + +#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; iname, 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 + +#include "config.h" + +#include "doomtype.h" +#include "m_argv.h" + +#include "w_file.h" + +extern wad_file_class_t stdc_wad_file; + +#ifdef _WIN32 +extern wad_file_class_t win32_wad_file; +#endif + +#ifdef HAVE_MMAP +extern wad_file_class_t posix_wad_file; +#endif + +static wad_file_class_t *wad_file_classes[] = +{ +#ifdef _WIN32 + &win32_wad_file, +#endif +#ifdef HAVE_MMAP + &posix_wad_file, +#endif + &stdc_wad_file, +}; + +wad_file_t *W_OpenFile(char *path) +{ + wad_file_t *result; + int i; + + //! + // Use the OS's virtual memory subsystem to map WAD files + // directly into memory. + // + + if (!M_CheckParm("-mmap")) + { + return stdc_wad_file.OpenFile(path); + } + + // Try all classes in order until we find one that works + + result = NULL; + + for (i = 0; i < arrlen(wad_file_classes); ++i) + { + result = wad_file_classes[i]->OpenFile(path); + + if (result != NULL) + { + break; + } + } + + return result; +} + +void W_CloseFile(wad_file_t *wad) +{ + wad->file_class->CloseFile(wad); +} + +size_t W_Read(wad_file_t *wad, unsigned int offset, + void *buffer, size_t buffer_len) +{ + return wad->file_class->Read(wad, offset, buffer, buffer_len); +} + diff --git a/frosted-doom/w_file.h b/frosted-doom/w_file.h new file mode 100644 index 0000000..f577814 --- /dev/null +++ b/frosted-doom/w_file.h @@ -0,0 +1,78 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// WAD I/O functions. +// + + +#ifndef __W_FILE__ +#define __W_FILE__ + +#include +#include "doomtype.h" + +typedef struct _wad_file_s wad_file_t; + +typedef struct +{ + // Open a file for reading. + + wad_file_t *(*OpenFile)(char *path); + + // Close the specified file. + + void (*CloseFile)(wad_file_t *file); + + // Read data from the specified position in the file into the + // provided buffer. Returns the number of bytes read. + + size_t (*Read)(wad_file_t *file, unsigned int offset, + void *buffer, size_t buffer_len); + +} wad_file_class_t; + +struct _wad_file_s +{ + // Class of this file. + + wad_file_class_t *file_class; + + // If this is NULL, the file cannot be mapped into memory. If this + // is non-NULL, it is a pointer to the mapped file. + + byte *mapped; + + // Length of the file, in bytes. + + unsigned int length; +}; + +// Open the specified file. Returns a pointer to a new wad_file_t +// handle for the WAD file, or NULL if it could not be opened. + +wad_file_t *W_OpenFile(char *path); + +// Close the specified WAD file. + +void W_CloseFile(wad_file_t *wad); + +// Read data from the specified file into the provided buffer. The +// data is read from the specified offset from the start of the file. +// Returns the number of bytes read. + +size_t W_Read(wad_file_t *wad, unsigned int offset, + void *buffer, size_t buffer_len); + +#endif /* #ifndef __W_FILE__ */ diff --git a/frosted-doom/w_file_stdc.c b/frosted-doom/w_file_stdc.c new file mode 100644 index 0000000..829e960 --- /dev/null +++ b/frosted-doom/w_file_stdc.c @@ -0,0 +1,96 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// WAD I/O functions. +// + +#include + +#include "m_misc.h" +#include "w_file.h" +#include "z_zone.h" + +typedef struct +{ + wad_file_t wad; + FILE *fstream; +} stdc_wad_file_t; + +extern wad_file_class_t stdc_wad_file; + +static wad_file_t *W_StdC_OpenFile(char *path) +{ + stdc_wad_file_t *result; + FILE *fstream; + + fstream = fopen(path, "rb"); + + if (fstream == NULL) + { + return NULL; + } + + // Create a new stdc_wad_file_t to hold the file handle. + + result = Z_Malloc(sizeof(stdc_wad_file_t), PU_STATIC, 0); + result->wad.file_class = &stdc_wad_file; + result->wad.mapped = NULL; + result->wad.length = M_FileLength(fstream); + result->fstream = fstream; + + return &result->wad; +} + +static void W_StdC_CloseFile(wad_file_t *wad) +{ + stdc_wad_file_t *stdc_wad; + + stdc_wad = (stdc_wad_file_t *) wad; + + fclose(stdc_wad->fstream); + Z_Free(stdc_wad); +} + +// Read data from the specified position in the file into the +// provided buffer. Returns the number of bytes read. + +size_t W_StdC_Read(wad_file_t *wad, unsigned int offset, + void *buffer, size_t buffer_len) +{ + stdc_wad_file_t *stdc_wad; + size_t result; + + stdc_wad = (stdc_wad_file_t *) wad; + + // Jump to the specified position in the file. + + fseek(stdc_wad->fstream, offset, SEEK_SET); + + // Read into the buffer. + + result = fread(buffer, 1, buffer_len, stdc_wad->fstream); + + return result; +} + + +wad_file_class_t stdc_wad_file = +{ + W_StdC_OpenFile, + W_StdC_CloseFile, + W_StdC_Read, +}; + + diff --git a/frosted-doom/w_file_stdc_unbuffered.c b/frosted-doom/w_file_stdc_unbuffered.c new file mode 100644 index 0000000..e59e63b --- /dev/null +++ b/frosted-doom/w_file_stdc_unbuffered.c @@ -0,0 +1,118 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// WAD I/O functions. +// + +#include +#include +#include +#include +#include +#include + +#include "m_misc.h" +#include "w_file.h" +#include "z_zone.h" + +typedef struct +{ + wad_file_t wad; + int fd; +} stdc_wad_file_t; + +extern wad_file_class_t stdc_wad_file; + +static unsigned int W_StdC_FileLength(int fd) +{ + long savedpos; + long length; + + // save the current position in the file + savedpos = lseek(fd, 0, SEEK_CUR); + + // jump to the end and find the length + length = lseek(fd, 0, SEEK_END); + + // go back to the old location + lseek(fd, savedpos, SEEK_SET); + + return length; +} + +static wad_file_t *W_StdC_OpenFile(char *path) +{ + stdc_wad_file_t *result; + int fd; + + fd = open(path, O_RDONLY); + + if (fd <= 0) + { + return NULL; + } + + // Create a new stdc_wad_file_t to hold the file handle. + + result = Z_Malloc(sizeof(stdc_wad_file_t), PU_STATIC, 0); + result->wad.file_class = &stdc_wad_file; + result->wad.mapped = NULL; + result->wad.length = W_StdC_FileLength(fd); + result->fd = fd; + + return &result->wad; +} + +static void W_StdC_CloseFile(wad_file_t *wad) +{ + stdc_wad_file_t *stdc_wad; + + stdc_wad = (stdc_wad_file_t *) wad; + + close(stdc_wad->fd); + Z_Free(stdc_wad); +} + +// Read data from the specified position in the file into the +// provided buffer. Returns the number of bytes read. + +size_t W_StdC_Read(wad_file_t *wad, unsigned int offset, + void *buffer, size_t buffer_len) +{ + stdc_wad_file_t *stdc_wad; + size_t result; + + stdc_wad = (stdc_wad_file_t *) wad; + + // Jump to the specified position in the file. + + lseek(stdc_wad->fd, offset, SEEK_SET); + + // Read into the buffer. + + result = read(stdc_wad->fd, buffer, buffer_len); + + return result; +} + + +wad_file_class_t stdc_wad_file = +{ + W_StdC_OpenFile, + W_StdC_CloseFile, + W_StdC_Read, +}; + + diff --git a/frosted-doom/w_main.c b/frosted-doom/w_main.c new file mode 100644 index 0000000..115f081 --- /dev/null +++ b/frosted-doom/w_main.c @@ -0,0 +1,198 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Common code to parse command line, identifying WAD files to load. +// + +#include "doomfeatures.h" +#include "d_iwad.h" +#include "m_argv.h" +#include "w_main.h" +#include "w_merge.h" +#include "w_wad.h" +#include "z_zone.h" + +// Parse the command line, merging WAD files that are sppecified. +// Returns true if at least one file was added. + +boolean W_ParseCommandLine(void) +{ + boolean modifiedgame = false; + int p; + +#ifdef FEATURE_WAD_MERGE + + // Merged PWADs are loaded first, because they are supposed to be + // modified IWADs. + + //! + // @arg + // @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 + // @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 + // @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 + // @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 + // @category mod + // + // Equivalent to "-af -as ". + // + + p = M_CheckParmWithArgs("-aa", 1); + + if (p > 0) + { + for (p = p + 1; p + // @vanilla + // + // Load the specified PWAD files. + // + + p = M_CheckParmWithArgs ("-file", 1); + if (p) + { + // the parms after p are wadfile/lump names, + // until end of parms or another - preceded parm + modifiedgame = true; // homebrew levels + while (++p != myargc && myargv[p][0] != '-') + { + char *filename; + + filename = D_TryFindWADByName(myargv[p]); + + printf(" adding %s\n", filename); + W_AddFile(filename); + } + } + +// W_PrintDirectory(); + + return modifiedgame; +} + diff --git a/frosted-doom/w_main.h b/frosted-doom/w_main.h new file mode 100644 index 0000000..2e39efc --- /dev/null +++ b/frosted-doom/w_main.h @@ -0,0 +1,24 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Common code to parse command line, identifying WAD files to load. +// + +#ifndef W_MAIN_H +#define W_MAIN_H + +boolean W_ParseCommandLine(void); + +#endif /* #ifndef W_MAIN_H */ + diff --git a/frosted-doom/w_merge.h b/frosted-doom/w_merge.h new file mode 100644 index 0000000..c8ecc69 --- /dev/null +++ b/frosted-doom/w_merge.h @@ -0,0 +1,44 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Handles merging of PWADs, similar to deutex's -merge option +// +// Ideally this should work exactly the same as in deutex, but trying to +// read the deutex source code made my brain hurt. +// + +#ifndef W_MERGE_H +#define W_MERGE_H + +#define W_NWT_MERGE_SPRITES 0x1 +#define W_NWT_MERGE_FLATS 0x2 + +// Add a new WAD and merge it into the main directory + +void W_MergeFile(char *filename); + +// NWT-style merging + +void W_NWTMergeFile(char *filename, int flags); + +// Acts the same as NWT's "-merge" option. + +void W_NWTDashMerge(char *filename); + +// Debug function that prints the WAD directory. + +void W_PrintDirectory(void); + +#endif /* #ifndef W_MERGE_H */ + diff --git a/frosted-doom/w_wad.c b/frosted-doom/w_wad.c index 636e4fb..1248046 100644 --- a/frosted-doom/w_wad.c +++ b/frosted-doom/w_wad.c @@ -1,122 +1,128 @@ -// 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 -#include +#include +#include #include -#include -#include -#include -#include -#include -#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; +// Hash table for fast lookups -#define strcmpi strcasecmp +static lumpinfo_t **lumphash; -void d_strupr (char* s) +// Hash function used for lump names. + +unsigned int W_LumpNameHash(const char *s) { - while (*s) { *s = toupper(*s); 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; + + for (i=0; i < 8 && s[i] != '\0'; ++i) + { + result = ((result << 5) ^ result ) ^ toupper((int)s[i]); + } + + return result; } -int filelength (int handle) -{ - struct stat fileinfo; - - if (fstat (handle,&fileinfo) == -1) - I_Error ("Error fstating"); - - return fileinfo.st_size; -} - - -void -ExtractFileBase -( char* path, - char* dest ) +// Increase the size of the lumpinfo[] array to the specified size. +static void ExtendLumpInfo(int newnumlumps) { - char* src; - int length; + lumpinfo_t *newlumpinfo; + unsigned int i; - src = path + strlen(path) - 1; - - // back up until a \ or the start - while (src != path - && *(src-1) != '\\' - && *(src-1) != '/') - { - src--; - } - - // 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); + newlumpinfo = calloc(newnumlumps, sizeof(lumpinfo_t)); - *dest++ = toupper((int)*src++); + if (newlumpinfo == NULL) + { + I_Error ("Couldn't realloc lumpinfo"); } + + // Copy over lumpinfo_t structures from the old array. If any of + // these lumps have been cached, we need to update the user + // pointers to the new location. + for (i = 0; i < numlumps && i < newnumlumps; ++i) + { + memcpy(&newlumpinfo[i], &lumpinfo[i], sizeof(lumpinfo_t)); + + if (newlumpinfo[i].cache != NULL) + { + Z_ChangeUser(newlumpinfo[i].cache, &newlumpinfo[i].cache); + } + + // We shouldn't be generating a hash table until after all WADs have + // been loaded, but just in case... + if (lumpinfo[i].next != NULL) + { + int nextlumpnum = lumpinfo[i].next - lumpinfo; + newlumpinfo[i].next = &newlumpinfo[nextlumpnum]; + } + } + + // All done. + free(lumpinfo); + lumpinfo = newlumpinfo; + numlumps = newnumlumps; } - - - - // // LUMP BASED ROUTINES. // @@ -129,214 +135,105 @@ ExtractFileBase // with multiple lumps. // Other files are single lumps with the base filename // for the lump name. -// -// If filename starts with a tilde, the file is handled -// specially to allow map reloads. -// But: the reload feature is a fragile hack... -int reloadlump; -char* reloadname; - - -void W_AddFile (char *filename) +wad_file_t *W_AddFile (char *filename) { - wadinfo_t header; - lumpinfo_t* lump_p; - unsigned i; - int handle; - int length; - int startlump; - filelump_t* fileinfo; - filelump_t singleinfo; - int storehandle; - + wadinfo_t header; + lumpinfo_t *lump_p; + unsigned int i; + wad_file_t *wad_file; + int length; + int startlump; + filelump_t *fileinfo; + filelump_t *filerover; + int newnumlumps; + // open the file and add to directory - // handle reload indicator. - if (filename[0] == '~') + wad_file = W_OpenFile(filename); + + if (wad_file == NULL) { - filename++; - reloadname = filename; - reloadlump = numlumps; - } - - if ( (handle = open (filename,O_RDONLY | O_BINARY)) == -1) - { - printf (" couldn't open %s\n",filename); - return; + printf (" couldn't open %s\n", filename); + return NULL; } - printf (" adding %s\n",filename); - startlump = numlumps; - - if (strcmpi (filename+strlen(filename)-3 , "wad" ) ) + newnumlumps = numlumps; + + if (strcasecmp(filename+strlen(filename)-3 , "wad" ) ) { - // single lump file - fileinfo = &singleinfo; - singleinfo.filepos = 0; - singleinfo.size = LONG(filelength(handle)); - ExtractFileBase (filename, singleinfo.name); - numlumps++; + // single lump file + + // 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). + + M_ExtractFileBase (filename, fileinfo->name); + newnumlumps++; } 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; + // 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; } - - // Fill in lumpinfo - lumpinfo = realloc (lumpinfo, numlumps*sizeof(lumpinfo_t)); - - if (!lumpinfo) - I_Error ("Couldn't realloc lumpinfo"); + // Increase size of numlumps array to accomodate the new file. + startlump = numlumps; + ExtendLumpInfo(newnumlumps); lump_p = &lumpinfo[startlump]; - - storehandle = reloadname ? -1 : handle; - - for (i=startlump ; ihandle = storehandle; - lump_p->position = LONG(fileinfo->filepos); - lump_p->size = LONG(fileinfo->size); - strncpy (lump_p->name, fileinfo->name, 8); + 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; } - //XXX: Alloca replacement - free(fileinfo); - - if (reloadname) - close (handle); -} + Z_Free(fileinfo); - - - -// -// 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 ; - iposition = LONG(fileinfo->filepos); - lump_p->size = LONG(fileinfo->size); + Z_Free(lumphash); + lumphash = NULL; } - free(fileinfo); - close (handle); -} - - - -// -// 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); -} - - - - -// -// W_InitFile -// Just initialize from a single file. -// -void W_InitFile (char* filename) -{ - char* names[2]; - - names[0] = filename; - names[1] = NULL; - W_InitMultipleFiles (names); + return wad_file; } @@ -358,42 +255,44 @@ int W_NumLumps (void) int W_CheckNumForName (char* name) { - union { - char s[9]; - int x[2]; - - } name8; - - int v1; - int v2; - lumpinfo_t* lump_p; + lumpinfo_t *lump_p; + int i; - // make the name into two integers for easy compares - strncpy (name8.s,name,8); + // Do we have a hash table yet? - // in case the name was a fill 8 chars - name8.s[8] = 0; - - // case insensitive - d_strupr (name8.s); - - v1 = name8.x[0]; - v2 = name8.x[1]; - - - // scan backwards so patch lump files take precedence - lump_p = lumpinfo + numlumps; - - while (lump_p-- != lumpinfo) + if (lumphash != NULL) { - if ( *(int *)lump_p->name == v1 - && *(int *)&lump_p->name[4] == v2) - { - return lump_p - lumpinfo; - } + int hash; + + // We do! Excellent. + + hash = W_LumpNameHash(name) % numlumps; + + for (lump_p = lumphash[hash]; lump_p != NULL; lump_p = lump_p->next) + { + if (!strncasecmp(lump_p->name, name, 8)) + { + return lump_p - lumpinfo; + } + } + } + else + { + // We don't have a hash table generate yet. Linear search :-( + // + // scan backwards so patch lump files take precedence + + for (i=numlumps-1; i >= 0; --i) + { + if (!strncasecmp(lumpinfo[i].name, name, 8)) + { + return i; + } + } } // TFB. Not found. + return -1; } @@ -409,10 +308,12 @@ int W_GetNumForName (char* name) int i; i = W_CheckNumForName (name); - - if (i == -1) - I_Error ("W_GetNumForName: %s not found!", name); - + + if (i < 0) + { + I_Error ("W_GetNumForName: %s not found!", name); + } + return i; } @@ -421,10 +322,12 @@ int W_GetNumForName (char* name) // W_LumpLength // Returns the buffer size needed to load the given lump. // -int W_LumpLength (int lump) +int W_LumpLength (unsigned int lump) { if (lump >= numlumps) - I_Error ("W_LumpLength: %i >= numlumps",lump); + { + I_Error ("W_LumpLength: %i >= numlumps", lump); + } return lumpinfo[lump].size; } @@ -436,42 +339,29 @@ int W_LumpLength (int lump) // Loads the lump into the given buffer, // which must be >= W_LumpLength(). // -void -W_ReadLump -( int lump, - void* dest ) +void W_ReadLump(unsigned int lump, void *dest) { - int c; - lumpinfo_t* l; - int handle; + int c; + lumpinfo_t *l; if (lump >= numlumps) - I_Error ("W_ReadLump: %i >= numlumps",lump); + { + I_Error ("W_ReadLump: %i >= numlumps", lump); + } l = lumpinfo+lump; - // ??? I_BeginRead (); + I_BeginRead (); - if (l->handle == -1) - { - // reloadable file, so use open / read / close - if ( (handle = open (reloadname,O_RDONLY | O_BINARY)) == -1) - I_Error ("W_ReadLump: couldn't open %s",reloadname); - } - else - handle = l->handle; - - lseek (handle, l->position, SEEK_SET); - c = read (handle, dest, l->size); + c = W_Read(l->wad_file, l->position, dest, l->size); if (c < l->size) + { I_Error ("W_ReadLump: only read %i of %i on lump %i", - c,l->size,lump); + c, l->size, lump); + } - if (l->handle == -1) - close (handle); - - // ??? I_EndRead (); + I_EndRead (); } @@ -480,31 +370,55 @@ W_ReadLump // // W_CacheLumpNum // -void* -W_CacheLumpNum -( int lump, - int tag ) -{ - byte* ptr; +// 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). +// - if ((unsigned)lump >= numlumps) - I_Error ("W_CacheLumpNum: %i >= numlumps",lump); - - if (!lumpcache[lump]) +void *W_CacheLumpNum(int lumpnum, int tag) +{ + byte *result; + lumpinfo_t *lump; + + if ((unsigned)lumpnum >= numlumps) { - // read the lump in - - //printf ("cache miss on lump %i\n",lump); - ptr = Z_Malloc (W_LumpLength (lump), tag, &lumpcache[lump]); - W_ReadLump (lump, lumpcache[lump]); + I_Error ("W_CacheLumpNum: %i >= numlumps", lumpnum); + } + + lump = &lumpinfo[lumpnum]; + + // Get the pointer to return. If the lump is in a memory-mapped + // file, we can just return a pointer to within the memory-mapped + // region. If the lump is in an ordinary file, we may already + // have it cached; otherwise, load it into memory. + + if (lump->wad_file->mapped != NULL) + { + // Memory mapped file, return from the mmapped region. + + result = lump->wad_file->mapped + lump->position; + } + else if (lump->cache != NULL) + { + // Already cached, so just switch the zone tag. + + result = lump->cache; + Z_ChangeTag(lump->cache, tag); } else { - //printf ("cache hit on lump %i\n",lump); - Z_ChangeTag (lumpcache[lump],tag); + // Not yet loaded, so load it now + + lump->cache = Z_Malloc(W_LumpLength(lumpnum), tag, &lump->cache); + W_ReadLump (lumpnum, lump->cache); + result = lump->cache; } - return lumpcache[lump]; + return result; } @@ -512,14 +426,48 @@ W_CacheLumpNum // // W_CacheLumpName // -void* -W_CacheLumpName -( char* name, - int tag ) +void *W_CacheLumpName(char *name, int tag) { - return W_CacheLumpNum (W_GetNumForName(name), tag); + return W_CacheLumpNum(W_GetNumForName(name), tag); } +// +// Release a lump back to the cache, so that it can be reused later +// without having to read from disk again, or alternatively, discarded +// if we run out of memory. +// +// Back in Vanilla Doom, this was just done using Z_ChangeTag +// directly, but now that we have WAD mmap, things are a bit more +// complicated ... +// + +void W_ReleaseLumpNum(int lumpnum) +{ + lumpinfo_t *lump; + + if ((unsigned)lumpnum >= numlumps) + { + I_Error ("W_ReleaseLumpNum: %i >= numlumps", lumpnum); + } + + lump = &lumpinfo[lumpnum]; + + if (lump->wad_file->mapped != NULL) + { + // Memory-mapped file, so nothing needs to be done here. + } + else + { + Z_ChangeTag(lump->cache, PU_CACHE); + } +} + +void W_ReleaseLumpName(char *name) +{ + W_ReleaseLumpNum(W_GetNumForName(name)); +} + +#if 0 // // W_Profile @@ -540,7 +488,7 @@ void W_Profile (void) for (i=0 ; i 0) + { + lumphash = Z_Malloc(sizeof(lumpinfo_t *) * numlumps, PU_STATIC, NULL); + memset(lumphash, 0, sizeof(lumpinfo_t *) * numlumps); + + for (i=0; i= 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)); + } + } + } +} + diff --git a/frosted-doom/w_wad.h b/frosted-doom/w_wad.h index db1faaa..7189574 100644 --- a/frosted-doom/w_wad.h +++ b/frosted-doom/w_wad.h @@ -1,89 +1,78 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // WAD I/O functions. // -//----------------------------------------------------------------------------- #ifndef __W_WAD__ #define __W_WAD__ +#include -#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:$ -// -//----------------------------------------------------------------------------- diff --git a/frosted-doom/wi_stuff.c b/frosted-doom/wi_stuff.c index 98be302..ddb9a66 100644 --- a/frosted-doom/wi_stuff.c +++ b/frosted-doom/wi_stuff.c @@ -1,36 +1,31 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Intermission screens. // -//----------------------------------------------------------------------------- -static const char -rcsid[] = "$Id: wi_stuff.c,v 1.7 1997/02/03 22:45:13 b1 Exp $"; #include #include "z_zone.h" +#include "m_misc.h" #include "m_random.h" -#include "m_swap.h" +#include "deh_main.h" +#include "i_swap.h" #include "i_system.h" #include "w_wad.h" @@ -223,48 +218,54 @@ static point_t lnodes[NUMEPISODES][NUMMAPS] = // Using patches saves a lot of space, // as they replace 320x200 full screen frames. // + +#define ANIM(type, period, nanims, x, y, nexttic) \ + { (type), (period), (nanims), { (x), (y) }, (nexttic), \ + 0, { NULL, NULL, NULL }, 0, 0, 0, 0 } + + static anim_t epsd0animinfo[] = { - { ANIM_ALWAYS, TICRATE/3, 3, { 224, 104 } }, - { ANIM_ALWAYS, TICRATE/3, 3, { 184, 160 } }, - { ANIM_ALWAYS, TICRATE/3, 3, { 112, 136 } }, - { ANIM_ALWAYS, TICRATE/3, 3, { 72, 112 } }, - { ANIM_ALWAYS, TICRATE/3, 3, { 88, 96 } }, - { ANIM_ALWAYS, TICRATE/3, 3, { 64, 48 } }, - { ANIM_ALWAYS, TICRATE/3, 3, { 192, 40 } }, - { ANIM_ALWAYS, TICRATE/3, 3, { 136, 16 } }, - { ANIM_ALWAYS, TICRATE/3, 3, { 80, 16 } }, - { ANIM_ALWAYS, TICRATE/3, 3, { 64, 24 } } + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 224, 104, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 184, 160, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 112, 136, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 72, 112, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 88, 96, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 64, 48, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 192, 40, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 136, 16, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 80, 16, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 64, 24, 0), }; static anim_t epsd1animinfo[] = { - { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 1 }, - { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 2 }, - { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 3 }, - { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 4 }, - { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 5 }, - { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 6 }, - { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 7 }, - { ANIM_LEVEL, TICRATE/3, 3, { 192, 144 }, 8 }, - { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 8 } + ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 1), + ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 2), + ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 3), + ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 4), + ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 5), + ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 6), + ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 7), + ANIM(ANIM_LEVEL, TICRATE/3, 3, 192, 144, 8), + ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 8), }; static anim_t epsd2animinfo[] = { - { ANIM_ALWAYS, TICRATE/3, 3, { 104, 168 } }, - { ANIM_ALWAYS, TICRATE/3, 3, { 40, 136 } }, - { ANIM_ALWAYS, TICRATE/3, 3, { 160, 96 } }, - { ANIM_ALWAYS, TICRATE/3, 3, { 104, 80 } }, - { ANIM_ALWAYS, TICRATE/3, 3, { 120, 32 } }, - { ANIM_ALWAYS, TICRATE/4, 3, { 40, 0 } } + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 104, 168, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 40, 136, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 160, 96, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 104, 80, 0), + ANIM(ANIM_ALWAYS, TICRATE/3, 3, 120, 32, 0), + ANIM(ANIM_ALWAYS, TICRATE/4, 3, 40, 0, 0), }; static int NUMANIMS[NUMEPISODES] = { - sizeof(epsd0animinfo)/sizeof(anim_t), - sizeof(epsd1animinfo)/sizeof(anim_t), - sizeof(epsd2animinfo)/sizeof(anim_t) + arrlen(epsd0animinfo), + arrlen(epsd1animinfo), + arrlen(epsd2animinfo), }; static anim_t *anims[NUMEPISODES] = @@ -282,8 +283,6 @@ static anim_t *anims[NUMEPISODES] = // // Locally used stuff. // -#define FB 0 - // States for single-player #define SP_KILLS 0 @@ -338,14 +337,11 @@ static int NUMCMAPS; // GRAPHICS // -// background (map of levels). -static patch_t* bg; - // You Are Here graphic -static patch_t* yah[2]; +static patch_t* yah[3] = { NULL, NULL, NULL }; // splat -static patch_t* splat; +static patch_t* splat[2] = { NULL, NULL }; // %, : graphics static patch_t* percent; @@ -373,7 +369,7 @@ static patch_t* items; static patch_t* frags; // Time sucks. -static patch_t* time; +static patch_t* timepatch; static patch_t* par; static patch_t* sucks; @@ -395,18 +391,17 @@ static patch_t* bp[MAXPLAYERS]; // Name graphics of each level (centered) static patch_t** lnames; +// Buffer storing the backdrop +static patch_t *background; + // // CODE // // slam background -// UNUSED static unsigned char *background=0; - - void WI_slamBackground(void) { - memcpy(screens[0], screens[1], SCREENWIDTH * SCREENHEIGHT); - V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT); + V_DrawPatch(0, 0, background); } // The ticker is used to detect keys @@ -422,15 +417,33 @@ void WI_drawLF(void) { int y = WI_TITLEY; - // draw - V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->last]->width))/2, - y, FB, lnames[wbs->last]); + if (gamemode != commercial || wbs->last < NUMCMAPS) + { + // draw + V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->last]->width))/2, + y, lnames[wbs->last]); - // draw "Finished!" - y += (5*SHORT(lnames[wbs->last]->height))/4; - - V_DrawPatch((SCREENWIDTH - SHORT(finished->width))/2, - y, FB, finished); + // draw "Finished!" + y += (5*SHORT(lnames[wbs->last]->height))/4; + + V_DrawPatch((SCREENWIDTH - SHORT(finished->width)) / 2, y, finished); + } + else if (wbs->last == NUMCMAPS) + { + // MAP33 - nothing is displayed! + } + else if (wbs->last > NUMCMAPS) + { + // > MAP33. Doom bombs out here with a Bad V_DrawPatch error. + // I'm pretty sure that doom2.exe is just reading into random + // bits of memory at this point, but let's try to be accurate + // anyway. This deliberately triggers a V_DrawPatch error. + + patch_t tmp = { SCREENWIDTH, SCREENHEIGHT, 1, 1, + { 0, 0, 0, 0, 0, 0, 0, 0 } }; + + V_DrawPatch(0, y, &tmp); + } } @@ -442,13 +455,15 @@ void WI_drawEL(void) // draw "Entering" V_DrawPatch((SCREENWIDTH - SHORT(entering->width))/2, - y, FB, entering); + y, + entering); // draw level y += (5*SHORT(lnames[wbs->next]->height))/4; V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->next]->width))/2, - y, FB, lnames[wbs->next]); + y, + lnames[wbs->next]); } @@ -484,12 +499,13 @@ WI_drawOnLnode { i++; } - } while (!fits && i!=2); + } while (!fits && i!=2 && c[i] != NULL); if (fits && i<2) { - V_DrawPatch(lnodes[wbs->epsd][n].x, lnodes[wbs->epsd][n].y, - FB, c[i]); + V_DrawPatch(lnodes[wbs->epsd][n].x, + lnodes[wbs->epsd][n].y, + c[i]); } else { @@ -585,7 +601,7 @@ void WI_drawAnimatedBack(void) int i; anim_t* a; - if (commercial) + if (gamemode == commercial) return; if (wbs->epsd > 2) @@ -596,7 +612,7 @@ void WI_drawAnimatedBack(void) a = &anims[wbs->epsd][i]; if (a->ctr >= 0) - V_DrawPatch(a->loc.x, a->loc.y, FB, a->p[a->ctr]); + V_DrawPatch(a->loc.x, a->loc.y, a->p[a->ctr]); } } @@ -653,13 +669,13 @@ WI_drawNum while (digits--) { x -= fontwidth; - V_DrawPatch(x, y, FB, num[ n % 10 ]); + V_DrawPatch(x, y, num[ n % 10 ]); n /= 10; } // draw a minus sign if necessary if (neg) - V_DrawPatch(x-=8, y, FB, wiminus); + V_DrawPatch(x-=8, y, wiminus); return x; @@ -674,7 +690,7 @@ WI_drawPercent if (p < 0) return; - V_DrawPatch(x, y, FB, percent); + V_DrawPatch(x, y, percent); WI_drawNum(x, y, p, -1); } @@ -709,14 +725,14 @@ WI_drawTime // draw if (div==60 || t / div) - V_DrawPatch(x, y, FB, colon); + V_DrawPatch(x, y, colon); } while (t / div); } else { // "sucks" - V_DrawPatch(x - SHORT(sucks->width), y, FB, sucks); + V_DrawPatch(x - SHORT(sucks->width), y, sucks); } } @@ -740,7 +756,11 @@ void WI_updateNoState(void) { if (!--cnt) { - WI_End(); + // Don't call WI_End yet. G_WorldDone doesnt immediately + // change gamestate, so WI_Drawer is still going to get + // run until that happens. If we do that after WI_End + // (which unloads all the graphics), we're in trouble. + //WI_End(); G_WorldDone(); } @@ -791,11 +811,11 @@ void WI_drawShowNextLoc(void) // draw a splat on taken cities. for (i=0 ; i<=last ; i++) - WI_drawOnLnode(i, &splat); + WI_drawOnLnode(i, splat); // splat the secret level? if (wbs->didsecret) - WI_drawOnLnode(8, &splat); + WI_drawOnLnode(8, splat); // draw flashing ptr if (snl_pointeron) @@ -986,10 +1006,6 @@ void WI_drawDeathmatchStats(void) int x; int y; int w; - - //int lh; // line height - - //lh = WI_SPACINGY; WI_slamBackground(); @@ -1000,11 +1016,10 @@ void WI_drawDeathmatchStats(void) // draw stat titles (top line) V_DrawPatch(DM_TOTALSX-SHORT(total->width)/2, DM_MATRIXY-WI_SPACINGY+10, - FB, total); - V_DrawPatch(DM_KILLERSX, DM_KILLERSY, FB, killers); - V_DrawPatch(DM_VICTIMSX, DM_VICTIMSY, FB, victims); + V_DrawPatch(DM_KILLERSX, DM_KILLERSY, killers); + V_DrawPatch(DM_VICTIMSX, DM_VICTIMSY, victims); // draw P? x = DM_MATRIXX + DM_SPACINGX; @@ -1016,33 +1031,29 @@ void WI_drawDeathmatchStats(void) { V_DrawPatch(x-SHORT(p[i]->width)/2, DM_MATRIXY - WI_SPACINGY, - FB, p[i]); V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2, y, - FB, p[i]); if (i == me) { V_DrawPatch(x-SHORT(p[i]->width)/2, DM_MATRIXY - WI_SPACINGY, - FB, bstar); V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2, y, - FB, star); } } else { // V_DrawPatch(x-SHORT(bp[i]->width)/2, - // DM_MATRIXY - WI_SPACINGY, FB, bp[i]); + // DM_MATRIXY - WI_SPACINGY, bp[i]); // V_DrawPatch(DM_MATRIXX-SHORT(bp[i]->width)/2, - // y, FB, bp[i]); + // y, bp[i]); } x += DM_SPACINGX; y += WI_SPACINGY; @@ -1274,17 +1285,17 @@ void WI_drawNetgameStats(void) // draw stat titles (top line) V_DrawPatch(NG_STATSX+NG_SPACINGX-SHORT(kills->width), - NG_STATSY, FB, kills); + NG_STATSY, kills); V_DrawPatch(NG_STATSX+2*NG_SPACINGX-SHORT(items->width), - NG_STATSY, FB, items); + NG_STATSY, items); V_DrawPatch(NG_STATSX+3*NG_SPACINGX-SHORT(secret->width), - NG_STATSY, FB, secret); + NG_STATSY, secret); if (dofrags) V_DrawPatch(NG_STATSX+4*NG_SPACINGX-SHORT(frags->width), - NG_STATSY, FB, frags); + NG_STATSY, frags); // draw stats y = NG_STATSY + SHORT(kills->height); @@ -1295,10 +1306,10 @@ void WI_drawNetgameStats(void) continue; x = NG_STATSX; - V_DrawPatch(x-SHORT(p[i]->width), y, FB, p[i]); + V_DrawPatch(x-SHORT(p[i]->width), y, p[i]); if (i == me) - V_DrawPatch(x-SHORT(p[i]->width), y, FB, star); + V_DrawPatch(x-SHORT(p[i]->width), y, star); x += NG_SPACINGX; WI_drawPercent(x-pwidth, y+10, cnt_kills[i]); x += NG_SPACINGX; @@ -1447,21 +1458,21 @@ void WI_drawStats(void) WI_drawLF(); - V_DrawPatch(SP_STATSX, SP_STATSY, FB, kills); + V_DrawPatch(SP_STATSX, SP_STATSY, kills); WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY, cnt_kills[0]); - V_DrawPatch(SP_STATSX, SP_STATSY+lh, FB, items); + V_DrawPatch(SP_STATSX, SP_STATSY+lh, items); WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+lh, cnt_items[0]); - V_DrawPatch(SP_STATSX, SP_STATSY+2*lh, FB, sp_secret); + V_DrawPatch(SP_STATSX, SP_STATSY+2*lh, sp_secret); WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]); - V_DrawPatch(SP_TIMEX, SP_TIMEY, FB, time); + V_DrawPatch(SP_TIMEX, SP_TIMEY, timepatch); WI_drawTime(SCREENWIDTH/2 - SP_TIMEX, SP_TIMEY, cnt_time); if (wbs->epsd < 3) { - V_DrawPatch(SCREENWIDTH/2 + SP_TIMEX, SP_TIMEY, FB, par); + V_DrawPatch(SCREENWIDTH/2 + SP_TIMEX, SP_TIMEY, par); WI_drawTime(SCREENWIDTH - SP_TIMEX, SP_TIMEY, cnt_par); } @@ -1535,70 +1546,42 @@ void WI_Ticker(void) } -void WI_loadData(void) +typedef void (*load_callback_t)(char *lumpname, patch_t **variable); + +// Common load/unload function. Iterates over all the graphics +// lumps to be loaded/unloaded into memory. + +static void WI_loadUnloadData(load_callback_t callback) { - 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"); - } - - // background - bg = W_CacheLumpName(name, PU_CACHE); - V_DrawPatch(0, 0, 1, bg); - - - // 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++; - // } - //} + 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 ; iepsd, 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;jepsd];j++) @@ -1607,16 +1590,16 @@ void WI_loadData(void) for (i=0;inanims;i++) { // MONDO HACK! - if (wbs->epsd != 1 || j != 8) + if (wbs->epsd != 1 || j != 8) { // animations - sprintf(name, "WIA%d%.2d%.2d", wbs->epsd, j, i); - a->p[i] = W_CacheLumpName(name, PU_STATIC); + DEH_snprintf(name, 9, "WIA%d%.2d%.2d", wbs->epsd, j, i); + callback(name, &a->p[i]); } else { // HACK ALERT! - a->p[i] = anims[1][4].p[i]; + a->p[i] = anims[1][4].p[i]; } } } @@ -1624,149 +1607,146 @@ void WI_loadData(void) } // More hacks on minus sign. - wiminus = W_CacheLumpName("WIMINUS", PU_STATIC); + callback(DEH_String("WIMINUS"), &wiminus); for (i=0;i<10;i++) { // numbers 0-9 - sprintf(name, "WINUM%d", i); - num[i] = W_CacheLumpName(name, PU_STATIC); + DEH_snprintf(name, 9, "WINUM%d", i); + callback(name, &num[i]); } // percent sign - percent = W_CacheLumpName("WIPCNT", PU_STATIC); + callback(DEH_String("WIPCNT"), &percent); // "finished" - finished = W_CacheLumpName("WIF", PU_STATIC); + callback(DEH_String("WIF"), &finished); // "entering" - entering = W_CacheLumpName("WIENTER", PU_STATIC); + callback(DEH_String("WIENTER"), &entering); // "kills" - kills = W_CacheLumpName("WIOSTK", PU_STATIC); + callback(DEH_String("WIOSTK"), &kills); // "scrt" - secret = W_CacheLumpName("WIOSTS", PU_STATIC); + callback(DEH_String("WIOSTS"), &secret); // "secret" - sp_secret = W_CacheLumpName("WISCRT2", PU_STATIC); + callback(DEH_String("WISCRT2"), &sp_secret); - // Yuck. - if (french) + // french wad uses WIOBJ (?) + if (W_CheckNumForName(DEH_String("WIOBJ")) >= 0) { - // "items" - if (netgame && !deathmatch) - items = W_CacheLumpName("WIOBJ", PU_STATIC); - else - items = W_CacheLumpName("WIOSTI", PU_STATIC); - } else - items = W_CacheLumpName("WIOSTI", PU_STATIC); + // "items" + if (netgame && !deathmatch) + callback(DEH_String("WIOBJ"), &items); + else + callback(DEH_String("WIOSTI"), &items); + } else { + callback(DEH_String("WIOSTI"), &items); + } // "frgs" - frags = W_CacheLumpName("WIFRGS", PU_STATIC); + callback(DEH_String("WIFRGS"), &frags); // ":" - colon = W_CacheLumpName("WICOLON", PU_STATIC); + callback(DEH_String("WICOLON"), &colon); // "time" - time = W_CacheLumpName("WITIME", PU_STATIC); + callback(DEH_String("WITIME"), &timepatch); // "sucks" - sucks = W_CacheLumpName("WISUCKS", PU_STATIC); + callback(DEH_String("WISUCKS"), &sucks); // "par" - par = W_CacheLumpName("WIPAR", PU_STATIC); + callback(DEH_String("WIPAR"), &par); // "killers" (vertical) - killers = W_CacheLumpName("WIKILRS", PU_STATIC); + callback(DEH_String("WIKILRS"), &killers); // "victims" (horiz) - victims = W_CacheLumpName("WIVCTMS", PU_STATIC); + callback(DEH_String("WIVCTMS"), &victims); // "total" - total = W_CacheLumpName("WIMSTT", PU_STATIC); - - // your face - star = W_CacheLumpName("STFST01", PU_STATIC); - - // dead face - bstar = W_CacheLumpName("STFDEAD0", PU_STATIC); + callback(DEH_String("WIMSTT"), &total); for (i=0 ; iepsd == 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); +} + +static void WI_loadCallback(char *name, patch_t **variable) +{ + *variable = W_CacheLumpName(name, PU_STATIC); +} + +void WI_loadData(void) +{ + if (gamemode == commercial) + { + NUMCMAPS = 32; + lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMCMAPS, + PU_STATIC, NULL); + } + else + { + lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMMAPS, + PU_STATIC, NULL); + } + + WI_loadUnloadData(WI_loadCallback); + + // These two graphics are special cased because we're sharing + // them with the status bar code + + // 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) { - int i; - int j; + WI_loadUnloadData(WI_unloadCallback); - Z_ChangeTag(wiminus, PU_CACHE); - - for (i=0 ; i<10 ; i++) - Z_ChangeTag(num[i], PU_CACHE); - - if (gamemode == commercial) - { - for (i=0 ; iepsd < 3) - { - for (j=0;jepsd];j++) - { - if (wbs->epsd != 1 || j != 8) - for (i=0;iepsd][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 ; iprev = block->next = &zone->blocklist; - // NULL indicates a free block. - block->user = NULL; + // a free block. + block->tag = PU_FREE; block->size = zone->size - sizeof(memzone_t); } @@ -109,8 +113,8 @@ void Z_Init (void) block->prev = block->next = &mainzone->blocklist; - // NULL indicates a free block. - block->user = NULL; + // free block + block->tag = PU_FREE; block->size = mainzone->size - sizeof(memzone_t); } @@ -129,45 +133,42 @@ void Z_Free (void* ptr) if (block->id != ZONEID) I_Error ("Z_Free: freed a pointer without ZONEID"); - if (block->user > (void **)0x100) + if (block->tag != PU_FREE && block->user != NULL) { - // smaller values are not pointers - // Note: OS-dependend? - - // clear the user's mark - *block->user = 0; + // clear the user's mark + *block->user = 0; } // mark as free - block->user = NULL; - block->tag = 0; + block->tag = PU_FREE; + block->user = NULL; block->id = 0; other = block->prev; - if (!other->user) + if (other->tag == PU_FREE) { - // merge with previous free block - other->size += block->size; - other->next = block->next; - other->next->prev = other; + // merge with previous free block + other->size += block->size; + other->next = block->next; + other->next->prev = other; - if (block == mainzone->rover) - mainzone->rover = other; + if (block == mainzone->rover) + mainzone->rover = other; - block = other; + block = other; } other = block->next; - if (!other->user) + if (other->tag == PU_FREE) { - // merge the next free block onto the end - block->size += other->size; - block->next = other->next; - block->next->prev = block; + // merge the next free block onto the end + block->size += other->size; + block->next = other->next; + block->next->prev = block; - if (other == mainzone->rover) - mainzone->rover = block; + if (other == mainzone->rover) + mainzone->rover = block; } } @@ -191,8 +192,9 @@ Z_Malloc memblock_t* rover; memblock_t* newblock; memblock_t* base; + void *result; - size = (size + 3) & ~3; + size = (size + MEM_ALIGN - 1) & ~(MEM_ALIGN - 1); // scan through the block list, // looking for the first free block @@ -206,42 +208,45 @@ Z_Malloc // back up over them base = mainzone->rover; - if (!base->prev->user) - base = base->prev; + if (base->prev->tag == PU_FREE) + base = base->prev; rover = base; start = base->prev; do { - if (rover == start) - { - // scanned all the way around the list - I_Error ("Z_Malloc: failed on allocation of %i bytes", size); - } + if (rover == start) + { + // scanned all the way around the list + I_Error ("Z_Malloc: failed on allocation of %i bytes", size); + } - if (rover->user) - { - if (rover->tag < PU_PURGELEVEL) - { - // hit a block that can't be purged, - // so move base past it - base = rover = rover->next; - } - else - { - // free the rover block (adding the size to base) + 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->user || base->size < size); + // the rover can be the base block + base = base->prev; + Z_Free ((byte *)rover+sizeof(memblock_t)); + base = base->next; + rover = base->next; + } + } + else + { + rover = rover->next; + } + + } while (base->tag != PU_FREE || base->size < size); // found a block big enough @@ -249,43 +254,39 @@ Z_Malloc if (extra > MINFRAGMENT) { - // there will be a free fragment after the allocated block - newblock = (memblock_t *) ((byte *)base + size ); - newblock->size = extra; + // there will be a free fragment after the allocated block + newblock = (memblock_t *) ((byte *)base + size ); + newblock->size = extra; - // NULL indicates free block. - newblock->user = NULL; - newblock->tag = 0; - newblock->prev = base; - newblock->next = base->next; - newblock->next->prev = newblock; + newblock->tag = PU_FREE; + newblock->user = NULL; + newblock->prev = base; + newblock->next = base->next; + newblock->next->prev = newblock; - base->next = newblock; - base->size = size; + base->next = newblock; + base->size = size; } - if (user) - { - // mark as an in use block - base->user = user; - *(void **)user = (void *) ((byte *)base + sizeof(memblock_t)); - } - else - { - if (tag >= PU_PURGELEVEL) + if (user == NULL && tag >= PU_PURGELEVEL) I_Error ("Z_Malloc: an owner is required for purgable blocks"); - // mark as in use, but unowned - base->user = (void *)2; - } + base->user = user; base->tag = tag; + result = (void *) ((byte *)base + sizeof(memblock_t)); + + if (base->user) + { + *base->user = result; + } + // next allocation will start looking here mainzone->rover = base->next; base->id = ZONEID; - return (void *) ((byte *)base + sizeof(memblock_t)); + return result; } @@ -309,7 +310,7 @@ Z_FreeTags next = block->next; // free block? - if (!block->user) + if (block->tag == PU_FREE) continue; if (block->tag >= lowtag && block->tag <= hightag) @@ -354,7 +355,7 @@ Z_DumpHeap if ( block->next->prev != block) printf ("ERROR: next block doesn't have proper back link\n"); - if (!block->user && !block->next->user) + if (block->tag == PU_FREE && block->next->tag == PU_FREE) printf ("ERROR: two consecutive free blocks\n"); } } @@ -386,7 +387,7 @@ void Z_FileDumpHeap (FILE* f) if ( block->next->prev != block) fprintf (f,"ERROR: next block doesn't have proper back link\n"); - if (!block->user && !block->next->user) + if (block->tag == PU_FREE && block->next->tag == PU_FREE) fprintf (f,"ERROR: two consecutive free blocks\n"); } } @@ -414,7 +415,7 @@ void Z_CheckHeap (void) if ( block->next->prev != block) I_Error ("Z_CheckHeap: next block doesn't have proper back link\n"); - if (!block->user && !block->next->user) + if (block->tag == PU_FREE && block->next->tag == PU_FREE) I_Error ("Z_CheckHeap: two consecutive free blocks\n"); } } @@ -425,24 +426,38 @@ void Z_CheckHeap (void) // // Z_ChangeTag // -void -Z_ChangeTag2 -( void* ptr, - int tag ) +void Z_ChangeTag2(void *ptr, int tag, char *file, int line) { memblock_t* block; - block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t)); + block = (memblock_t *) ((byte *)ptr - sizeof(memblock_t)); if (block->id != ZONEID) - I_Error ("Z_ChangeTag: freed a pointer without ZONEID"); + I_Error("%s:%i: Z_ChangeTag: block without a ZONEID!", + file, line); - if (tag >= PU_PURGELEVEL && (unsigned)block->user < 0x100) - I_Error ("Z_ChangeTag: an owner is required for purgable blocks"); + if (tag >= PU_PURGELEVEL && block->user == NULL) + I_Error("%s:%i: Z_ChangeTag: an owner is required " + "for purgable blocks", file, line); block->tag = tag; } +void Z_ChangeUser(void *ptr, void **user) +{ + memblock_t* block; + + block = (memblock_t *) ((byte *)ptr - sizeof(memblock_t)); + + if (block->id != ZONEID) + { + I_Error("Z_ChangeUser: Tried to change user for invalid block!"); + } + + block->user = user; + *user = ptr; +} + // @@ -456,12 +471,18 @@ int Z_FreeMemory (void) free = 0; for (block = mainzone->blocklist.next ; - block != &mainzone->blocklist; - block = block->next) + block != &mainzone->blocklist; + block = block->next) { - if (!block->user || block->tag >= PU_PURGELEVEL) - free += block->size; + if (block->tag == PU_FREE || block->tag >= PU_PURGELEVEL) + free += block->size; } + return free; } +unsigned int Z_ZoneSize(void) +{ + return mainzone->size; +} + diff --git a/frosted-doom/z_zone.h b/frosted-doom/z_zone.h index cf153d0..526f30d 100644 --- a/frosted-doom/z_zone.h +++ b/frosted-doom/z_zone.h @@ -1,18 +1,16 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- // -// $Id:$ +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard // -// Copyright (C) 1993-1996 by id Software, Inc. +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. // -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, +// This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // // DESCRIPTION: // Zone Memory Allocation, perhaps NeXT ObjectiveC inspired. @@ -20,7 +18,6 @@ // to John Carmack, might have been useful for // Quake. // -//--------------------------------------------------------------------- @@ -32,17 +29,26 @@ // // ZONE MEMORY // PU - purge tags. -// Tags < 100 are not overwritten until freed. -#define PU_STATIC 1 // static entire execution time -#define PU_SOUND 2 // static while playing -#define PU_MUSIC 3 // static while playing -#define PU_DAVE 4 // anything else Dave wants static -#define PU_LEVEL 50 // static until level exited -#define PU_LEVSPEC 51 // a special thinker in a level -// Tags >= 100 are purgable whenever needed. -#define PU_PURGELEVEL 100 -#define PU_CACHE 101 +enum +{ + PU_STATIC = 1, // static entire execution time + PU_SOUND, // static while playing + PU_MUSIC, // static while playing + PU_FREE, // a free block + PU_LEVEL, // static until level exited + PU_LEVSPEC, // a special thinker in a level + + // Tags >= PU_PURGELEVEL are purgable whenever needed. + + PU_PURGELEVEL, + PU_CACHE, + + // Total number of different tag types + + PU_NUM_TAGS +}; + void Z_Init (void); void* Z_Malloc (int size, int tag, void *ptr); @@ -51,36 +57,17 @@ void Z_FreeTags (int lowtag, int hightag); void Z_DumpHeap (int lowtag, int hightag); void Z_FileDumpHeap (FILE *f); void Z_CheckHeap (void); -void Z_ChangeTag2 (void *ptr, int tag); +void Z_ChangeTag2 (void *ptr, int tag, char *file, int line); +void Z_ChangeUser(void *ptr, void **user); int Z_FreeMemory (void); - - -typedef struct memblock_s -{ - int size; // including the header and possibly tiny fragments - void** user; // NULL if a free block - int tag; // purgelevel - int id; // should be ZONEID - struct memblock_s* next; - struct memblock_s* prev; -} memblock_t; +unsigned int Z_ZoneSize(void); // // This is used to get the local FILE:LINE info from CPP // prior to really call the function in question. // -#define Z_ChangeTag(p,t) \ -{ \ - if (( (memblock_t *)( (byte *)(p) - sizeof(memblock_t)))->id!=0x1d4a11) \ - I_Error("Z_CT at "__FILE__":%i",__LINE__); \ - Z_ChangeTag2(p,t); \ -}; - +#define Z_ChangeTag(p,t) \ + Z_ChangeTag2((p), (t), __FILE__, __LINE__) #endif -//----------------------------------------------------------------------------- -// -// $Log:$ -// -//-----------------------------------------------------------------------------