From 32d0425ff0594d93d1ef744003556f9355114c1d Mon Sep 17 00:00:00 2001 From: Simon Garrelou Date: Fri, 1 Jan 2021 18:56:53 +0100 Subject: First commit --- .gitignore | 5 + AUTHORS | 163 ++ COPYING | 367 +++ Makefile | 22 + NEWS | 566 +++++ README.md | 53 + README.old | 252 ++ TODO | 1495 ++++++++++++ config.h | 209 ++ data/Makefile.am | 12 + data/Makefile.in | 362 +++ data/prboom.txt | 207 ++ data/prboom.wad | Bin 0 -> 281020 bytes extensions/prboom/config.xml | 12 + extensions/prboom/menu.json | 15 + extensions/prboom/run.sh | 7 + src/KINDLE/i_joy.c | 68 + src/KINDLE/i_main.c | 409 ++++ src/KINDLE/i_network.c | 292 +++ src/KINDLE/i_sound.c | 534 ++++ src/KINDLE/i_sshot.c | 60 + src/KINDLE/i_system.c | 460 ++++ src/KINDLE/i_video.c | 529 ++++ src/Makefile.am | 72 + src/Makefile.in | 736 ++++++ src/am_map.c | 1585 ++++++++++++ src/am_map.h | 111 + src/d_client.c | 539 ++++ src/d_deh.c | 3090 +++++++++++++++++++++++ src/d_deh.h | 1118 +++++++++ src/d_englsh.h | 707 ++++++ src/d_event.h | 125 + src/d_items.c | 140 ++ src/d_items.h | 59 + src/d_main.c | 1725 +++++++++++++ src/d_main.h | 82 + src/d_net.h | 214 ++ src/d_player.h | 234 ++ src/d_think.h | 94 + src/d_ticcmd.h | 59 + src/doomdata.h | 204 ++ src/doomdef.c | 48 + src/doomdef.h | 330 +++ src/doomstat.c | 108 + src/doomstat.h | 332 +++ src/doomtype.h | 128 + src/dstrings.c | 85 + src/dstrings.h | 80 + src/f_finale.c | 668 +++++ src/f_finale.h | 56 + src/f_wipe.c | 202 ++ src/f_wipe.h | 45 + src/g_game.c | 2970 ++++++++++++++++++++++ src/g_game.h | 178 ++ src/hu_lib.c | 767 ++++++ src/hu_lib.h | 247 ++ src/hu_stuff.c | 1593 ++++++++++++ src/hu_stuff.h | 90 + src/i_joy.h | 47 + src/i_main.h | 44 + src/i_network.h | 74 + src/i_sound.h | 120 + src/i_system.h | 77 + src/i_video.h | 82 + src/info.c | 4899 +++++++++++++++++++++++++++++++++++++ src/info.h | 1498 ++++++++++++ src/lprintf.c | 382 +++ src/lprintf.h | 68 + src/m_argv.c | 58 + src/m_argv.h | 47 + src/m_bbox.c | 58 + src/m_bbox.h | 56 + src/m_cheat.c | 744 ++++++ src/m_cheat.h | 58 + src/m_fixed.h | 101 + src/m_menu.c | 5559 ++++++++++++++++++++++++++++++++++++++++++ src/m_menu.h | 182 ++ src/m_misc.c | 1081 ++++++++ src/m_misc.h | 111 + src/m_random.c | 147 ++ src/m_random.h | 154 ++ src/m_swap.h | 134 + src/md5.c | 240 ++ src/md5.h | 47 + src/mmus2mid.c | 866 +++++++ src/mmus2mid.h | 76 + src/p_ceilng.c | 467 ++++ src/p_checksum.c | 100 + src/p_checksum.h | 4 + src/p_doors.c | 711 ++++++ src/p_enemy.c | 2601 ++++++++++++++++++++ src/p_enemy.h | 118 + src/p_floor.c | 1042 ++++++++ src/p_genlin.c | 1164 +++++++++ src/p_inter.c | 913 +++++++ src/p_inter.h | 75 + src/p_lights.c | 443 ++++ src/p_map.c | 2335 ++++++++++++++++++ src/p_map.h | 92 + src/p_maputl.c | 683 ++++++ src/p_maputl.h | 89 + src/p_mobj.c | 1526 ++++++++++++ src/p_mobj.h | 403 +++ src/p_plats.c | 437 ++++ src/p_pspr.c | 829 +++++++ src/p_pspr.h | 119 + src/p_saveg.c | 1029 ++++++++ src/p_saveg.h | 66 + src/p_setup.c | 1688 +++++++++++++ src/p_setup.h | 57 + src/p_sight.c | 338 +++ src/p_spec.c | 3353 +++++++++++++++++++++++++ src/p_spec.h | 1141 +++++++++ src/p_switch.c | 1150 +++++++++ src/p_telept.c | 345 +++ src/p_tick.c | 291 +++ src/p_tick.h | 75 + src/p_user.c | 452 ++++ src/p_user.h | 47 + src/protocol.h | 96 + src/r_bsp.c | 664 +++++ src/r_bsp.h | 64 + src/r_data.c | 745 ++++++ src/r_data.h | 109 + src/r_defs.h | 428 ++++ src/r_demo.c | 88 + src/r_demo.h | 45 + src/r_draw.c | 1128 +++++++++ src/r_draw.h | 163 ++ src/r_drawcolpipeline.inl | 51 + src/r_drawcolumn.inl | 378 +++ src/r_drawflush.inl | 300 +++ src/r_drawspan.inl | 160 ++ src/r_filter.c | 119 + src/r_filter.h | 174 ++ src/r_fps.c | 450 ++++ src/r_fps.h | 76 + src/r_main.c | 649 +++++ src/r_main.h | 120 + src/r_patch.c | 786 ++++++ src/r_patch.h | 111 + src/r_plane.c | 468 ++++ src/r_plane.h | 67 + src/r_segs.c | 854 +++++++ src/r_segs.h | 44 + src/r_sky.c | 56 + src/r_sky.h | 55 + src/r_state.h | 116 + src/r_things.c | 1077 ++++++++ src/r_things.h | 72 + src/s_sound.c | 688 ++++++ src/s_sound.h | 100 + src/sounds.c | 245 ++ src/sounds.h | 305 +++ src/st_lib.c | 374 +++ src/st_lib.h | 209 ++ src/st_stuff.c | 1160 +++++++++ src/st_stuff.h | 102 + src/tables.c | 128 + src/tables.h | 93 + src/v_video.c | 1037 ++++++++ src/v_video.h | 207 ++ src/version.c | 38 + src/version.h | 40 + src/w_mmap.c | 333 +++ src/w_wad.c | 476 ++++ src/w_wad.h | 146 ++ src/wi_stuff.c | 1968 +++++++++++++++ src/wi_stuff.h | 64 + src/z_bmalloc.c | 123 + src/z_bmalloc.h | 52 + src/z_zone.c | 705 ++++++ src/z_zone.h | 129 + 173 files changed, 84548 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 Makefile create mode 100644 NEWS create mode 100644 README.md create mode 100644 README.old create mode 100644 TODO create mode 100644 config.h create mode 100644 data/Makefile.am create mode 100644 data/Makefile.in create mode 100644 data/prboom.txt create mode 100644 data/prboom.wad create mode 100644 extensions/prboom/config.xml create mode 100644 extensions/prboom/menu.json create mode 100644 extensions/prboom/run.sh create mode 100644 src/KINDLE/i_joy.c create mode 100644 src/KINDLE/i_main.c create mode 100644 src/KINDLE/i_network.c create mode 100644 src/KINDLE/i_sound.c create mode 100644 src/KINDLE/i_sshot.c create mode 100644 src/KINDLE/i_system.c create mode 100644 src/KINDLE/i_video.c create mode 100644 src/Makefile.am create mode 100644 src/Makefile.in create mode 100644 src/am_map.c create mode 100644 src/am_map.h create mode 100644 src/d_client.c create mode 100644 src/d_deh.c create mode 100644 src/d_deh.h create mode 100644 src/d_englsh.h create mode 100644 src/d_event.h create mode 100644 src/d_items.c create mode 100644 src/d_items.h create mode 100644 src/d_main.c create mode 100644 src/d_main.h create mode 100644 src/d_net.h create mode 100644 src/d_player.h create mode 100644 src/d_think.h create mode 100644 src/d_ticcmd.h create mode 100644 src/doomdata.h create mode 100644 src/doomdef.c create mode 100644 src/doomdef.h create mode 100644 src/doomstat.c create mode 100644 src/doomstat.h create mode 100644 src/doomtype.h create mode 100644 src/dstrings.c create mode 100644 src/dstrings.h create mode 100644 src/f_finale.c create mode 100644 src/f_finale.h create mode 100644 src/f_wipe.c create mode 100644 src/f_wipe.h create mode 100644 src/g_game.c create mode 100644 src/g_game.h create mode 100644 src/hu_lib.c create mode 100644 src/hu_lib.h create mode 100644 src/hu_stuff.c create mode 100644 src/hu_stuff.h create mode 100644 src/i_joy.h create mode 100644 src/i_main.h create mode 100644 src/i_network.h create mode 100644 src/i_sound.h create mode 100644 src/i_system.h create mode 100644 src/i_video.h create mode 100644 src/info.c create mode 100644 src/info.h create mode 100644 src/lprintf.c create mode 100644 src/lprintf.h create mode 100644 src/m_argv.c create mode 100644 src/m_argv.h create mode 100644 src/m_bbox.c create mode 100644 src/m_bbox.h create mode 100644 src/m_cheat.c create mode 100644 src/m_cheat.h create mode 100644 src/m_fixed.h create mode 100644 src/m_menu.c create mode 100644 src/m_menu.h create mode 100644 src/m_misc.c create mode 100644 src/m_misc.h create mode 100644 src/m_random.c create mode 100644 src/m_random.h create mode 100644 src/m_swap.h create mode 100644 src/md5.c create mode 100644 src/md5.h create mode 100644 src/mmus2mid.c create mode 100644 src/mmus2mid.h create mode 100644 src/p_ceilng.c create mode 100644 src/p_checksum.c create mode 100644 src/p_checksum.h create mode 100644 src/p_doors.c create mode 100644 src/p_enemy.c create mode 100644 src/p_enemy.h create mode 100644 src/p_floor.c create mode 100644 src/p_genlin.c create mode 100644 src/p_inter.c create mode 100644 src/p_inter.h create mode 100644 src/p_lights.c create mode 100644 src/p_map.c create mode 100644 src/p_map.h create mode 100644 src/p_maputl.c create mode 100644 src/p_maputl.h create mode 100644 src/p_mobj.c create mode 100644 src/p_mobj.h create mode 100644 src/p_plats.c create mode 100644 src/p_pspr.c create mode 100644 src/p_pspr.h create mode 100644 src/p_saveg.c create mode 100644 src/p_saveg.h create mode 100644 src/p_setup.c create mode 100644 src/p_setup.h create mode 100644 src/p_sight.c create mode 100644 src/p_spec.c create mode 100644 src/p_spec.h create mode 100644 src/p_switch.c create mode 100644 src/p_telept.c create mode 100644 src/p_tick.c create mode 100644 src/p_tick.h create mode 100644 src/p_user.c create mode 100644 src/p_user.h create mode 100644 src/protocol.h create mode 100644 src/r_bsp.c create mode 100644 src/r_bsp.h create mode 100644 src/r_data.c create mode 100644 src/r_data.h create mode 100644 src/r_defs.h create mode 100644 src/r_demo.c create mode 100644 src/r_demo.h create mode 100644 src/r_draw.c create mode 100644 src/r_draw.h create mode 100644 src/r_drawcolpipeline.inl create mode 100644 src/r_drawcolumn.inl create mode 100644 src/r_drawflush.inl create mode 100644 src/r_drawspan.inl create mode 100644 src/r_filter.c create mode 100644 src/r_filter.h create mode 100644 src/r_fps.c create mode 100644 src/r_fps.h create mode 100644 src/r_main.c create mode 100644 src/r_main.h create mode 100644 src/r_patch.c create mode 100644 src/r_patch.h create mode 100644 src/r_plane.c create mode 100644 src/r_plane.h create mode 100644 src/r_segs.c create mode 100644 src/r_segs.h create mode 100644 src/r_sky.c create mode 100644 src/r_sky.h create mode 100644 src/r_state.h create mode 100644 src/r_things.c create mode 100644 src/r_things.h create mode 100644 src/s_sound.c create mode 100644 src/s_sound.h create mode 100644 src/sounds.c create mode 100644 src/sounds.h create mode 100644 src/st_lib.c create mode 100644 src/st_lib.h create mode 100644 src/st_stuff.c create mode 100644 src/st_stuff.h create mode 100644 src/tables.c create mode 100644 src/tables.h create mode 100644 src/v_video.c create mode 100644 src/v_video.h create mode 100644 src/version.c create mode 100644 src/version.h create mode 100644 src/w_mmap.c create mode 100644 src/w_wad.c create mode 100644 src/w_wad.h create mode 100644 src/wi_stuff.c create mode 100644 src/wi_stuff.h create mode 100644 src/z_bmalloc.c create mode 100644 src/z_bmalloc.h create mode 100644 src/z_zone.c create mode 100644 src/z_zone.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7d4d312 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +Doom.wad +*.o +/prboom +/extensions/prboom/prboom +*.zip \ No newline at end of file diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..7839f8e --- /dev/null +++ b/AUTHORS @@ -0,0 +1,163 @@ +This file is now the amalgamated list of authors, contributors and credits +for PrBoom. Hopefully by keeping these all in one place, they will remain +more accurate. + +Doom was originally written by id software; when playing with any id main +wad file, you can see their list of credits, which includes the list of +programmers. After some years, they released the source code, to allow +others to work on improving the game. + +One of the first projects was DosDoom, by Chi Hoang. This was a quick port +of the released source code, which was for Linux, to DOS. This was then +picked up by TeamTNT (http://www.teamtnt.com/), who produced Boom, a greatly +debugged and extended version of Doom. The Boom programmers were Lee +Killough, Jim Flynn, Rand Phares, Ty Halderman. + +Several projects started working from the Boom source code. One was PrBoom, +made by Florian Schulze, that ported the code to Windows, added suport for +higher resolutions and later OpenGL. Another was Marine's Best Friend +(known as MBF) by Lee Killough, which fixed a lot of Boom bugs and added +many new game features. Finally, there was LxDoom, a port of Boom to Linux +by Colin Phipps. + +In October 1999, id Software re-released the Doom source code under the +GNU General Public License. TeamTNT have also changed to the new license, +and the other sources mentioned above have all allowed their code to be +GPLed. So PrBoom is covered by the GPL. + +In May 2000, LxDoom, PrBoom, and a derived port called LSDLDoom, merged into +one. The current authors of PrBoom are: + +Florian Schulze +Colin Phipps +Neil Stevens - Mac OS X porting +Andrey Budko +Rob Young (RjY) + +Our thanks go to all the authors of the ports mentioned above, and also the +following people who contributed code to LxDoom or PrBoom: + +Jess Haas +Of LSDLdoom, who merged his project into PrBoom, contributing his SDL code. + +Nicolas Kalkhof +Much work on the OpenGL renderer. + +James "Quasar" Haley +Ever willing to talk about source ideas, and has pointed me in the direction of +a lot of Boom and MBF bugs; also various bits code from his port Eternity have +been used, such as the BEX enhancements. + +Bob Aman (sporkmonger.com) +Created the RMUDAnsiTextView class used in the Mac launcher. + +Gady Kozma gady@math.tau.ac.il +Added hires to the SVGALib version of LxDoom, and other useful patches. + +Dick Leban +Lots of feedback about portability issues and helping get the network code +working properly back at v1.3.6. + +Eduardo Casino Almao +Lots of helpful feedback and suggestions, but more importantly actually getting +to grips with the code and giving very precise bug reports and patches. + +Joey Hess +For numerous patches, like the glibc fixes and window manager updates, and +help with the music. + +Ben Winslow +Various useful patches, like the colour ENDOOM code. + +Josh Parsons josh@schlick.anu.edu.au +Sent me the patches to use autoconf for configuring LxDoom. + +Steve Van Devender +Found the bug causing slight noise at the start of sounds playing, and other +patches. + +Barry Mead +Improvements to the mouse code and other odd patches. + +Mattias Kunkel +Made the lxdoom.spec file for creating LxDoom RPMs. + +Vicente Aguilar vicente@hal.dhis.org +Handy patch for the file handling + +Benjamin L McGee +Patch fixing the joystick code. + +Chris Young +Patch improving the ENDOOM printing + +Peter Jay Salzman +Cleanup patches + +Oliver Kraus +Send bug reports and patches for Solaris/Sparc. + +Paul S Jenner +Nice patch to make RPM building easier + +Julian +Fixed inline asm for gcc-2.95 (from Eternity) + +Lionel Ulmer +Patch to fix alignment problems on ARM processors. + +Ville Vuorinen +Spotted and helped patch the player spawn bug, as well as helping with some +Win32 issues. + +Steven Elliot +Misc patches. + +Andreas Dehmel +Spotted & patched a savegame bug. + +Jon Dowland +Bug reports & fixes, documentation improvements. + +If you have sent in patches and I forgot to list you, I apologise. Please email +me and I will add you. + +Also, thanks to the following people who have helped in various ways: + +Simon "fraggle" Howard +More MBF bugs. + +Robert Phipps +Network game testing, feature suggestions etc. + +Udo Monk +His port xdoom is very portable, and I referred to his code sometimes for help +with the X stuff; also his collection of Doom tools (XWadTools) is the +definitive tools collection for Linux. + +Andre Majorel +For Yadex, so I can debug those problematic levels more easily. + +Michael Heasley +Author of musserver, which helped me first add music support. + +Rafael Reilova +Helped with the music server program for LxDoom + +Frederic Oghdayan +For useful feedback on LxDoom v1.0.1, and repeating his bug reports until I +believed them :-). + +Adam Hegyi +Prompted me to hunt down those last few demo sync bugs, and provided some useful +insights and example demos to help. + +Adam Williamson +Pointing me toward yet another compatibility bug. + +Ingo van Lil +Another bug spotter. + +Everyone who contributed indirectly to MBF and Boom and Doom; see the +respective documentation files. + diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..f698bce --- /dev/null +++ b/COPYING @@ -0,0 +1,367 @@ +GNU GENERAL PUBLIC LICENSE +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +Preamble +The licenses for most software are designed to take away your freedom +to share and change it. By contrast, the GNU General Public License +is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit +to using it. (Some other Free Software Foundation software is covered +by the GNU Library General Public License instead.) You can apply it +to your programs, too. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge +for this service if you wish), that you receive source code or can +get it if you want it, that you can change the software or use pieces +of it in new free programs; and that you know you can do these +things. + +To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + +We protect your rights with two steps: (1) copyright the software, +and (2) offer you this license which gives you legal permission to +copy, distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, +we want its recipients to know that what they have is not the +original, so that any problems introduced by others will not reflect +on the original authors' reputations. + +Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making +the program proprietary. To prevent this, we have made it clear that +any patent must be licensed for everyone's free use or not licensed +at all. + +The precise terms and conditions for copying, distribution and +modification follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +0. This License applies to any program or other work which contains a +notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the +Program is covered only if its contents constitute a work based on +the Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any +warranty; and give any other recipients of the Program a copy of this +License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a +fee. + +2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + +a) You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change. + +b) You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Program or any part +thereof, to be licensed as a whole at no charge to all third parties +under the terms of this License. + +c) If the modified program normally reads commands interactively when +run, you must cause it, when started running for such interactive use +in the most ordinary way, to print or display an announcement +including an appropriate copyright notice and a notice that there is +no warranty (or else, saying that you provide a warranty) and that +users may redistribute the program under these conditions, and +telling the user how to view a copy of this License. (Exception: if +the Program itself is interactive but does not normally print such an +announcement, your work based on the Program is not required to print +an announcement.) +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the +Program with the Program (or with a work based on the Program) on a +volume of a storage or distribution medium does not bring the other +work under the scope of this License. + +3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the +following: + +a) Accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections 1 +and 2 above on a medium customarily used for software interchange; +or, + +b) Accompany it with a written offer, valid for at least three years, +to give any third party, for a charge no more than your cost of +physically performing source distribution, a complete +machine-readable copy of the corresponding source code, to be +distributed under the terms of Sections 1 and 2 above on a medium +customarily used for software interchange; or, + +c) Accompany it with the information you received as to the offer to +distribute corresponding source code. (This alternative is allowed +only for noncommercial distribution and only if you received the +program in object code or executable form with such an offer, in +accord with Subsection b above.) +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this +License. However, parties who have received copies, or rights, from +you under this License will not have their licenses terminated so +long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject +to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted +herein. You are not responsible for enforcing compliance by third +parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do +not excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under +this License and any other pertinent obligations, then as a +consequence you may not distribute the Program at all. For example, +if a patent license would not permit royalty-free redistribution of +the Program by all those who receive copies directly or indirectly +through you, then the only way you could satisfy both it and this +License would be to refrain entirely from distribution of the +Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended +to apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is +willing to distribute software through any other system and a +licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new +versions of the General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published +by the Free Software Foundation. If the Program does not specify a +version number of this License, you may choose any version ever +published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the +author to ask for permission. For software which is copyrighted by +the Free Software Foundation, write to the Free Software Foundation; +we sometimes make exceptions for this. Our decision will be guided by +the two goals of preserving the free status of all derivatives of our +free software and of promoting the sharing and reuse of software +generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + +END OF TERMS AND CONDITIONS +How to Apply These Terms to Your New Programs +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make +it free software which everyone can redistribute and change under +these terms. + +To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + +one line to give the program's name and an idea of what it does. +Copyright (C) yyyy name of author + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU 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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + +Also add information on how to contact you by electronic and paper +mail. + +If the program is interactive, make it output a short notice like +this when it starts in an interactive mode: + +Gnomovision version 69, Copyright (C) yyyy name of author +Gnomovision comes with ABSOLUTELY NO WARRANTY; for details +type `show w'. This is free software, and you are welcome +to redistribute it under certain conditions; type `show c' +for details. + +The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and +`show c'; they could even be mouse-clicks or menu items--whatever +suits your program. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the +program, if necessary. Here is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright +interest in the program `Gnomovision' +(which makes passes at compilers) written +by James Hacker. + +signature of Ty Coon, 1 April 1989 +Ty Coon, President of Vice + +This General Public License does not permit incorporating your +program into proprietary programs. If your program is a subroutine +library, you may consider it more useful to permit linking +proprietary applications with the library. If this is what you want +to do, use the GNU Library General Public License instead of this +License. + + +---------------------------------------------------------------------- +---------- +Return to GNU's home page. +FSF & GNU inquiries & questions to gnu@gnu.org. Other ways to contact +the FSF. + +Comments on these web pages to webmasters@www.gnu.org, send other +questions to gnu@gnu.org. + +Copyright notice above. +Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111, USA + +Updated: 16 Feb 1998 tower + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2c5450d --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +INCLUDE=-Isrc/ -Isrc/KINDLE -I. + +CFLAGS=$(INCLUDE) -D_GNU_SOURCE -DHAVE_CONFIG_H -DDISABLE_DOUBLEBUFFER + +C_FILES=$(wildcard src/*.c) $(wildcard src/KINDLE/*.c) +OBJ_FILES=$(patsubst %.c,%.o,$(C_FILES)) + +all: prboom + +src/%.o: src/%.c + $(CC) -c $(CFLAGS) $< -o $@ + +prboom: $(OBJ_FILES) Makefile + $(CC) -static $(CFLAGS) -o prboom $(OBJ_FILES) + +extension: prboom + mv $< extensions/prboom/$< + zip -r PrBoom_KUAL.zip extensions + +clean: + rm -rf $(OBJ_FILES) + rm -f PrBoom_KUAL.zip \ No newline at end of file diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..9591d0e --- /dev/null +++ b/NEWS @@ -0,0 +1,566 @@ +This file shows a history of changes between PrBoom versions since v2.1.0. +For historical reference, the complete LxDoom changelog follows it. + +Changes from v2.4.7 to v2.5.0 +- Limit the game to one CPU core on a multicore machine [prb+] +- Fix crash when out-of-range values are used in fixed point arithmetic [prb+] +- Allow the game to build without SDL_mixer, add --without-mixer option to + ./configure to force this. Music support will be disabled in this case +- Don't set the default game skill from the new game menu + Instead there is an option to set it explicitly in the General menu +- Fix the brightness of the player's weapon +- Fix linear filtering on flats in software mode +- Fix crash when an unknown sprite is used with a non-zero frame number +- Restore special case for trivial maps (bug #1837422) +- Fix screenshots in high colour screen modes - if libpng is available at + build time it will be used, otherwise a BMP will be saved +- Don't process mouse input in the menus [prb+] +- Always use Doom's main menu order to avoid bugs with Alien Vendetta [prb+] +- Remove line of junk graphics below status bar [prb+] +- Restore Boom friction and bobbing code [prb+] +- Fix crash by testing for null targets in mancubus fire code pointers +- Restore last known enemy check in Boom compatibility [prb+] +- Animated middle textures with zero index forced [prb+] +- Better handling of unrecognised demo formats [prb+] +- Fix for hanging decoration disappearing in Batman Doom MAP02 [prb+] +- Fix menu description: pain elementals are limited to 21 lost souls +- Manual page fixes from Debian +- Fix position of netgame player arrows on the automap in rotate mode +- Ignore chat key presses in multiplayer demo playback and -solo-net +- In deathmatch demo playback always draw player arrows on the automap +- In a multiplayer demo, don't reset view to console player on a new map +- Fix crash when MP3 music is being used and the player changes back to + a piece of music that's already been loaded before +- Avoid HOM effect on large maps such as epic.wad 5 [prb+] +- Fix sound origins on large levels [prb+] +- Handle demos with bad or missing headers [prb+] +- Fix the colour of player 4 (red) in multiplayer +- Play correct player pickup sounds in multiplayer demos +- Don't allow solids to pass through no-clipping objects in Doom [prb+] +- Restore Dehacked's ability to set the raisestate of a mobj [prb+] +- Handle demos with a missing end marker [prb+] +- Ignore switches that reference unknown textures instead of exiting +- Fix crash when resetting a menu to defaults [prb+] +- Fix crash when trying to play demos from Boom 2.00 [prb+] +- Fix crash in multiplayer demos when there are still sounds playing + on map changes (e.g. players revving chainsaws) [prb+] +- Fix mouse clicks on the intermission screen being ignored +- Don't eat screenshot key presses (see sf bug #1843280) +- Detect Hexen-format maps and refuse to play them, instead of crashing +- Fix crash when loading maps with missing player starts +- The backs of switches must be pressable in any demo recorded by + Boom 2.01, even those in Boom's "compatibility" mode [prb+] +- Force comp_doorstuck=1 in Boom 2.01 compatibility mode [prb+] +- comp_dropoff=1 was broken in MBF compatibility mode [prb+] +- Restore --disable-dogs but make sure it doesn't break Dehacked +- Fix desync if the user presses pause on the intermission screen [prb+] +- comp_666 fixed: either cyberdemon or spider can end E2M8 or E3M8; + killing a baron on E3M8 won't cause the level to end any more [prb+] +- Fix broken string matching in Dehacked [prb+] +- Passing --without-net to ./configure will compile the game without + network support; this may help if your platform lacks SDL_net +- Fix crash when reloading network savegames (bug #1590350) +- Fix bug in transparency rendering caused by doing it in two places +- Added high color rendering + +Changes from v2.4.6 to v2.4.7 +- Fixed comp_soul and comp_maskedanim options not actually being optional. +- Fixed searching for IWAD/prboom.wad (bugs #1585185, #1585600) +- Multiple sound crash fixes (bugs #1577495, #1586800) +- Fix for previously introduced HOM error +- Fix frame numbering problem in MBF dehacked patches (bug #1576151) + +Changes from v2.4.5 to v2.4.6 +- Mac OS X: Fixed music volume slider +- Implemented patch clipping. This fixes bug #1557501. +- Fixed update of compatibility options after use of TNTCOMP cheat +- Reenabled padding if short or missing reject lumps. + Patch #1570517 by RjY. +- Removed unaligned memory access in r_drawflush.inl. This should fix bus + errors on architectures where unaligned access is forbidden and should + give a slight speedup on other architectures. +- Stop right after the quit sound stops, instead of waiting three seconds +- Fixed sound origin for switches. This is compatibility optioned. + Patch #1533045 by RjY. +- Fixed "oof" sound when hitting ground while already dead + Patch #1532700 by RjY. +- Ported Eternitys fix to show the "ouch" face when severly hit +- Unified drawing functions, this speeds things up a bit and fixes most + artifacts on small numbers and fonts in high resolution modes. +- Mac OS X: Add resolution and video mode (OpenGL vs software) selection to + launcher +- Added rendering filters for software mode, they are configurable in a new + page in general settings +- Emulate some texture composition bugs +- Fix more common WAD bugs that can cause crashes +- Fixed random crashes caused by use of uninitialized memory +- Fix some demo incompatibilities caused by slime trail removal +- Fixed crashes with WADs which use newer gl nodes or don't have any nodes +- Automatically load gwa files with gl nodes +- Fixed integer overrun in automap on large levels (from PrBoom+) + +Changes from v2.4.4 to v2.4.5 +- fix crash when saving the game in levels with lots of monsters + (bug introduced in 2.4.4) +- -nodeh option to disable automatic loading of dehacked-in-wad lump +- Unified software and opengl engine into one binary +- Added video mode selection to menu +- fix demo desyncs on E1M5 on x86_64 systems +- Fullscreen setting will only take effect after game restart +- reduce red palette translation if the menu is up, so the menu can still be read +- screenshots now in PNG format on Linux/Unix in GL mode too +- Added experimental -checksum option for demo playback comparison +- Merged new internal patch (graphics) format from PrBoom 2.3 +- Mac OS X: Launcher now uses drawers instead of tabs +- Mac OS X: Fix some longstanding Wad chooser issues +- Mac OS X: Add a console to display text output from PrBoom + +Changes from v2.4.3 to v2.4.4 +- Don't fail when a texture name can't be looked up +- Increased several limits - Thanks to entryway and RjY + - Increased number of sidedef limit to 65534 + - Increased number of vertexes limit to 65535 + - Fixed crash when crossing sectors with very big height differences +- fix crash on E4M8 +- New command-line options for setting a window (-window) or fullscreen + (-nowindow) mode temporarily. +- The maximal supported resolution is increased from 1600x1200 to 2048x1536 +- GLBoom will use the closest supported resolution when running fullscreen +- The "RUN" key inverts the autorun state +- Live monsters are highlighted in a different colour on the iddt-automap +- Fixed OpenGL sky rendering in Requiem and Memento Mori +- The "Show coordinates of automap pointer" setting works now +- merged many cleanups and fixes from PrBoom 2.3 +- fix translucency map file handle leak +- fix consistency failures in netgames +- prevent crashes at 800x600 caused by rounding errors with naive clipping +- fixed slowdown at 1024x768 on some systems +- ability to play tasdoom demos directly +- -solo-net option is a shortcut for one-player network games +- emulate spechit overflows for dosdoom and tasdoom compatibility +- made several cleanups and fixes + +Changes from v2.4.2 to v2.4.3 +- Massive speed improvements in higher resolutions taken from Eternity. + Thanks to SoM and Quasar!!! +- fix bugs in gameplay occurring with gcc-4.1 +- Mac OS X: Add "Show Game Folder" to menus, for easy installation of new + game wads +- Mac OS X: Disable games in popup menu whose wads cannot be found +- fix compilation warnings +- tidy up configure script + +Changes from v2.4.1 to v2.4.2 +- Move gamma correction tables into prboom.wad +- Clean up light level calculations for walls & sprites +- CheckIWAD uses ANSI C streams for better portability and error handling +- Make screen wipe time independent of resolution +- Applied various small cleanups and fixes from PrBoom 2.3.1 +- Fix problems with dehacked substitution of long strings +- End of level sound crash fixed +- Mac OS X: Added simple launcher which allows to configure the most common + settings +- Mac OS X: Uses Quicktime for music now to fix crashes (adapted from Jaakko + Keränen's work in Doomsday) +- Windows: Converted project files to free Visual Studio 2005 Express Edition + +Changes from v2.4.0 to v2.4.1 +- PrBoom demos are now recorded with high-precision turning (like the + "Doom v1.91" hack that is floating around) +- when both -nodraw and -nosound are supplied, then no graphics will be + initialized and no windows opened +- add ultdoom compatibility level, and bring compatibility levels into line + with Prboom+ +- screenshots now use correct palette in software mode +- screenshots now in PNG format on Linux/Unix where available +- suppress use-supershotgun key in compatibility mode +- removed obsolete video related code +- fix screenshots on 64bit systems +- fix comp_666 + +Changes from v2.2.6 to v2.4.0 +- emulate reject overflows and spechit overflows - from prboom-plus +- more original doom compatibility options +- improve stretched graphics drawing for hires +- fix super-shotgun reload on last shot +- fix compilation with gcc 4.x +- fix some more dehacked support problems (e.g. Hacx) +- fix crash if pwad contains zero-length sound lumps +- added possibility to use mmap for wad access, this leads to less memory usage +- simplified the memory handling +- removed old Doom v1.2 lumps from prboom.wad +- windows also uses prboom.wad now +- add Mac OS X bundle build +- removed lumps and tables which are in prboom.wad from source + +Changes from v2.2.5 to v2.2.6 +- fix Inferno intermission screen crash +- fix lockup for other netgame clients when one client quits +- fix memory leak in netgame server +- fix SDL_LockScreen crashes on Win32 +- fix fuzz drawing for hi-res +- network games should survive temporary loss of connection +- fix dehacked NOSECTOR/NOBLOCKMAP effects +- fix player spawn sound + +Changes from v2.2.4 to v2.2.5 +- fix crash caused by long messages in HUD +- live monster counter on HUD +- notify server if client quits during startup wait +- improved response file parser +- fast forward to given map # in demo playback +- fixes for various sound bugs +- fix doom2 demos at levels with >10 deathmatch starts +- and more compatibility and demo fixes +- support higher-turning-resolution demos from v1.91 +- fix compilation with gcc 3.4.x + +Changes from v2.2.3 to v2.2.4 +- fixed sky-over-sky HOM +- add sound compatibility option +- improve sound volume accuracy +- shared texture palette isn't the default anymore +- better invulnerabilty rendering for non paletted OpenGL +- network game server can now read config files to set game options +- fix latency problems in LAN games +- small compilation fixed for OpenGL on some unix platforms +- fix for dehacked files which change frames +- fixed name clash when compiling for some unix platforms +- flag counted items with different colour on the IDDT automap +- fixed extra shot sound when chaingun runs out of ammo +- fix some telefragging related desyncs +- fixed offsets for flipped sprites +- hopefully fix problems with network games on big-endian platforms + +Changes from v2.2.2 to v2.2.3 +- improved mouse handling +- intermission demo sync bug fixed +- framebuffer update fixes (solves flicker on fbcon) +- -forceoldbsp allowed in non-GL version, and saved in demos +- fix player colours in multiplayer demos +- apply workarounds for buggy pwads even during demo playback +- fix numpad 5 key +- allow compilation on systems where SDL is built without joystick support +- fix comp_skymap +- using anisotropic filtering when the OpenGL extension is available +- using paletted textures when the OpenGL extension is available +- added gl_use_paletted_texture option to glboom configuration file +- using shared texture palette when the OpenGL extension is available +- added gl_use_shared_texture_palette option to glboom configuration file + +Changes from v2.2.1 to v2.2.2 +- more demo sync problems for original Doom and Boom fixed +- added changeable samplerate for soundmixing +- added fullscreen/window toggle in option menu +- added double buffering +- floor rendering made more accurate +- Win32 config file handling fixed +- fix endian conversion problem on Linux/PPC + +Changes from v2.2.0 to v2.2.1 +- improved fix for demo sync problems with lost souls bouncing off floors +- fixed bug where loading a -fast or -respawn savegame failed to restore + those options properly +- fixed demo sync bug with doors also tagged to lift triggers +- fix some endianness problems in the OpenGL renderer +- hopefully fixed some problems compiling for Linux/ARM +- fix multi-level demo time totals to agree with compet-n +- linux rpm is now a bit more standardised + +Changes from v2.1.2 to v2.2.0 +- fix compiling problem on alpha processors (size_t != unsigned long) +- fixed stair building (ex. TNT - Evilution MAP30) +- fixed OpenGL menu drawing bug +- hopefully fixed top sky line bug for some OpenGL drivers +- added joystick support through SDL +- made a (temporary) fix for the crash at 800x600 when timidity can't find cfg +- fixed some key binding problems +- fixed linking problems on some UNIX systems + +Changes from v2.1.1 to v2.1.2 +- fix problem with sound stereo +- fix problem with new network games +- supports demo files with base name >8 characters +- enable IDDT and other display cheats in demo playback +- various fixes for running on Solaris/sparc + +Changes from v2.1.0 to v2.1.1 +- config file is now prboom.cfg for the non-GL version, glboom.cfg + for the GL version. If you have used PrBoom (or LxDoom) before, + rename your old config file (boom.cfg) appropriately. +- fullscreen is now default for new prboom.cfg +- included sdl_mixer.dll now plays midi-files +- if waveout is used for sound (Windows NT4) the sound doesn't stutter anymore +- redid parts of the OpenGL renderer + - sprites behind translucent walls are rendered correctly + - translucent walls are rendered correctly + - support for glBSP nodes + - compliant to glBSP spec v2 + - use_mipmapping option in boom.cfg + - the default for zone memory in OpenGL is now 16MB +- fix screen melt transition +- most Boom demos should now work +- a lot more original Doom demos work +- keycard switches are shown coloured on the map, like doors +- improved ENDOOM rendering +- non-highres rendering functions dropped + +----------------------------------------------------------------------------- +This file is a log of all the changes to LxDoom since v1.0.0. +Note that LxDoom v0.* was a seperate line of development. + +* Changes from v1.4.4 to the PrBoom merger +- Fix rare demo sync problem (LxDoom v1.4.x bug, only noticed on Memento + Mori DEMO3) +- Fix memory management bugs + - Memory wasted by bug in Z_FreeTags (original Doom bug) + - Store correct size in extra memory blocks (Boom/MBF bug, harmless + except when debugging) + - Fix level precaching + - Disabled by default, controlled by config file + - Fix needlessly locked lumps (bug since LxDoom v1.3.2) + +* Changes v1.4.3 to v1.4.4 +- Install documentation in the right directory +- Sound code cleanup +- Fix problem with network games often desyncing immediately at startup + +* Changes v1.4.2 to v1.4.3 +- Improved mouse resolution, thanks to a patch from Barry Mead +- Various robustness fixed to the networking code +- Fixed various build problems + - gcc 2.7.2 compile problems fixed + - uid_t problems on odd systems should be fixed + +* Changes v1.4.1 to v1.4.2 +- Fixed various build problems, including + - Networking not work on many systems + - Portability improvements, in particular for Sparc + - Autoconf getting confused on systems with X headers in the include path +- Fix bug with music not looping after being unpaused +- Misc minor improvements + +* Changes v1.4.0 to v1.4.1 +- Fixed occasional tutti fruiti on non-power-of-2 short textures +- Fixed minor bug in the WAD autoloading code +- Fixed the function keys in lsdoom, thanks to a patch from Chris Purnell +- Fixed all compile warnings with the new gcc + +* Changes v1.3.7 to v1.4.0 +- License is now the GNU General Public License, see COPYING. +- autoconf based setup makes compiling LxDoom simple on most systems; + automatically compiles only the versions and features your system + supports. +- Fixed rendering bugs: + - tall vertical shafts did not block vision on the automap, and on x86 + systems there could be crashes in the column rendering near such shafts ( + bug from original Doom). + - fixed slowdown caused by non-power of 2 height textures in the case + where they don't tile (i.e. almost all cases) (this was the tutti-fruiti + "fix" from Boom, I've "fixed the fix" in a sense) + - fixed a slight slowdown caused by a bad optimisation (an old LxDoom bug) +- Fixed bug where things were rendered brighter in high-res, depending on the + resolution (bug from PRBoom). +- Improvements to the sound code: + - Fixed noise at the start of sounds playing (thanks to Steve Van Devender). + - LxDoom detects the music or sound server exiting (alright, so I mean + crashing ;-) and stops sending more data. +- Performance improvements, including: + - New algorithm in P_GroupLines, saves seconds when loading big levels. +- Fixed problems with the networking code, where multihomed machines could + get the wrong IP registered with the server. +- Screen code improvements: + - Rewrote screen layout logic, fixing numerous bugs. + - Fixed bug with flipped patches in high-res that could cause crashes, + thanks to Gady Kozma. + - Independent x and y scaling of the status bar, by Gady Kozma. +- Added warning messages whenever LxDoom auto-corrects errors in buggy + PWADs. Also made -devparm cause LxDoom to initialise all textures at + startup, so all texture errors are found at once. +- Store config files and save games in ~/.lxdoom/ instead of the current + directory, removed the -cdrom parameter. +- Fixed Doom bug where the "got a medikit you REALLY needed" message was + never used. Thanks to James "Quasar" Haley for pointing that one out. +- Made the numeric keypad keys be treated differently from their normal + equivalents, so you can bind them to different actions. +- Fixed bad importing of mobj pointer reference code from MBF. +- The level completed screen is now shown after ExM8 levels in Doom 1/ + Ultimate Doom. +- Minor coop improvements: + - Total game time shown on the intermission screen, as for single player + - Quicksave enabled +- Removed the frame rate dots, instead I added a cheat code "IDRATE" to show + various rendering stats, including the frame rate. +- Fixed the intermission screen code to store its data right (bad code from + original Doom). + +* Changes v1.3.6 to v1.3.7 +- Client-server style net-games, including new server program +- LxDoom starts faster, thanks to an idea borrowed from DosDoom +- Player colours system sorted out, now your personal player colour is part of + your player preferences. +- Fix for problems with 24bpp screens, new option in config file to deal with + this. +- Fix key setup problems where certain choices of key setup could hinder + message typing in multi-player. +- Misc stuff + +* Changes v1.3.5 to v1.3.6 +- Hires for the SVGALib version +- Automap rotation/overlay +- Modified to work with the new musserver +- Various misc improvements + +* Changes v1.3.4 to v1.3.5 +- Fixed nasty overflow in I_GetTime_RealTime, causing hangs +- Removed a load of I_GetTime references in m_menu.c +- Added support for music pausing/unpausing + +* Changes from v1.3.3 to v1.3.4 +- More MBF features/improvements imported: + - Internal improvements (mobj pointer reference counting) + - Enhanced skies support +- Status bar scaling for high-res +- Bug fixes: + - Occasional corrupt save-games in large levels fixed (Boom/MBF bug) + - -loadgame crashes fixed +- Performance improvements +- Command line argument parsing logic changed for convenience in shell scripts + (later arguments take precedence) + +* Changes from v1.3.2 to v1.3.3 +- Optimised i386 assembly some more, about 2% improvement in fps +- Tested to compile and run on FreeBSD +- Modified #includes to use current headers +- Updated makefile hints for FreeBSD compiling +- Made install script more portable + +* Changes from v1.3.1 to v1.3.2 +- Imported/added some MBF features + - New code pointers added + - "Faster" sprite sorting + - Improved Dehacked handling (more reliable, Dehacked-in-a-PWAD) + - Fractional floor attributes saved in save-games + - Auto-correction of common errors in wads +- Massive internal improvements, making LxDoom more stable - WAD lump locking, + rewritten patch drawing code. +- Improved config file handling - now accepts (and writes out selected) numbers + in hex, entries are sorted into sections with headers, and internally the + handling is better. +- Portability improvements - LxDoom is now near-completely endian-corrected, so it + should be compilable on big-endian machines, read the little endian Doom data + files fine, and even network with other machines regardless of endianness. + Also lots of misc portability stuff, explicitly signing some variables, a + lot more stuff made const, etc. The only problem I think is that save-games aren't + yet interchangeable across endiannesses. +- More memory efficient - block memory allocator reduces memory fragmentation, + video buffers allocated only when needed, more things made constant and + initialised better. +- Imported bug fixes from MBF: + - File handle leak in translucency code + - Water sector sprite problems + - No chat in demo playback + - Archville fire spawn + - Scroller calculations overflow + - Fast shots going through walls + - Improved d_deh.c fixed numerous SIGSEGV's and error code bugs + - Zombie players exiting levels + - New thing flags caused incompatibility with buggy Doom wads + - Setup menu backspace + - Indigo/Brown default chat keys reversed +- Glide (3dfx) frame-buffer target (warning - released only in source code form and + only for alpha testing purposes, not ready for normal use). +- Improved ENDOOM support - (optional) colour ENDOOM display, non-ASCII + characters displayed, sensible choice between ENDOOM and ENDBOOM (displays + any from a PWAD in preference, randomly chooses otherwise). +- Minor improvements so LxDoom integrates more naturally into UNIX systems; sound + and music server are now searched for via the path, and wads are looked for in + /usr/local/games/wads/ if no DOOMWADDIR is set. +- More keys work in the SVGALib version (notably PAUSE). +- Monster-monster kills in coop are assigned to the player the monster was + targeting, or a random player if it wasn't targeting any, so coop + monster kills stats total 100% at the end-level screen. +- Total game time is displayed on the intermission screens. This is a simple + total of the times shown on the end-level screens so far this game, not + including intermission times, and accurate to 1/35 of a second. +- Low sound volume fixed. +- Multi-player colours selectable in the config file. +- Misc minor fixes and improvements inspired by MBF: + - Support for -noload parameter + - Support auto-loading of deh/BEX files as well as wads + - Removed limit on number of wad-files loaded. + - Fixed buffer overrun in menu text writing code by wrapping long lines. + +* Changes from v1.3.0 to v1.3.1 +- Fixed saving of config file (bug affected most Linux systems) +- Binaries are now use libc.so.6. +- 24 bpp and 32 bpp true colour X displays are now supported (untested) (24 + bpp only supported for i386 systems). +- Auto-loading of wad files - in the config file there is a new option + which lists wad files to be loaded automatically (several directories are + searched as for IWADs). +- Loading saved games during a multi-player game now works. Very handy for + coop games :). +- New config file option controls music pausing - when the game pauses + the music can either continue or be stopped. So people playing at home can + have the music continue while they read the map; people playing at work + can pause when the boss comes in and have the music stop ;). +- Several more variables added to config file, most notably the + default size of the LxDoom window (for high-res). +- PRBoom v2.02 networking code is now used. It still doesn't network with + PRBoom though. Net games with just LxDoom work fine still. Anyone with ideas + why it won't go with PRBoom let me know. +- If saving a demo/screen-shot/save-game to disk fails an error message is + displayed. One of the most frustrating features of all versions of Doom that I + have used is that they always say "Game Saved" even if you are + out of disk space and it didn't save. I'm glad to have this one fixed. +- Fixed the -cdrom parameter. +- Fixed makefile hints for FreeBSD. +- Fixed music pausing causing musserver crash. +- Documentation updates. + +* Changes from v1.2.0 to v1.3.0 +- Hi-res added to X-windows version +- Portability improvements (FreeBSD and RISC stuff in the makefile, minor code + changes included) +- Minor bug-fixes + +* Changes from v1.1.1 to v1.2.0 +- Boom v2.02 updates incorporated (see TeamTNT's site for info on that) +- Improved music comms code, to pass instruments and volume info +- Code reorganisation & tweaking; video code is more logically organised, + and SVGALib code is neater now. + +* Changes from v1.1.0 to v1.1.1 +- Fixed crash using -warp parameter with SVGALib version +- Fixed music server communication code +- Should compile using glibc + +* Changes from v1.0.1 to v1.1.0 +- SVGALib version +- Fixed timing problem on buggy kernels causing crashes in the wipe screens +- Fixed bug in sound server communications which prevented Doom 1 working +- Fixed problem with sound code causing accelerated sound on v2.1.125 kernel +- Removed need for IPC in sound server communications, used pipe instead +- Improved mouse grabbing/ungrabbing code in XFree86 version, now depends on + game and window status +- Improved TrueColor/DirectColor 16 bpp support +- X version is more multitasking friendly - detects when it is hidden or paused + or an intermission screen is up, and tries to free some more CPU time. + +* Changes from v1.0.0 to v1.0.1: +- 16 bpp colour modes now supported. If you use a 16 bpp colour mode (65 + thousand colours approx.), then you don't have to change your X setup to 256 + colours (8 bpp) before using lxdoom anymore. However, it is still a good idea + to use 256 colours, because it is faster that way. +- fixed a minor bug in routine used for the 8 bpp '-2' option (screen + doubling), which caused a couple of lines to be missed at the bottom of the + display window. +- fixed a Boom bug which caused crashes in multi-player games. The bug occurred + when, during a single game session, first the players played one level at + which someone died, and then later exited that level, and later still another + player died. I.e in a multilevel death-match, or a long coop game. Caused one + machine to exit lxdoom with 'Segmentation Violation'. The version of PRBoom I + have also exhibits these symptoms, though obviously I can't be sure that this + is the cause; Boom v2.0 and v2.01 had this bug. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..feb9548 --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# kindle-doom -- a port of PrBoom for the Kindle 4 + +## Description + +This repository contains the source code for a port of the [PrBoom](http://prboom.sourceforge.net/) project to the Kindle 4. It is **not** intended as anything more than a proof-of-concept: the Kindle's e-ink display is absolutely not adapted to gaming. + +## Installing & playing + +Prerequisites: copy your `doom.wad` and `prboom.wad` to the root of your Kindle USB partition. `prboom.wad` can be found [here](data/prboom.wad). + +1. Download the latest release +2. Make sure you installed [KUAL](https://www.mobileread.com/forums/showthread.php?t=203326) on your Kindle. +3. Extract the release to the root of your Kindle USB partition +4. Run KUAL and run "Simon's Fun Land -> PrBoom" + +The controls are as follows: +- Keypad to move +- "OK" button to shoot +- "Home" button to quit + +There's no "Use" key, because I haven't totally figured out how the other buttons work yet. + +## Compilation + +If you want to build the project for yourself, you will need an `armv7` GCC toolchain. I successfully used Bootlin's [`armv7-eabihf`](https://toolchains.bootlin.com/releases_armv7-eabihf.html) "musl" toolchain. Compiling with the glibc toolchain also works, but the `libc` on the Kindle is too old and it will refuse to start. + +Export `CC` to the location of the GCC cross-compiler and run `make`. + +```shell +$ export CC=/home/simon/armv7-eabihf--musl--stable-2020.08-1/bin/arm-linux-gcc +$ make -j8 +``` + +## Changes + +Based on [`prboom-2.5.0`](https://sourceforge.net/projects/prboom/files/prboom%20stable/2.5.0/). + +The main change is the addition of `src/KINDLE/`, which defines most Kindle-specific functions. I basically copied `src/SDL/` and modified everything to remove dependencies on SDL and instead work directly on the Kindle's framebuffer. + +Resolution is hardcoded to 600x800 and cannot be changed. + +I removed all the autoconf stuff and wrote a Makefile by hand. + +## Known bugs + +- Demo playback doesn't seem to work correctly. I think this is due to tick calculation, but I'm not sure. +- Because of this, it is not really possible to load the game directly, you have to "warp" to the beginning of the first level. + +## Limitations + +- The code is horrible, I only tried to hack together something that works. +- There's no sound support, because my Kindle doesn't have speakers / aux output. +- The game is basically unplayable because of the e-ink refresh mode, but it's still a nifty demo nevertheless. \ No newline at end of file diff --git a/README.old b/README.old new file mode 100644 index 0000000..d1ac70d --- /dev/null +++ b/README.old @@ -0,0 +1,252 @@ +PrBoom 2.5.0 +============ + +PrBoom is a version of the classic 3D shoot'em'up game Doom, originally +written by id Software. + +See the file AUTHORS in this distribution for a list of authors and +other contributors, and a history of the projects PrBoom is derived +from. + +PrBoom is made available under the GNU General Public License. See the +file COPYING included in this distribution for details. + +Please see the NEWS file included for changes since the previous version. + +Game data - WADs +---------------- + +(This section is aimed at people not familiar with Doom and the +data files it uses.) + +PrBoom is a game engine - it provides a program to play Doom levels, but +it doesn't include any levels itself. More importantly, you need all the +sounds, sprites, and other graphics that make up the Doom environment. +So to play PrBoom, you need one of the main Doom date files from id +Software - either doom.wad, doom2.wad, tnt.wad or plutonia.wad from one +of the commercial Doom games, or the shareware doom1.wad. This file +is called the IWAD. + +PrBoom also supports playing Doom add-on levels, called "PWADs", which +are small extra .wad files which just contain extra levels or other +resources. PWADs are ONLY ADD-ONS, you still need the original IWAD +that they are designed to work with. In practice, most PWADs on the +Internet require doom2.wad (although some work with doom.wad). + +If you don't own any of the Doom games, get the shareware doom1.wad +from doom19s.zip on Doomworld's shareware download page. But note that you +will not be able to play most add-ons. +http://www.doomworld.com/files/shareware.shtml + +Windows Installation +-------------------- + +Just extract the zip to a directory of your choice and copy your IWAD +files into it. Now you can make shortcuts and add "-iwad filename.wad" +to them. + +The SDL_mixer library used by PrBoom supports software MIDI music +synthesis. If you want to hear the Doom music, you need a set of +Timidity instrument patches. Do a web search for timidity patch sets, +there are plenty around. +These patch sets are a large download (>5megs). +SDL_mixer does not currently support hardware MIDI synthesis. But we +have added a hacked version of SDL_mixer with native midi support. If +you like to try it out, rename SDL_mixer_beta.dll to SDL_mixer.dll. +You should rename the original SDL_mixer.dll before. Tell us if it +works or not. Please note, that there might be bugs in the native midi +implementation. + +Linux Installation +------------------ + +For UNIX, Linux, and other POSIX systems, you need the SDL libraries in +order to use PrBoom. If you haven't already done so, visit +http://prboom.sourceforge.net/linux.html and follow the instructions there +for your system, downloading the necessary libraries, and either +installing the binary RPM package or compiling PrBoom from source. + +Once you've done that, you'll need to copy your IWAD file (see the section +above if you don't know what this is) to a directory where PrBoom can find +it. Make /usr/local/share/games/doom/, and copy your IWAD (all of your +IWADs, if you own more than one) to that directory. + +Mac OS Installation +------------------- + +Copy your IWAD (see above) into your home folder under +Library:Application Support:PrBoom (this folder will be created for you the +first time you run PrBoom). + +First Use +--------- + +If it's the first time you've run PrBoom, you'll need to do some configuring +to get the controls and display right for you. + +On a new installation, PrBoom runs at 640x480 resolution. If you have used +PrBoom before, you may have an old config file in your home directory which +specifies a lower resolution, such as Doom's normal 320x200. You can use the +-width and -height parameters to select a higher resolution, e.g.: + +prboom -width 640 -height 400 + +sets the resolution. This setting is remembered for future sessions. For +other parameters, see the included README.command-line. + +You may also wish to customise the key bindings. PrBoom's default keybindings +are the same as the original Doom; unlike original Doom, you can change key +bindings in the game. In the in-game menus, go to Options, Settings, Key +Bindings. + +On Mac OS X, you can't use the command line, but after running the program +once, you can edit YOURHOME:Library:Application Support:PrBoom:prboom.cfg to +change settings like your screen resolution. + +Features +-------- + + This is all the features PrBoom has compared to the original Doom game + - it's intended to give you an idea of the enhancements, rather than + burying you in details. + + See http://prboom.sourceforge.net/about.html for an HTML version of + this list. + + This is shamelessly modelled on Boom's changes pages. By each + change, there's the name of the port the feature comes from (so it's + compatible with). + +Playing the game + + * Supports loading dehacked files at the command line, or in WADs + (BOOM, MBF) + * Supports PWADs containing sprites and flats (BOOM) + * Save games and demos completely store game parameters (BOOM, + MBF) + * Savegames store list of loaded WAD files, warning if wrong files + loaded (BOOM, MBF) + +Game engine + + * Player bobbing improved, optional (BOOM, MBF) + * Friction effects (BOOM), affecting players and monsters + (MBF) + * Wind, current, conveyor effects (BOOM) + * Far more flexible scrolling wall/floor types (BOOM) + * Always run (BOOM) + * Weapon change logic overhauled and improved (BOOM) + * Support for friendly monsters, helper dogs (MBF) + * Monster target finding code improved (MBF) + * AI improvements (MBF) + * Bouncy and touchy things (MBF) + * New code pointers (MBF) + * Per-level and animated skies (MBF) + * Generalised line types system gives complete flexibility + (BOOM) + * Elevators (BOOM) + * Translucent sprites, walls (BOOM) + * Independent floor and ceiling lighting (BOOM) + * Silent teleports (BOOM) + * Deep water, true underwater areas (BOOM) + * Icon of Sin telefragging made more consistent (MBF) + * Fix large numbers of game bugs (BOOM, MBF, LxDoom) + * Support arbitrary texture heights (BOOM) + +Screen + + * High resolution support (PrBoom) + * Optional message console, multiple message lines (BOOM) + * Status bar shows health/armour/ammo in colours (BOOM) + * Heads up display, showing ammo, health, keys overlayed on view + (BOOM) + +Multiplayer + + * Spy mode improved (BOOM) + * Support for loadgame in a net game (LxDoom) + * Client server style network games (LxDoom) + +Automap + + * No limit on marks (BOOM) + * Rotation and overlay modes (DOSDoom, LxDoom) + * Map shows coordinates (BOOM), optionally follow pointer + (MBF) + * Teleport lines, key doors and switches marked specially (BOOM) + * Keys, secrets visible on map with cheat codes (BOOM) + * Colours fully configurable from menus (BOOM) + +Intermission screens + + * Par times hidden when not relevant (BOOM) + * Total episode time shown (LxDoom) + +Menus + + * F1 help screen shows current key setup (BOOM) + * Key bindings, monster behaviour, and compatibility settings all set + in menus (BOOM, MBF) + +Compatibility + + * Game is capable of behaving like any of: original Doom v1.9, Boom + v2.02, MBF (BOOM, MBF, LxDoom) + * Plays most original Doom v1.9 demos (more than Boom or MBF) + * Plays most Boom v2.02 demos (apart from levels with friction + effects everything should work). + * Plays some DOSDoom, earlier Doom, earlier Boom, and LxDoom demos. + * Plays all MBF demos. + * Auto-correction of common bugs in old levels (MBF), with + warnings (LxDoom) + * Fine control of options controlling compatibility and new features + (MBF) + +Controls + + * Greater control of key bindings from in game menus (BOOM) + * More accurate mouse sensitivity control (BOOM, LxDoom) + +Misc + + * Screenshot code improved, supports BMPs (BOOM) + * Support for ENDOOM and ENDBOOM (BOOM, LxDoom) + * -timedemo and -fastdemo options (BOOM) + * Real time frame rate, segs, visplanes, sprites display + (LxDoom) + * Various extra cheat codes (BOOM, LxDoom) + +Internals + + * Greatly improved internal memory management (BOOM, LxDoom) + * Startup time greatly shortened by lazy generation of some lookups + (DOSDoom, LxDoom) + * Removed internal limits (BOOM) + +Other Tips +---------- + +On Linux, SDL tries to detect an appropriate video device automatically. +If you want to overrite the default, you can set the SDL_VIDEODRIVER +enviromental variable. At a bash prompt, this is as easy as running: + +SDL_VIDEODRIVER=fbcon prboom +or +SDL_VIDEODRIVER=svga prboom + +Details +------- + +Details on these extra features are split into separate text files: + +README.demos provides a guide to PrBoom's demo support +README.compatibility describes PrBoom's various compatibility + options and modes +README.command-line gives a command line reference for prboom, + prboom-game-server, and the format of boom.cfg. + On UNIX/Linux systems use the man pages instead. + +Editing features are not covered in the docs with this package. We plan +to bundle the editing docs as a separate download. Watch our website +for news. + diff --git a/TODO b/TODO new file mode 100644 index 0000000..51474b0 --- /dev/null +++ b/TODO @@ -0,0 +1,1495 @@ +Entrys marked by a * are fixed. + +-------------------------------------------------------------------------- +33. (2000/12/24) Single key quit + +Colin: opulent wants the old 'q quits demo recording' feature back. + I suggest making it a configurable key setting, not bound to any + key by default. +Proff: For 2.2.4? + +-------------------------------------------------------------------------- +34. (2002/07/28) Fix documentation + +Proff: +- add mp3 stuff +- add new opengl options +- update FAQ? + +-------------------------------------------------------------------------- +*35. (2002/07/28) Fix OpenGL segfault on Linux + +Proff: +Possibly caused by using gluImageScale when paletted textures used. +Either write my own scaling functions, which would allow mipmapping +for paletted textures, or just kick the scaling. I'm for the first +if I get the time. Small fix would be disabling gluImageScale when +paletted textures used. +Proff: Will hopefully be fixed in 2.3.x + +-------------------------------------------------------------------------- +*36. (2002/07/28) Add option to move backward with second mousebutton + +Proff: like it was in my old prboom version +Proff: 2.3.x + +-------------------------------------------------------------------------- + +List of revisions from PrBoom 2.3: + +[!] - cph needs to check +[+] - already merged +[ ] - empty or not wanted +[-] - interesting but not merged yet + ++ r597 | Add player number to spawn as a parameter to P_SpawnPlayer, repl ++ r598 | Improved P_InterceptVector that isn't subject to overflows Remov ++ r599 | Check whether usleep(3) is supported, and fall back on select(2) ++ r602 | Changed long long to int_64_t. +- r603 | Added chasecam patch and fixed long long problems. Worked withou + Chasecam +- r604 | Added p_chase.* + Chasecam + r605 | Support saving games at all compat levels - this will be necessa ++ r606 | Linux byteorder.h macros are unsigned, so we must force them to + r607 | Linux byteorder.h macros are unsigned, so we must force them to +- r608 | Nice catch Quasar` - fix sprite clipping for cameras in underwat + Chasecam + r609 | Minor fix + r610 | General cleanup of EV_BuildStairs Fix scanning for multiple stai + r611 | Separate demo sync stuff into its own section Add Final Doom tel + r612 | Fix dropoff flag for Boom demos + r613 | Fix D_DoomExeDir. Win2000 and possibly others don't report the f ++ r614 | Fix D_DoomExeDir. Win2000 and possibly others don't report the f + r615 | Bump version number + r616 | Merge rewritten R_DrawSpan from the dev tree + r617 | Final demo support refinements, inc. -complevel (which was docum + r618 | Include spec file in the tarball, and build RPM with -ta + r619 | From the 2.3.x tree: Cleaned up sound code. I_StartSound gets ch + r620 | Bump version number. + r621 | Various things for 2.2.2 + r622 | Update with WAD generated from the dev tree, no v1.2 compat save + r623 | Imported doublebuffering and fullscreen toggle from dev tree. + r624 | Put samplerate a little bit down, because when timidity is used + r625 | Update boom.cfg.5 with new video options, from Proff Man page fi + r626 | This commit was manufactured by cvs2svn to create tag 'prboom_2_ + r627 | Released 2.2.2 ++ r628 | comp_stairs fix and EV_BuildStairs cleanup from stable branch ++ r629 | Boom dropoff compat fix, from stable branch ++ r630 | *** empty log message *** ++ r631 | Merge newer version from stable branch Switch to %configure and ++ r632 | Very minor spacing fixes ++ r633 | Must distribute prboom.txt so the make can pass prboom.wad + r634 | Distros have caught up with us and are shipping SDL 1.2 now Clea + r635 | Fix typo ++ r636 | Rationalise the light level calcs for sprites and walls - new fu ++ r637 | SDL video corectness fix - use SDL_MUSTLOCK to determine if we h ++ r638 | We need malloc wrappers to do error handling etc; just go back t ++ r639 | New I_Read wrapper for read(2) - partial read handling - error h ++ r640 | Clear curline after use, so preventing R_ColourMap applying it t + r641 | New savegame format revision, save compat level in saves so we c ++ r642 | Get rid of the SIGPIPE handler - it's been unused since we switc ++ r643 | Merge in Proff's port of the BEX extensions from Eternity for mu ++ r644 | Fix some d_deh.c compile warnings Make lots of internal processi ++ r645 | Eliminate another static buffer in favour of doom_printf ++ r646 | Doom v1.2 did not animate 2s middle textures (cf levels/d-f/dmsp + r647 | We always compile with SDL_mixer these days, so drop all the ho + (will break Mac) ++ r648 | Clean up POSIX build process - remove obsolete stuff about no-ne ++ r649 | Clarify the base[xy]scale logic a bit, use correct global variab ++ r650 | Eliminate some redundant variables and calculations in R_StoreWa ++ r651 | Remove sprite{width,offset,topoffset}, these were just caches of + r652 | Fixed latest changes for Visual C++. + (not necessary) + r653 | Added the new menu code from SMMU. + (we don't want the new menu code) + r654 | HEADER_SIZE must be derived from sizeof(memblock_t), which can b + r655 | Fix typo causing keypad 5 to map to PAD0 ++ r656 | Fix keypad 5 Use SDL_SetPalette (SDL1.2 feature which allows us + r657 | Update POSIX Makefile for new menu system files Remove obsoleted + (the useful stuff is already in) + r658 | Fix running with no existing config file (but the currently comm + (g_bind is not used) + r659 | Removed unused I_ConTextAttr. + r660 | I'm stupid or somewhat, I_ConTextAttr IS used. I should check th ++ r661 | For consistency, keep all linked thinkers on a class list - have ++ r662 | Remove duplicate extern for thinkercap from doomstat.h Move comm ++ r663 | Remove old Linux joystick code + r667 | Move config file stuff to g_config.c Split out code for specific + (g_config) + r668 | Added g_config to VisualC project files. + (g_config) + r669 | Added g_config.h. + (g_config) ++ r670 | Minor cleanup + r671 | Makefile change for g_config.[ch], which I forgot to commit yest + (g_config) + r672 | This commit was manufactured by cvs2svn to create branch 'axes_s + r673 | Robert Sherwood's axes patch + r674 | G_SaveDefaults callback set up only after G_LoadDefaults done Ad ++ r675 | Removed Dreamcast stuff which doesn't belong here. + r676 | Updated Dreamcast stuff (some bugs left). + (Dreamcast) + r677 | Updated/cleaned up Dreamcast stuff (some bugs left). Fixed some + (Dreamcast) + r678 | Updated/cleaned up Dreamcast stuff. Works now, the bugs weren't + (Dreamcast) + r679 | Added sound to Dreamcast version. + (Dreamcast) + r680 | Fixed tolower(*s++) bug. + (Binding/Console) + r681 | Fixed D_DoomExeDir for Dreamcast. + (Dreamcast) + r682 | Added keyboard support for Dreamcast. + (Dreamcast) + r683 | From rsherwood: Axes now scale against the appropriate values (i + r684 | Added "Installation From CVS" (Steven Elliott). ++ r685 | Added "Installation From CVS" (Steven Elliott). + (was already merged) + r686 | P_SpawnPlayer must only be called with mthing_t's from the playe ++ r687 | On the right branch this time, merge the fix for my player start + (was already merged) + 688-707 + r708 | Updated. + (TODO) ++ r709 | Intermission screen demo sync bug fixed Also fix a possible time + (was already merged) + r710 | Added additional check for extensions. + r711 | Fix for compiling prboom_server on windows. ++ r712 | Fixed some z_zone related problems. + (was already merged) ++ r713 | Fix WAD bugs that can cause crashes even in demo compatibility m + (was already merged) + r714 | New config file name prboom.config for both GL and non-GL versio + (new config format) ++ r715 | Pull forward fixes from stable tree: Fix numeric keypad. Kill th + (was already merged) ++ r716 | Another fix fromt he stable branch: Fix fastparm and respawnparm + (was already merged) + r717 | HEADER_SIZE must be derived from sizeof(memblock_t), which can b + r718 | Crop some old bits Update on progress Add comp_sound idea + r719 | Update some email addresses + r720 | *** empty log message *** + r721 | Correct compatibility levels comment + r722 | Import items from 2.2.2 and 2.2.3 + r723 | pedantic html fix + r724 | Add super shotgun/A_CheckReload fix. ++ r725 | Fix file handle leak in R_InitTranMap when called before WADs lo ++ r726 | Make A_CheckReload actually work. Compatibility optioned for old + (was already merged) + r727 | Fix typo. ++ r728 | Some patches from selliot to improve handling of missing monster ++ r729 | Make M_ReadFile return -1 on error, so we can distniguish an emp + (parts were missing) ++ r730 | LOL, backslash escaping, what was I thinking, the windows users + (was already merged) +- r731 | Initialise gamestate so it's not GS_LEVEL. This stops a SEGV if + (Chasecam) +- r732 | Merged in the axes stuff. It's a more general replacement of the + (Generalise axes handling for input devices) ++ r733 | Clear player mobj's at level end - they're allocated PU_LEVEL so ++ r734 | Add back in horrible kludge used in 2.2.x to stop desyncs in the + (was already merged) + r735 | i_joy.c is gone ++ r736 | Removed now unused X11 and OSS. ++ r737 | New comp_sound compatibility option: - player only ever hears th + (was already merged) + r738 | *** empty log message *** + r739 | Updated. ++ r740 | Moved D_DoomExeDir and FindWADFile to i_system. Renamed to I_Doo + (cleaned up) ++ r741 | -forceoldbsp is valid for non-GL builds + (was already merged) ++ r742 | Fix comp_skymap. Looks like I just overlooked this one when I di + (was already merged) ++ r743 | Added the MP3 loading. MP3 will only be loaded if the music lump + (was already merged) + r744 | Load default config from a wad if config file not found. + (new config format) + r745 | Strings in menuitem_t will be const + r746 | Add the latest new compatibility levels. + (console) + r747 | Enable gamma correction with new config system. + (console) + r748 | Extension usage from 2.2.x. + (from 2.2) +- r749 | Save sensitivity settings. + (axes) + r750 | Small fix for keybinding names. + (binding) + r751 | Credits. + (new menu stuff) + r752 | Fix version strings. + r753 | Updated. + r754 | Hopefully fix some Linux/NVidia problems. + r755 | *** empty log message *** + r756 | Minor corrections + r757 | More corrections + r758 | Another HTML fix. + r759 | Move ssg fix to the right section. + r760 | Add DivlineSide coord-swapping bug. Add more info on p_sight.c d ++ r761 | Fix swapped coord in LOS calcs involving east-west walls (this + (from 2.2) ++ r762 | Auto-fix WAD bug where 1S line uses negative sidedef number othe + r763 | Add back screenshot capability. + (menu) + r764 | Eliminate tmthing, redundant. Save tmx & tmy over P_CreateSecNod ++ r765 | Remove tmflags, redundant. Preserve tmx & tmy over calls to P_Cr + (was already merged) + r766 | Revised P_CreateSecNodeList details. ++ r767 | Added fix for 800x600 bug by John Popplewell, but currently put + r768 | Enabled fix for 800x600 bug by John Popplewell. Finetuned the va + (skipped, related to previous) + r769 | Removed debug hack. + r770 | Added statusbar console variables. Worked a little bit on the me + (menu, console) + r771 | Added hud and cheat console variables. Worked a little bit on th ++ r772 | Better invulnerability drawing for normal OpenGL (not paletted). + (2.2) +- r773 | Added better dynamic OpenGL loader (Linux makefiles need updates + (Dynamic OpenGL) +- r774 | Tried fixing release bug in tesselator. Not sucessful yet. + (Tesselator) + r775 | Sorting config file output (Lucas Pope). + (config) + r776 | Small bugfix for VC7. isprint doesn't like anything above 255 (L + (binding) + r777 | Disabling gluTesselator till it's fixed. + (Tesselator) +- r778 | New and unified software rendering by Lucas Pope. This adds 16 a + (renderer) + r779 | Accidently added this in the last update. This is the new sound +- r780 | Added fix for 800x600 bug by John Popplewell which wasn't in the + (renderer) +- r781 | Unified patch rendering (filtering etc) (Lucas Pope). + (renderer) + r782 | Added more console commands. + (console) + r783 | Added more console commands. Fixed OpenGL mode. + (console) +- r784 | Implemented on the fly video mode changing (8,16,32 bit). + (renderer) + r785 | updated + r786 | added s_samplerate console var + (console) + r787 | enclosed the signal handlers with #ifndef _DEBUG + r788 | small comment change + (binding) +- r789 | added the RDRAW_FILTER_ROUNDED filter method that combines the s + (renderer) +- r790 | added RDRAW_FILTER_ROUNDED support + (renderer) + r791 | Reverted back to old sound code, due to some problems. +- r792 | fixed V_PlotPatch clipping, still not perfect, but better. also + (renderer) +- r793 | added bufferWidth/Height and convertToBGRA parameters for the V_ + (renderer) +- r794 | Fixed some bugs in the V_GetPlotted* function family. + (renderer) +- r795 | just some small little fixes + (renderer) +- r796 | Using new V_GetPlotted functions for the OpenGL texture generati + (renderer) +- r797 | Fix include filename case for compilation on Linux + (renderer) +- r798 | __cdecl presumably only needed on Win32; not available with gcc + (renderer) +- r799 | Case sensitive filename fixes + (renderer) +- r800 | Removed __cdecl. + (renderer) + r801 | showMessages now defaults to on. + (console) +- r802 | Fixed OpenGL/Software clash. + (renderer) +- r803 | Made OpenGL library name configurable. Added dynamic screen reso + (renderer) +- r804 | Removed test code. + (renderer) +- r805 | Moved DrawLine from am_map to v_video. Added all wrappers for Op + (renderer) +- r806 | Fixed resizing in windowed mode. + (renderer) +- r807 | Fixed warnings about different const modifier. Added small check + (renderer) +- r808 | Fixed some bugs (release version now works). Touched the memory + (renderer) + r809 | String const fix + (console) + r810 | Minor fixes + (menu) +- r811 | Removed all references to V_DrawMemPatch. + (renderer) + r812 | More const fixes. + (console) +- r813 | Screenshot is now a video system function. + (renderer) +- r814 | Removed GL_DOOM. + (renderer) +- r815 | Removed all remaining GL_DOOMs before full unification. + (renderer) +- r816 | Unified software and OpenGL into one executable. Nothing changed + (renderer) ++ r817 | cleaned up the PAUSE patch rendering ++ r818 | fixed a major bug that caused any deh patch that modified a mons + (was already merged) + r819 | Made slowturntics variable. + (console) + r820 | Merge "time" portability fix fom dev branch (wi_stuff.c:1.6->1.7 + r821 | Bump version numbers Add link to HP-UX compilation instructions +- r822 | Fix inlining, min/max macros for gcc + (renderer) + r823 | Add gl_dyn.c, r_filter.h +- r824 | new TPatch format, VIDD integration, many fixed video issues + (renderer) +- r825 | new TPatch format, VIDD integration + (renderer) +- r826 | Fixed OpenGL calls to the new patch functions. Updated VisualC++ + (renderer) +- r827 | Newlines at EOF to passify gcc. + (renderer) ++ r828 | Remove duplicate BuildBEXTables (well spotted, Quasar`). + (was already merged) +- r829 | Add r_patch.c. + (renderer) + r830 | BEX-equivalent strings output should have spaces around the = ( ++ r831 | BEX-equivalent strings output should have spaces around the = ( + (was already merged) +- r832 | Removed debug code. + (renderer) +- r833 | More error checking. + (renderer) +- r834 | Some code reorganisation. Added infinitePerspective which replac + (renderer) + r835 | Some code reorganisation. + r836 | Don't use paletted textures as default. + r837 | backported from 2.3.x: fixed a major bug that caused any deh pat +- r838 | Removed glu tesselation code, as it doesn't work properly and is + (renderer) + r839 | Don't use paletted textures as default. + r840 | Backported better invulnerability drawing for normal OpenGL (not + r841 | Removed glu tesselation code, as it doesn't work properly and is + r842 | Updated. + r843 | Bumped version number. + r844 | Commit Mead's/my countable item automap highlighting. + r845 | Fix SEGV on failed lookup for BEX codepointer. + r846 | Always rangecheck patch drawing to the framebuffer, we have no g + r847 | Respawn frame bug "reported" on DW forums by Graf Zahl. + r848 | Don't treat linedef types in the 0x8000-0xffff range as generali + r849 | Fix DEH_MOBJINFOMAX. + r850 | Removed need for far clipping plane. + r851 | Updated and added some details. + r852 | Added some stuff from 2.2.x. + r853 | Update and cleanup. + r854 | Clean up some code indenting. + r855 | Split visplane duplication into new function. Fix sky-over-sky H ++ r856 | From prboom_stable_2_2: Split visplane duplication into new func + (2.2) + r857 | Updated. + r858 | Fix erroneous extra shot noise when chaingun runs out of ammFix ++ r859 | Fix chaingun bullet-noise-after-last-bullet bug. + (was already merged) + r860 | Compatibility option the chaingun sound fix (Bahdko made me, hon + r861 | Add chaingun extra shot sound fix. HTML cleanups. Obscure email + r862 | Obscure email addresses against spam harvesting. + r863 | Another email link obscured. + r864 | Fix for crash when trying to load empty slot. + (menu) + r865 | Removed $Id: $ lines. This is for the future switch to subversio + r866 | Removed $Id: $ lines. This is for the future switch to subversio + r867 | Wow, I totally messed up the last checkin. At all places where a + r868 | Wow, I totally messed up the last checkin. At all places where a + r869 | Fixed compiling of prboom_server. + r870 | Wow, I totally messed up the last checkin. At all places where a +- r871 | Fixed double dcvars.translation mapping in 16 and 32 bit. + (renderer) +- r872 | Fixed tranlation mapping for rounding filter in 8 bit. + (renderer) + r873 | Added r_patchfilter and r_patchslope console variables. + (console) +- r874 | Patch drawing defaults to point filter and square borders as thi + (renderer) + r875 | Fix crash when doing timedemo from the menu. + (menu) +- r876 | Added translucent patch drawing (used in video settings menu). + (renderer) +- r877 | Added more menu graphics from smmu. + (menu graphics) + r878 | Added r_homflash console command. + (console) + r879 | Use smaller slider graphics from smmu. Boolean values are switch + (menu) + r880 | Output of lprintf now also goes to console. + (console) + r881 | Added names for keypad keys. + (binding) +- r882 | Renamed r_videomode to r_rendermode. The r_width, r_height and r + (rendering) + r883 | Video settings menu is much more complete (OpenGL stuff missing) + (menu) + r884 | Updated. ++ r885 | Made I_SoundInit callable more that once. + r886 | The snd_samplerate command is toggleable and only allows values + (console) + r887 | Fixed sound menu. + (menu) + r888 | Added use_mouse console variable. + (console) + r889 | Fixed compilation warning related to defdemoname. Made G_Compati + (console) + r890 | Moved default_compatibility_level and compatibility_level consol + (console) + r891 | Some small changes. Split up compatibility into two pages. + (menu) + r892 | Added p_cmd.c and made small related changes. This adds monster + (console) + r893 | Removed cvs log. + r894 | Removed non OpenGL versions. +- r895 | Added OpenGL console commands. Added OpenGL settings to video me + (renderer) +- r896 | Added ViddSys. Added viddsys project for VisualC6. Enabled vidd + (VIDD) + r897 | Added some stuff. + r898 | Removed unused stuff. + (console) + r899 | Reworked the menus a bit. Disabled some non working stuff for no + (menu) + r900 | Moved demo stuff from g_game to g_demo. + (g_demo) +- r901 | Implemented iwad console command for on the fly iwad switching. + (IWAD switching) +- r902 | Documentation for vidd. + (VIDD) + r903 | Fix drawing when console is fullscreen. + (console) + r904 | Added C_RunTextCmdf. Added c_addcommand_stats console command wh + (console) + r905 | Changed to use C_RunTextCmdf. + (menu) + r906 | Added iwad selection in "features->load wad". + (menu) +- r907 | Changed iwad from console command to console string and prevent + (IWAD switching) + r908 | Using g_iwad (from iwad console string) for default iwad when no + (IWAD switching, menu) +- r909 | Sound functions take const mobj_t * instead of void * for locati + (VIDD) + r910 | Moved includes bacuase of some changes in the header files. +- r911 | Sound functions take const mobj_t * instead of void * for locati + (IWAD switching) + r912 | Added c_net from smmu. + (net from smmu) + r913 | Added fraggle script files from smmu, but didn't integrate it in + (fraggle script) +- r914 | Made wall and floor filters seperatly selectable (to allow round + (renderer) +- r915 | Added Lucas Pope to credits. + (renderer) + r916 | Several small changes to let fraggle script stuff compile. Added + (fraggle script) + r917 | Added fraggle script files. Moved some files into project subfol + (fraggle script) +- r918 | Three font graphics from SMMU added. + (font graphics) +- r919 | Merging more stuff from SMMU: v_misc added and moved font handli + (font handling - better get it from Eternity) +- r920 | Using the new V_Text* functions here instead of implementing ess + (font handling) + r921 | Removed unused externs. + r922 | Some cleanup. Using V_IsPrint to check if char is printable. Add + (console) +- r923 | Initialize the font in v_misc. + (font handling) + r924 | For iwad switching: Initialize patches (R_Init) before any call + r925 | Definitions for silentmove sector flags. + r926 | Added totalfrags in preparation for the coming smmu hud code. + (smmu hud) + r927 | Added lightlevel_t. Added prototypes for new functions from smmu + (fraggle script) + r928 | Fixed type cast compiler warnings. + (fraggle script) + r929 | Using the recently added V_DrawBox function. + (menu) + r930 | Prevent adding a command twice, as this causes an endless loop l + (console) +- r931 | Typecast to prevent warning. + (renderer) + r932 | Added linedefs for scripting from smmu. + (fraggle script) + r933 | Last log entry is wrong. This added silentmove. + (fraggle script) +- r934 | Adding silentmove and using plat_up, plat_stop and palt_down con + (some constants) +- r935 | Added T_LightFade and P_FadeLight from smmu. + (P_FadeLight) + r936 | Enabled T_AddCommands and V_AddCommands. Some moving around of * + (console) + r937 | New hud from smmu with some small related changes. The fullscree + (HUD) + r938 | Removed cvs log. +- r939 | Removed message from player_t, use doom_printf or player_printf + (Removed message from player_t, use doom_printf or player_printf instead) +- r940 | Fix chasecam when teleporting. + (chasecam) +- r941 | Added r_blockmap. + (blockmap) +- r942 | Some code cleanups and documentation fixes. Very small changes f + (several changes) +- r943 | Enabled V_FPSDrawer: + (FPS drawer) + r944 | Added and enabled more smmu stuff. + (smmu) +- r945 | Fixed V_WriteTextXYGapFont call from using v_font to supplied fo + (font) + r946 | Small cleanups and added some variables from smmu. +- r947 | prboom.wad now loaded together with iwad. Using IndentifyVersion + (IWAD switching) + r948 | Added deh_loaded variable from smmu. + (console) + r949 | gravity is now a variable. + (gravity variable) + r950 | Renamed G_DeferedInitNew to G_DeferedInitNewNum and G_InitNew to + (hubs) + r951 | Moved G_Ticker to the end of the file. + r952 | Added p_info and p_hubs from smmu. + (hubs) + r953 | Some definitions (intermission camera related) and the barest mi + (intermission camera) + r954 | Check if soundfx is enabled in S_StopSounds to fix crash. + r955 | Moved "extern int screenblocks;" to r_main.h + r956 | Removed now unused extern int key_* definitions. Added G_Scrambl +- r957 | Print errors to console instead of calling I_Error. + (renderer) + r958 | Put code from g_game (G_DoLoadLevel) to init the sky texture nam + (smmu) + r959 | More things from smmu in P_SetupLevel. + (smmu) + r960 | Removed unused key_* definitions. Moved key_map_* definitions to +- r961 | Z_PrintStats is Z_DrawStats now and called from HU_Drawer. It's + (font) + r962 | MAXLOADWADS now 2 again, cause prboom is implicitely loaded. +- r963 | bodyqueue fix from mbf. + (bodyqueue) + r964 | New sound code from smmu. + (smmu - sound) + r965 | Reenabled quit sounds. Added i_endoom_delay to change delay when +- r966 | Small changes and additions from smmu. + (chasecam) + r967 | P_SetupLevel and G_InitNew take a levelname instead of gameepiso + (smmu) + r968 | Added death messages from smmu. + (smmu) + r969 | Bump version number for autoconf. + r970 | Sprite offsets must be flipped for flipped sprites. Thanks to fr + r971 | Further improve the P_CreateSecNodeList global variable cleanups + r972 | Fix endianness issues in tic field of network packets. Should be + r973 | cf http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=174541 Remov + r974 | Get line lengths right in README.command-line + r975 | Added more intermission code from smmu. Made some functions stat + (smmu) + r976 | Added use_startmap and startlevel. Added functions for dynamic w + (smmu) + r977 | Enabled some smmu stuff which didn't work before. + (smmu) + r978 | Removed ChangeLog as it's generated. + r979 | Reintroduce -nomouse option; essential for debugging. + r980 | Add comp_sound stuff, backported from the development version. + r981 | Set compatiility options correctly in netgames in old compatibil + r982 | Add support to network game server for reading config files. It + r983 | Added explanation for AM_PATH_SDL problem to compile from cvs se + r984 | Added explanation for AM_PATH_SDL problem to compile from cvs se + r985 | Added correct eol property. + r986 | Added correct eol property. + r987 | Fixed Makefile.am. Small posix related fixes. + r988 | Added Visual Studio .NET project files. + r989 | Added tab before each line of files. + r990 | More Makefile and posix fixes. + r991 | Posix fixes for OpenGL. Now always compiled in, as there are no + r992 | Makefiles are weird. Replaced tabs with spaces in file list. + r993 | Added VISUALCNET to distribution. + r994 | Added inl and vidd directorys to makefiles. + r995 | Fix end of line. + r996 | Fix case. + r997 | Fix case. + r998 | Added src/inl/Makefile and src/vidd/Makefile. + r999 | Fix end of line. + r1000 | Removed trailing slashes in I_DoomExeDir. + r1001 | Moved includes from gl_intern.h to gl_main.c and gl_texture.c. P + r1002 | Remove ChangeLog from distribution tarball - we don't have one. + r1003 | Remove readme.txt from distribution, as it is not in the reposit + r1004 | Sanity checking for netcmd numbers. Add more entries to netcmd e + (console, net) +- r1005 | Endian fixes. + (renderer) + r1006 | Removed PFNGLCOLORTABLEEXTPROC definition and added FAQ entry. + r1007 | Added GL_DOOM define. +- r1008 | More endian fixes. + (renderer) + r1009 | Reorder comp_sound to match 2.2.4. ++ r1010 | Import fixes from stable tree, revisions 823,825,827: - Respawn + (2.2) ++ r1011 | Port forward fraggle's sprite offset flipping fix. Clean up and + (sprite clipping fix) ++ r1012 | Port forward the fix for global variable overwriting (tmbbox) in + (2.2) + r1013 | New address for Barry Mead. + r1014 | Fix non-GL_Doom compilation. + r1015 | Allow s_sound.c to specify volume with greater precision. This a + r1016 | Work around defect in SDLNet_UDP_Bind channel support. + r1017 | Add a feedback mechanism to keep clients more accurately synchro + r1018 | Upadte email address and download address. + r1019 | Remove direct smpeg dependency - it should be pulled in automati + r1020 | Remove debugging accidentally committed yesterday, and update NE + r1021 | Add weapon pickup sounds, sprite flipping, and updated p_map.c f + r1022 | Protect another email address. + r1023 | Hide another email. + r1024 | Update for 2.2.4 release. ++ r1025 | Bring forward generalised line range fix from 2.2.x branch. + (2.2) + r1026 | Fix xtratics - it was generating negative tic #s and the server + r1027 | Added Makefile.am for extra files in generated tar. + r1028 | Tag the 2.2.4 release. + r1029 | Added more missing files to the Makefiles. + r1030 | Added missing GenEnd. ++ r1031 | Updates to spec file (from 2.2.4). + (2.2) ++ r1032 | Do not link smpeg (ported from 2.2.4). + (2.2) ++ r1033 | From 2.2.4, less strict automake checks. + (2.2) ++ r1034 | Port back-off support from 2.2.4. Port endianness fixes from 2.2 + (2.2) ++ r1035 | As in 2.2.4, removed ChangeLog. + (2.2) ++ r1036 | Improve accuracy of sound calculations (sound range fix ported f + (2.2) ++ r1037 | Update NEWS with final 2.2.4 list. + (2.2) + r1038 | Tagging PrBoom 2.3.0 + r1039 | PrBoom 2.3.0 released. + r1040 | Explain a bit that this is a rough'n'ready beta release. Solicit + r1041 | Windows release was bad. + r1042 | Some feedback. + r1043 | Updated. + r1044 | Correct the off-screen checking in HUlib_drawTextLine. This stop + r1045 | Bumped version number. + r1046 | Fix config.h for Windows. All references to "../config.h" were r + r1047 | Fix eol. + r1048 | Report error if port bind failed. Sanity checking on player numb + r1049 | Load OpenGL libraries only when needed. +- r1050 | I think this description of the networking is worth saving. + (network explanation) + r1051 | Take screenshot - f12 Quit - f10 Gama correction - f11 + (config) + r1052 | Added autorun to menu. Updated todo. + (menu) + r1053 | Moved and added stuff for redesign. + r1054 | Forgot to rename. + r1055 | Mostly working like the old pages. I have to fix the tool first. + r1056 | With SimpleTAL 3.5, a small hack in pubtal and some small fixes + r1057 | Add navigation and reordered some things. + r1058 | Added hover effect for links. + r1059 | Added missing template. + r1060 | A very small readme on how to build the website. + r1061 | Nicer rollover effect. + r1062 | Fix eol. I finally found the option to prevent my editor from me + r1063 | Fix eol. I finally found the option to prevent my editor from me +- r1064 | More endian fixes. Now it works on big endian systems as far as + (renderer) + r1065 | Fixed ignore-filter. + r1066 | Not needed anymore. ++ r1067 | Obvious bug in my attempts to fix the T_VerticalDoor corruption + (2.2) + r1068 | Fix overzealous safety check added in last update. + r1069 | If server is closed before game start, exit the client too. + r1070 | We should call D_QuitNetGame for any client exit after the serve + r1071 | Better management of players joining and quitting during startup + r1072 | Demo players are after this: total live monsters count in the HU + r1073 | Set savegame root. + r1074 | fake_contrast should be on by default (used to be on but configu + r1075 | Bump version number. + r1076 | Marked hub and script related stuff with ifdefs. + (hub) +- r1077 | Fixed textcolours array, this caused segfaults. + (font) +- r1078 | Fix prboom.wad not found [Patch 949349]. + (IWAD switching) +- r1079 | Fix texture pegging for upper textures [Patch 897801] [Bug 59999 + (renderer) + r1080 | Set svn:eol-style property. + r1081 | Set svn:eol-style property. + r1082 | Make line_t junk static in A_LineEffect. ++ r1083 | Make line_t junk static in A_LineEffect [Bug 946686]. + (2.2) + r1084 | Fix for new GCC warnings. +- r1085 | Wrap extremely long lines. + (renderer) + r1086 | Fix Bug #845129. Filenames with dots didn't work properly (and s +- r1087 | Fixed Bug #929248. Buffer overflow in F_TextWrite. + (font) + r1088 | Added SDLK_CARET as console key. + r1089 | Fix compilation. +- r1090 | (Partly) fix bug #851055. (Re)implemented multipatch textures. D + (renderer) +- r1091 | Fix bug #810700. It was some rounding error introduced with the + (renderer) +- r1092 | Limit the posts of a patch to the limits of the texture. As a si + (renderer) +- r1093 | Removed some unused code. I think this got obsolete with the new + (renderer) + r1094 | Added an ifdef USE_ULL_SUFFIX. This should be added with a test + r1095 | Fix bug #826682. Unavailable IWADs get disabled. + (menu, iwad switching) + r1096 | Fix savegames (Bug #896092). + (smmu savegames) +- r1097 | Fix multiple-patches-on-one-column textures (Bug #851055). + (renderer) + r1098 | Bump version number. + r1099 | Load OpenGL library only once. + r1100 | Fix bug #926548 and enhance widgets with the possibility to choo + (hud) + r1101 | Fix bug #810562. Bounded keys weren't checked when playing demo. + (binding) + r1102 | Tried to achive savegame compatibility with 2.2.x, but failed. T + (smmu savegame) + r1103 | Update email address. + r1104 | Use SDL_MUSTLOCK to determine whether si render direct to buffer + r1105 | Bump version number. + r1106 | A few minor fixes so far. + r1107 | Fix --enable-dogs + r1108 | Cheatcodes didn't work anymore and this change wasn't necessary + (binding) + r1109 | Updated. +- r1110 | Removed W_UnlockLump* calls made obsolte by the new renderer. + (renderer) + r1111 | Added a sanity check to prevent problems. + r1112 | Prevent compiler warning. + r1113 | Fix position of automap text widgets when using high-res. + (hud) + r1114 | Added devparm as console command. + (console) +- r1115 | Made R_GetTextureColumn simpler by using the new R_GetTextureCom + (renderer) +- r1116 | Added missing R_GetTextureColumn call for dcvars.prevcolumn. + (renderer) +- r1117 | Use user pointer on Z_Malloc. + (renderer) +- r1118 | Use normal malloc instead of Z_Malloc. + (renderer) + r1119 | Fix compiler warnings and a weird compiler error in Visual Studi + (VIDD) + r1120 | Updated to Visual Studio .NET 2003. + r1121 | Added test for ULL number suffix. + r1122 | Import r418 from trunk: Simplify event handling, logic is all in + r1123 | Update for new dmalloc API. + r1124 | Import r1115 from trunk, fixing dmalloc support. More consistent + r1125 | Merge r941 from trunk (plus Lee's comments from MBF): bodyqueue + r1126 | Import r707 from trunk, for bug #592350: Use M_ReadFile for Find + r1127 | Import r417 from trunk: No need for screenshot to be a gameactio +- r1128 | Fix texture offset when using linear filter in software mode. + (renderer) +- r1129 | Fixed bug #834202. Translucency setting wasn't saved. Patches ar + (renderer) + r1130 | Fixed several compiler warnings. + r1131 | Import r514 from trunk: Better inline asm from Eternity. + r1132 | Fast forward to given map # in demo playback. + r1133 | Fix desync caused by timing differences in intermission screen w ++ r1134 | Intermission screen desync on secrets counter. for e.g. 30cn3519 + (2.2) + r1135 | Another demo sync fix for Boom. + r1136 | monkeys, traditional_menu, sts_always_red and weapon_recoil set + r1137 | Import r712 from trunk (needed to complement r418 imported yeste +- r1138 | Imported new colour translation code from SMMU/Eternity. + (renderer) + r1139 | Fixed a few warnings. Let z_zone.c compile on windows. Add defau + r1140 | Import r708 from trunk, needed to complement r707 imported yeste + r1141 | Ripped out tranmap caching. +- r1142 | Don't initialise sound before I_Init(). + (init sound) + r1143 | Import 2.3.x prboom.wad. + r1144 | Blazing door hitting an obstacle should make a blazing door soun +- r1145 | Blazing door closing and hitting something should make a blazing + (blazing door sound) ++ r1146 | Live monster counter for HUD, imported from stable_2.2 r1064. + (2.2) + r1147 | Another blazing door noise bug. ++ r1148 | The new simplified z_zone implementation. It's just a wrapper ar + (z_zone) + r1149 | #include "z_zone.h", for malloc. ++ r1150 | Clear tmthing after each tic - could be referencing a freed obje + (z_zone) ++ r1151 | Demo fast forward to given map #, from stable_2.2. + (2.2) + r1152 | Fix autoconf warning. ++ r1153 | Live monster counter now worksa with archville resurrections. + (2.2) + r1154 | Live monster counter now counts archville resurrections. ++ r1155 | Fix r1142: need p_map.h for P_Map*. + (z_zone) + r1156 | Fix a possible SEGV due to tmthing holding a dangling pointer if +- r1157 | Made patches and texture composites of the new software renderer + (renderer) ++ r1158 | Added memory_size variable, which is the threshold at which purg + (z_zone) ++ r1159 | Fixed long standing backspace printing bug on windows. + (was already merged) + r1160 | Fixed long standing backspace printing bug on windows. ++ r1161 | Fixed missing 0 at end of string. + (was already merged) + r1162 | Fixed missing 0 at end of string. + r1163 | Add \n when printing HUD messages to console. + (console) ++ r1164 | Fixed rather big memory leak. + (was already merged) + r1165 | Fixed rather big memory leak. +- r1166 | Set edgeSloping when combining posts. + (renderer) + r1167 | Fixed config for new PubTal. Changed CSS a little bit. + r1168 | Generalised doors now make sounds appropriate to their speed. Th +- r1169 | Fix sounds based on speed of generalised doors. Fix comp_sound i + (sounds) +- r1170 | More original Doom like default settings. + (default settings) + r1171 | Padding for short REJECT lumps (fixes rq22-318.lmp and probably + r1172 | Make it possible to abort network checking on windows. +- r1173 | Make it possible to abort network checking on windows. + (networking on windows) +- r1174 | Completely removed G_ChangedPlayerColour. + (G_ChangedPlayerColor) +- r1175 | Added portable snprintf. Compile with warnings as errors on wind + (psnprintf) +- r1176 | Made some buffers bigger, so they will not overrun. + (buffers) +- r1177 | Small enhancements and bugfixes from Eternity. Fix indentation. + (renderer) + r1178 | Removed limit on aliases (from Eternity). Small enhancements and + (console) +- r1179 | Unify V_WriteText* and V_StringWidth* functions. + (font) + r1180 | Small enhancements and bugfixes from Eternity. Fix indentation. + (console) + r1181 | Fix compilation with gcc 3.4.x - inconsistency between header an + r1182 | Add calls to SMMU/Eternity net code. + (net) + r1183 | Fix dist target for newer autoconf. + r1184 | Enhanced Edition v1.9 demo support. + r1185 | Fix compilation of server. + (net) + r1186 | Implemented printing of tabs. ++ r1187 | Implemented printing of tabs. + (was already merged) + r1188 | Fix crash when player respawns in multiplayer due to new P_MapSt + r1189 | Small fix from Eternity. Small code cleanups. Fix compilation of + (net) +- r1190 | Fix bug #810566. Music stops playing after sound settings change + (sound) ++ r1191 | Fix player respawn crashes with new P_MapStart/End + (z_zone) + r1192 | Updated. + r1193 | Bug fixes from Eternity. Small code cleanups. Enabled some more + (smmu fixes from eternity) + r1194 | Bugfixes from Eternity. Small code cleanups. Enabled more stuff. + (smmu fixes from eternity) ++ r1195 | Renamed namespace to li_namespace. + (was already merged) ++ r1196 | Removed stealth monsters, they weren't supported in the renderer ++ r1197 | Ripped out the remaining stealth monster bits. The flags in p_mo + r1198 | Added psnprntf.* and m_fcvt.*. + r1199 | Added pastebin. + r1200 | Start level code also uses P_Map* and must be wrapped (else P_Ma ++ r1201 | Start level code also uses P_Map* and must be wrapped (else P_Ma + (2.2) + r1202 | Small changes to css. Moved passwords outside of pastebin.php. R +- r1203 | Don't use systems snprintf as replacement for psnprintf. + (psnprintf) +- r1204 | Use psnprintf instead of snprintf or sprintf. + (psnprintf) + r1205 | Fix for newer autoconf. +! r1206 | Fix prboom_3_compatibility savegames. + (savegame) ++ r1207 | Longtics/EE support ported from stable_2.2. + (2.2) + r1208 | doom2.exe only used the first 10 deathmatch starts. ++ r1209 | doom2.exe only used the first 10 deathmatch starts. + (was already merged) + r1210 | Transmit data for tic 0. This probably caused the first-tic desy + r1211 | Experimental proxy server between ipxsetup.exe's IPX networking + r1212 | Works now - fixed packet sizes and tic wrapping calcs. + r1213 | Make the backoff stronger, needed to need down the lag with doom + r1214 | Pack and pad the packet header struct, and ensure that the paddi + r1215 | Make demo noise a bit less intrusive. + r1216 | Prevent SEGV if server incorrectly give a bad consoleplayer numb + r1217 | Extra confirmation phase, to deal with clients that quit or lose + r1218 | MF_BLOCKMAP missing from Doom -> PrBoom flags conversion, and th + r1219 | non-SDL_net net code is gone. Remove makefile conditionals, as t + r1220 | Move GL_DOOM and COMPILE_VIDD from project settings to config.h. +- r1221 | Avoid crash when prboom.wad is not found. + (IWAD switching) +- r1222 | Avoid crash when the opengl extension string is too long. + (renderer) +- r1223 | Fix printing of opengl extension. The length was calculated inco + (renderer) ++ r1224 | Another fix for tabulators in the windows console window. + (was already merged) + r1225 | Backport of the fix for printing opengl extensions and the tabul + r1226 | Fix up .NET project files. + r1227 | updated. +- r1228 | Fix compilation of prboom_server. + (psnprintf) + r1229 | Fix compilation of prboom_server. + r1230 | EE got called v1.91 + r1231 | EE got called v1.91 ++ r1232 | Fix dehacked mobj bits conversion, cf r1218 from stable branch a + (was already merged) + r1233 | monster_backing off by default too. + r1234 | Fix my email address. + r1235 | Bring my email addresses up to date. + r1236 | PrBoom 2.2.5. + r1237 | PrBoom 2.3.0. + r1238 | Small fix to prevent unwanted newlines. + r1239 | Created tag for PrBoom 2.2.5. + r1240 | Bump version number. + r1241 | autoconf and rpm disagree about the use of an explicit platform + r1242 | Created tag for PrBoom 2.3.1. + r1243 | Bumped version number. + r1244 | Fix intermission screen splat/YaH code, which was crashing due t ++ r1245 | Fix off-screen you-are-here's on Inferno intermission screens. + (was already merged) +- r1246 | Don't play music when volume is 0. + (music volume 0) ++ r1247 | Fix fuzz drawing for hi-re. + (was already merged) + r1248 | Fix fuzz drawing for hi-re. +- r1249 | Fixed patch drawing with VPT_FLIP. + (renderer) + r1250 | updated. + r1251 | Fix hang when one network client exits. + r1252 | Update default server parameters to match the client. + r1253 | Fix some serious memory leaks. + r1254 | and news for the mem leak. + r1255 | Nicer diagnostics of player states. + r1256 | Fix NOSECTOR and NOBLOCKMAP effects in old dehacked patches. ++ r1257 | Fix nosector/noblockmap mixup. + (was already merged) + r1258 | and the NEWS item for the deh fix. +- r1259 | Set default netgame options the same as the default prboom.confi + (defaults) + r1260 | Fixed player spawn sound. ++ r1261 | Fixed player spawn sound. + (was already merged) + r1262 | Player reborn TFOG bug. +- r1263 | No oof sound on open 2S lines when comp_sound. + (sounds) ++ r1264 | Quick hack to enable network client to ride over temporary loss + (was already merged) + r1265 | Use g_game.h instead of redefining stuff. Backspace repeat. ++ r1266 | Bring into line with intended protocol, from stable branch. + (2.2) ++ r1267 | Bring slightly more into line with my work from 2.2.x. r1048+r10 + (was already merged) + r1268 | Created bundle folder remotely. + r1269 | Created bundle for prboom2. ++ r1270 | Make I_WaitForPacket more useful, have a timeout. + (2.2) + r1271 | Repeat init packet - it might get lost or server is slow startin ++ r1272 | fix last commit. + (was already merged) ++ r1273 | Return time to next tick. + (2.2) +- r1274 | Enable key repeat. + (key repeat) + r1275 | Remove unused consdata in ticcmd. + (console) + r1276 | Treat warnings as errors. + r1277 | Fix some warnings. + r1278 | Don't what I mean, not what I say :-). Don't call SDL_GetTicks t + r1279 | More intelligent timing in TryRunTics. + r1280 | Smarter delays in TryRunTics. Also, listen for network packets w + r1281 | Use packet_set for PKT_TICC. + r1282 | Shorter delay while waiting on packet, so windows users have the + r1283 | Fix tntem cheat. +- r1284 | Fix HOM detection drawing. + (renderer) +- r1309 | Fix bug [1046368] and patch [1199312]. + () +DONE! + +-------------------------------------------------------------------------- + +PrBoom-plus revisions since "Stuff to port from prboom-plus" + + + unexamined ++ done +% partially done +- of interest +? not sure +x not of interest + ! needs attention + ++ r2312 | fix of hanging decoration disappearing in Batman Doom MAP02 +? r2313 | comp[comp_oofsound] - done ++ r2319 | the global variable r_NoInterpolate is not necessary any more (s ++ r2320 | don't thrash cpu during pausing (should be applied to prboom) ++ r2321 | do nothing if a pause has been pressed during playback. pausing +x r2322 | "-auto" for autoloading of wads according to the lmp file-name +?! r2323 | correction of smart items clipping code: not a fully dead corpse +?! r2324 | heh, previous commiting was unsaved version.fixed +?! r2325 | there are three modes of sprite clipping in opengl: +?! r2326 | gl_sprite_offset moved to globals; things with MF_MISSILE should +?! r2327 | some comment changed ++ r2328 | fixed(?) cph's bug(?) introduced in r1431 ++ r2329 | fix for 2328. maybe better possible +x r2330 | bug with def_arr type (Z_Realloc do not fill additional region o ++ r2331 | comp_doorstuck should be forced for boom201 compatibility (at le +x r2332 | launcher ++ r2333 | cph's one more bug: The current behaviour with comp_666 is that ++ r2334 | Check for prevention of possible collisions between level of com ++ r2335 | revert to r2333 ++ r2336 | Additional check of gameepisode in A_BossDeath is added, because +?! r2337 | small fix for opengl, sky and mouselook +x r2338 | progress bar during demo playback works during skipping +x r2339 | minimization of distinctions with trunk +x r2341 | Merged r2304:2340 from trunk +- r2342 | Optional removal of a quit sound delay (it is old Prboom-Plus's +- r2344 | Improved support for Doom v1.2: +x r2345 | - the progress bar did not work correctly for demos with more th +x r2346 | Predefined translucency setting (comp_translucency) should not o +x r2347 | Prevention of division by zero in G_DoPlayDemo() if players coun ++ r2348 | Handling of unrecognized demo formats ++ r2349 | fix for r2348 (Doom v1.2 demos) ++ r2350 | comments +x r2351 | Files for -auto should be searched in all standard places: curre +x r2352 | Sometimes the figures for kills, items, etc., stop getting updat +? r2353 | warning C4018: '==' : signed/unsigned mismatch +x r2356 | to avoid conflicts prboom-plus.wad should be added with full pat +x r2357 | launcher +x r2358 | launcher again +x r2359 | launcher again again +x r2360 | added I_vWarning() function +? r2361 | I_FindFile: searching exe dir before current dir, check wfname a ++ r2362 | Better compatibility with boom v2.01. There are no more desync o ++ r2363 | fix for r2362 ++ r2364 | demover is global now. it's required for demos recorded in "demo ++ r2365 | Three separate definitions of max and min are moved in doomtype. +x r2366 | Compilation fixes: ++ r2367 | max, min are renamed to MAX, MIN to avoid all possible warnings ++ r2368 | removing unnecessary code (after r2367) +?! r2369 | spriteclip code shouldn't be applied to things with MF_NOGRAVITY +x r2370 | Removed files and folders with compiled pcre libs +x r2371 | pcre projects are added to main solution +? r2372 | New savegame format with continuous numbering. Now it is not nec +? r2373 | missed PACKAGEVERSION in VisualC6\config.h +? r2374 | ALL_IN_ONE define for having PrBoom-Plus.wad in the exe (win32 o +? r2375 | fix compilation +x r2376 | Merged r2340:2355 from trunk ++ r2377 | Fixed mbf_compatibility incompatibility. There is no more desync +x r2378 | Demo Progress Bar during skipping will be updated not more often +x r2380 | All-in-one doesn't find resource wad when using -auto ++ r2381 | "All boss types can trigger tag 666 at ExM8" -> "Emulate pre-Ult ++ r2382 | There is no more crashes on boom200 demos (wrongly header readin ++! r2383 | Animated middle textures with a zero index should be forced. +?! r2384 | New mouse code without SDL lags. Win32 mouse handling was remove ++ r2385 | non traditional menu was removed to avoid bugs with Alien Vendet +?! r2386 | New mouse code: Sounds as nonsense, but SDL mouse lags are depen +? r2387 | do not clear events queue at the start (like vanilla) +?! r2388 | some comments about new mouse code +?! r2389 | There is no more win32 specific code in new mouse code. Now it w +x r2390 | launcher: wrong strings in history combo +- r2391 | sound_noquitsound is renamed to misc_fastexit +?! r2392 | missed SDL_WM_GrabInput(SDL_GRAB_OFF) ++ r2393 | do not process mouse input in menu because it's buggy and annoyi +x r2394 | Merged r2355:2379 from trunk +% r2395 | fix some compilation problems on MAC and POSIX +?! r2396 | very small improvement ++ r2397 | Fixed Boom incompatibilities. There are no more desyncs on Donce ++ r2398 | Fixed Boom incompatibilities. Original friction and bobbing code +x r2399 | bump version to 2.4.8.2 +x r2400 | REJECT overflow cannot be emulated if the REJECT size is not div +x r2401 | Not used function (RejectOverrunAddInt) has been removed +?! r2402 | Boom's color maps are supported in OpenGL mode +?! r2403 | Boom's colormaps: some comments are added +?! r2404 | Effect of invulnerability uses a colormap instead of hard-coding +?! r2405 | comp[comp_skymap] works in OpenGL mode now; +x r2406 | "Paper Items" setting is not applied to hanging things. +x r2407 | always grab the mouse in camera mode when playing levels and men +- r2408 | [-] PrBoom bug: %DOOMWADDIR% had no effect for PWADs. +?! r2409 | Boom's colormaps in OpenGL: fix crash in gld_Precache +-! r2410 | New mus -> mid conversion code thanks to Ben Ryves lprintf in PCSOUND files + r2485 | bug introduced in r2482 - wrong indexes were used + r2486 | PrBoom bug: Par times are not shown + r2487 | Sometimes the pistol sounds that play while the tallies are bein + r2488 | Has made compatible my correction of par times (r2486) with "-au + r2489 | fix "-emulation" code + r2490 | let's show the warning if savegame is from the previous version + r2491 | has made dynamic changing of gamespeed more smooth + r2492 | "-force_lxdoom_demo_compatibility" comman-line switch for emulat + r2493 | On ExM8 of movie runs, the total time is often displayed wrong. + r2494 | -force_lxdoom_demo_compatibility: there are no more desynchs on + r2495 | The ultimate 'ATI sucks' fix: Some of ATIs graphics cards are so + r2496 | big comment for r2473: + r2497 | fix for demoprogressbar with veeeeeeery long demos on high resol + r2498 | fix compilation problems + r2499 | gl_render_precise variable for control of the new seamless code + r2500 | Move the window to the screen center if stupid SDL create it in + r2501 | Fix crash when the program wants to S_AdjustSoundParams() for pl + r2502 | The local variable should be used in G_ReadDemoHeader() instead + r2503 | check for overrun in G_ReadDemoHeader() + r2504 | allow -recordfromto for all levels of compatibility + r2505 | "-emulate prboom_ver" includes bug with direct switch to SSG in + r2506 | huge speedup (up to 10x) on levels with sectors which have many + r2507 | fix for r2506 + r2508 | -emultae prboom-ver stuff: few new entries are added + r2509 | Monsters spawned by Icon of Sin should not be countable for tota + r2510 | comment for previous commit (r2509) + r2511 | S_DISABLE and CR_DISABLE for disabled items in menu to avoid bug + r2512 | Sound initialization was broken in r2508 if "-skipsec" command-l + r2513 | Attempt to revert some old changes made in prboom+. Probably all + r2514 | A lot of cleanups, speedups and bugfixes in render: + r2515 | Avoid crashes at end of demos if DEMOMARKER (0x80) does not exis + r2516 | fix for r2515 + r2517 | fix for r2506 (huge speedup on levels with sectors which have ma + r2518 | Fox for "The ultimate 'ATI sucks' fix" (r2495) + r2519 | fix compilation problems + r2520 | Compatibility with common mapping errors "linedefs w/o tags appl + r2521 | M_DoScreenShot did not work with "-videodriver directx" on fulls + r2522 | Optimization of "quality" mode of "rendering quality" setting. V + r2523 | fix compilation problems + r2524 | Do not use seamless code ("quality" mode) in software mode + r2525 | missed M_ChangeGLRenderPrecise call + r2526 | In GL mode, the IDRATE info for sprites is always displayed as 0 + r2527 | Try to fix building prboom-plus under linux again. + r2528 | Optimization of "quality" mode of "rendering quality" setting. F + r2529 | fix r2513: statusbar were not updated in automap mode on softwar + r2530 | There is no more visual glitches with sky on Icarus map14 and He + r2531 | nothing. comment. + r2532 | Fix of no warning (flashes between shadowed and solid) when invi + r2533 | PrBoom bug: When putting -devparm in the command line, prboom-pl + r2534 | Do not rebuild blockmap on the same level (after save/load) + r2535 | Blinking during demoskip on fullscreen + r2536 | Don't thrash cpu if the window doesnt have focus + r2537 | Original P_FindNextHighestFloor() is restored for demo_compatibi + r2538 | Ability to force -nomonsters and -respawn for playback of 1.2 de + r2539 | 1. gl_boom_colormaps config's variable to reduce memory use + r2540 | USE_GLU_IMAGESCALE is temporarily enabled to avoid some bugs + r2541 | optimization: make heightlist static to avoid malloc/free pair i + r2543 | DemoProgresBar continued to be displayed for in-wad demos (demo1 + r2544 | There are TWO bugs in the ouch face code. Not only was the condi + r2545 | Move mouse sensitivity menu upwards a little to avoid overlap wi + r2546 | The bug in algorithm of splitting of a sector into the closed co + r2547 | There is a new command-line switch "-shorttics". This makes it p + r2548 | fix compilation problem + r2549 | Fix compilation on Mac OS X. + r2550 | fix sound origin for large levels + r2551 | fix previous revision r2550 + r2552 | Premature program exit during map26 in 4-player coop demo 29uv4p + r2553 | dded two new precalculated float fields in GLTexture struct + r2554 | Wrong calculation of x2 coordinate of a weapon in gld_DrawWeapon + r2555 | fix for r2554 + r2556 | M_ChangeFOV() and M_ChangeGLRenderPrecise() should be under cond + r2557 | two video pages should be cleared in gld_Init to avoid blink dur + r2558 | Remove any line which has a clone with the same vertexes and ori + r2559 | "Allow Boom colormaps" setting => "Allow colormaps" + r2560 | wipe screen effect in OpenGL + r2561 | wipe screen effect in OpenGL: fix memory overflow + r2562 | fixed slowdown during screen melt at 1024x768 on some systems + r2563 | fix menu bug after r2560 (wipe screen effect in OpenGL) + r2564 | Changes in algorithm of GL wipe. Now it works more quickly, requ + r2565 | Add gl_wipe.c to src/Makefile.am + r2566 | Transferred sky texture on scrolled wall was not scrolled if mou + r2567 | merge R_CheckTextureNumForName from prboom + r2568 | Fix compilation on Mac OS X: add gl_wipe.c to src/MAC/Rakefile + r2569 | vertical scroll on transferred sky texture works now too (if mou + r2570 | scroll stuff from the latest revisions is temporally disabled + r2571 | scroll on transferred sky texture is enabled again + r2572 | [-] GL wipe: white screen during final screen animation in some + r2573 | sky property-transfer linedef types should be applied only for M + r2574 | sky transfer under prboom_comp now + r2575 | Reuse of a current palette to avoid black screen at software ful + r2576 | unnecessary (duplicated) call of UpdateGrab() is removed from D_ + r2577 | More adequate warning of possibility of desynch in compatibility + r2578 | from chocolate-doom r958: Initialise tracksize variable before m + r2580 | hires textures + r2581 | hires: + r2582 | hires patches + r2583 | fake colormaps for hires patches + r2584 | fix progress of load hires on fullscreen + r2585 | hires: fix for hires patches and sts_always_red; optimization of + r2586 | hires: another fix for progress bar + r2587 | all gluBuild2DMipmaps entries had wrong second parameter: gl_tex + r2588 | caching of non power of two hires textures. it speed up loading + r2589 | Import the clipper code from gzdoom. Thanks to GrafZahl. PrBoom + r2592 | new defaults + r2593 | Type of useType in gl_hires.c/gld_HiresGetTextureName was unknow + r2594 | HAVE_LIBSDL_IMAGE stuff: sources now are compilable even if you + r2595 | configure.in: Test for SDL_image being installed. + r2600 | duplicated items are removed in prboom-plus.wad + r2601 | fix compilation problems with msvc2005 + r2602 | another fix compilation problems with msvc2005 + r2603 | definition for hires textures on MAC + r2605 | plus needs SDL_image + r2606 | Don't redefine M_PI when already defined; reduces compiler spew + r2607 | Find hires textures on more platforms and with less case sensiti + r2608 | Find hires textures in lowercase in cases of case-sensitive file + r2609 | fix SEGV in HU_Start() when gamemap is not initialized + r2610 | update docs + r2611 | History is no longer stored on the Internet + r2612 | strlwr is not portable + r2613 | Update doc/Makefile.am to include prboom-plus-* documentation fi + r2614 | Check for strlwr in configure.in (used in gl_hires.c) + r2615 | Fixed crash in M_ResetDefaults(). + r2616 | fixed bug if translucency percentage is less than 50, then all t + r2618 | Disabling transparency in OpenGL for original sprites which are + r2619 | typo + r2620 | allowing to bind mouse buttons through in-game menu was broken i + r2621 | fix bug during recording non-compatible demos (complevel >= 9) w + r2622 | do not update progress of loading hires more often than 35 times + r2623 | Support for DDS format of hires textures. DDSes can be loaded wi + r2624 | config.h: do not link SDL_image.lib if HAVE_LIBSDL_IMAGE is not + r2625 | do not update progress of hires loading if no real hires was loa + r2626 | configurable level of aniso (from in-game menu Off..16x) + r2627 | Better distinguish the PrBoom launcher from the PrBoom Plus one + r2628 | execution time of gld_Precache() -> stdout.txt + r2629 | Mouse look did not work on automap in overlay mode. + r2630 | Do not try to find hires textures in non existing dirs over and + r2631 | universal SNPRINTF instead of + r2632 | Applying SNPRINTF for whole code + r2633 | small fix for SNPRINTF (defines) + r2634 | wrong index in launcher. how it worked earlier? + r2635 | Technique of rendering to texture; Real black and white effect f + r2636 | some compatibility stuff with new invul effect and old hardware + r2637 | More 'real' invul effect without using colormaps (needs opengl 1 + r2638 | More informative message if frame buffer object (FBO) has not be + r2639 | GL_RGBA8 for SceneImageTextureFBO instead of gl_tex_format. Is i + r2640 | Do not try to create a frame buffer if GL_EXT_framebuffer_object ++ r2641 | Ability to use only the allowed CPUs. For example it is necessar ++ r2642 | %d for GetLastError() instead of %s of course + r2643 | gl_compatibility variable; all OpenGL extentions will be disable + r2644 | FBO: cleanup + r2645 | An alternative way of drawing the sky was added (gl_drawskys == + r2646 | Solution for Visual Studio 2008. + r2647 | Bump version number to 2.4.8.3 + r2648 | OpenGL: Fake contrast should add/remove one light level for wall + r2649 | Fix condition for bringing up the launcher if SHIFT key is press + r2650 | fix Visual Studio 2008 solution + r2651 | help_friends is zero by default now, because it super slow. I ha + r2652 | wrong GL_TEXTURE_MAG_FILTER for detail texture + r2653 | fixed bug in gl wipe + r2654 | Fix bug in new clipper code. Some unnecessary lines were drawn. + r2655 | Do not use FBO for all frames. Should be used only if motion blu + r2656 | Never grab the mouse when window does not have focus + r2657 | Check and fix wrong references to non-existent vertexes in SEGS + r2658 | More informative warning for previous revision + r2659 | Disable demo recording on levels with invalid nodes (see previou + r2660 | fix for error quit message in r2659 + r2661 | More precise rotation of sprite if render_paperitems is equal to + r2662 | Additional sector light mode was added (Options\General\Sector L + r2665 | Fix compilation on Mac OS X 10.5 when using 10.4u SDK. + r2667 | _exit() instead of ExitProcess() for "-resetgamma" + r2668 | Restore of startup gamma if window loses focus + r2669 | fix compilation problems + r2672 | Unknown gl nodes will be ignored instead of I_Error message + r2673 | Avoid zdoom's code in additional sector light mode. Now it is fr + r2674 | optimization of sprite rotation + r2675 | Restoring original visual behaviour for demo_compatibility. View + r2676 | Ability to play wads with wrong flat names. Unknown flats will b + r2677 | Make missing sounds non-fatal. Makes sense for doom.wad v1.2 for + r2678 | fix bug of r2674 + r2679 | Revert r2530. Icarus map14 and Hell Revialed map20 will have pro + r2680 | Refactor the intercepts overrun code so that it should work prop + r2681 | Launcher (win32): Now you can associate the current EXE with DOO + r2682 | New logic in music detection code from chocolate-doom. + r2683 | sky property-transfer linedef types will be applied for boom com + r2684 | Try to fix SmoothEdges on big endian systems; fixes sprite issue + r2685 | refix SmoothEdges for little endian and tabs replaced with space + r2686 | Fix bug with sky in the bottom part of an imaginary skybox aroun + r2687 | opengl: more correct (similar to software) drawing of skies with + r2688 | Clear the screen to black in V_AllocScreen(). Makes sense for wi + r2689 | there is no restriction for length of midies. fix for r2682 + r2690 | process_affinity_mask is 1 by default + r2691 | another try to fix problem with sky on map14 @ Icarus.wad sector + r2696 | Fixed some warnings about uninitialized/unused variables and shu + r2700 | Merged r2423:2699 from trunk (hicolor) + r2701 | Advanced syntax for -geom command-line switch + r2702 | Fix compilation. GCC doesn't like casted lvalues: (byte *)psrc - + r2705 | fix for latest merge r2700 and r2440 + r2707 | added description to r_screenmultiply.c.h; + r2708 | Screens works now for non 8-bit modes in software (16-bit, 32-bi + r2712 | dogs + r2719 | Merged r2699:2718 from trunk + r2723 | Speed up in R_PointToAngleEx() in software mode + r2726 | Merged r2718:2725 from trunk + r2727 | gl_render_precise now is known as render_precise and applies to + r2728 | comment added for r2727 + r2729 | better code for r2723 + r2730 | lower memory usage if glcolormaps are used + r2731 | Clean the memory from GL textures, etc in I_ShutdownGraphics + r2732 | Simplification of the code for the previous revision r2731 + r2733 | Speedup of level reloading in OpenGL mode + r2735 | Fixed error in OpenGL if upper texture on the linedef with "Tran + r2742 | Merged r2725:2741 from trunk + r2743 | Fixed bug with GL gamma in GZDoom mode for some buggy drivers: + r2744 | Use MEM_SEEK_SET for memio, not SEEK_SET (from chocolate-doom an + r2755 | Fix for r2733 (Speedup of level reloading in OpenGL mode): + r2756 | Remove duplicate declaration of G_ReadDemoHeader in e6y.h + r2757 | Fix {m,c}alloc_IfSameLevel build failure + r2758 | comperr_hangsolid: Pretend there's a fake ceiling under a body + r2761 | explicit type was missed in r2733 + r2762 | Removal of duplicates from cfg. + r2763 | Fix for r2682: non-MUS/MIDI music (MOD, S3M, etc) was broken the + r2764 | Fixed crash (Not enough storage is available to process this com + r2765 | Fixed crash if numbers of wads/lmps/dehs is greater than 100. + r2766 | Fix vanilla unprecise calculation (vibrations) of the texture co + r2767 | Fix wrong processing of the "Blue Armor Class" string from a DEH + r2768 | Fix wrong processing of the "Green Armor Class" string from a DE + r2769 | comments for the previous two revisions + r2770 | Ability to play demos recorded with old prbooms with wrong proce + r2771 | Previous fixes for wrong processing of armor classes from a deh + r2772 | Pump the event loop (SDL_PumpEvents) in I_InitInputs() before fi + r2773 | New 'mixed' lighting mode for opengl. It uses gamma ramps like i + r2774 | hardware gamma stuff has been moved to gl_gamma.c + r2775 | Fix build failure, add new file gl_gamma.c to src/Makefile.am + r2776 | Fix compilation with MSVC2008 + r2777 | There is no more necessity to restart glboom after change of tex + r2778 | Fix compilation problems for nongl configurations + r2779 | More accurate patch drawing. Predefined arrays are used instead + r2780 | fix gamma in glboom mode (introduced in r2773, r2774) + r2781 | refix "Respawn frame" part of r2117 + r2782 | "Flashing HOM indicator" option did nothing. Fixed. + r2783 | Ability to use negative numbers with -skipsec switch. "-skipsec + r2784 | Fixed crash in case if WI_drawOnLnode will try to get access to + r2785 | Added demo compatibility with chex.exe + r2786 | The latest column of patches was not drawn. Introduced in r2779 + r2787 | The level of compatibility at which fix for comp_stairs should b + r2788 | fixed stupid mistake in chex stuff (r2785) + r2789 | key_setup was not saved in cfg + r2790 | detection of more unsupported demo formats + r2791 | Texture bug. GL only. Example in ksutra.wad map15, "COOL!" area. + r2792 | videodriver name now saved in cfg + r2793 | The fourth episode for pre ultimate doom complevels is not allow + r2794 | More precise weapon drawing in GL: there is no more line of grap + r2795 | make GL stuff from the previous revision (r2794) under GL_DOOM d + r2796 | One more 'ATI sucks' revision. + r2797 | fixed anisotropic filtering. 16x now is 16x instead of 4x + r2798 | Prepare for release 2.4.8.3. + r2799 | missed change log entries + r2801 | Text mode emulation code from Chocolate-Doom + r2802 | New application icon and loading it through SDL + r2803 | Updated MSVC project files for using text mode emulation code + r2804 | ENDOOM support using text mode emulation + r2805 | missed icon.c and python script from chocolate-doom for generati + r2806 | Add textscreen to autotools + r2807 | Add icon.c and doomkeys.h to autotools + r2808 | quick and lazy fix for memory overrun introduced in r2779 + r2809 | Restore version banner output on exit + r2810 | -r2766 + r2811 | Separate out list of extensions to be added to music_tmp + r2812 | Construct temporary filename from music_tmp with extension added + r2813 | I_ShutdownMusic: delete music_tmp and all its possible extension + r2814 | Minor music_tmp-related fixes + r2815 | prevent recursive exits + r2816 | stop music before shutdown + r2817 | New algorithm for detection of fake flats and ceilings. It is mu + r2818 | Fix build failure, add new file gl_missingtexture.c to src/Makef + r2819 | r2817+: better handling of fake floors/ceilings for sectors with + r2820 | bump version to 2.4.8.4 + r2821 | Update docs and change log + r2822 | Fixed compilation on Mac? + r2823 | added gl_gamma to Rakefile + r2824 | Shift Mac build to 10.5 target + r2825 | Remove headers from mac build + r2827 | bump version to 2.4.8.5 + r2828 | Fixed crash when nodes used for in-wad demo playback are not equ ++ r2829 | Set processor affinity under non-Windows platforms using the POS ++ r2830 | random symbol after #endif ++ r2831 | I_SetAffinityMask() has moved to i_main.c from e6y.c ++ r2832 | Fix compilation on *nix + r2833 | Eating of Alt-Tab event to prevent switching to the automap afte + r2834 | Stupid bug in deh processing. Thanks Death-Destiny for the hint + r2835 | Fixed old bug in searching responsefile. + r2836 | fixed crash with @responsefile + r2837 | change log for 2.4.8.5 + r2838 | bump version to 2.4.8.6 ++ r2839 | For now, set a no-op I_SetAffinityMask for the Mac + r2850 | Resolution limitation is removed. Memory usage has decreased as + r2852 | fixed crash if screenblocks is not equal to 11 (introduced in th + r2853 | fixed hi-color modes for r2850 + r2863 | fixed bug with caching planes heights (introduced in r2850) + r2864 | "PrBoom-Plus" -> PACKAGE_TITLE + r2865 | Temporarily define PACKAGE_TITLE in configure.in and MAC/config. + r2866 | launcher_enable variable now has three values: "never", "smart" + r2891 | Status Bar was affected by light level of the sector on some on- ++ r2892 | Fixed crash with FixedDiv(-2147483648,x) ++ r2893 | added comment for the previous revision r2892 to know what happe ++ r2894 | 2892++ (more detailed comment for crash in FixedDiv) + r2907 | Unused ConvertMus() is removed. There are no more compiling erro + r2912 | fix for r2793: do not try to show the fourth episode in menu for + r2913 | Trying to optimise screen pitch for reducing of CPU cache misses + r2914 | changed formatting of stdout for the previous revision (r2913) + r2915 | fixed bug in r2817? + r2916 | another try of r2766: Fix vanilla unprecise calculation (vibrati + r2917 | fixed wipe in software + +-------------------------------------------------------------------------- + +Unresolved issues mentioned in the Doomworld thread since 2.4.7 +http://www.doomworld.com/vb/source-ports/23525-prboom-issues-thread/ + +- http://www.doomworld.com/vb/post/644107 + mbf options lumps (bad idea, dehacked changing cheats is annoying enough) +- http://www.doomworld.com/vb/post/648619 + suggestion to steal chocolate-doom's netgame code +- http://www.doomworld.com/vb/post/654924 + cheat codes don't work in -altdeath in single player but do in vanilla +- http://www.doomworld.com/vb/post/699446 + http://www.doomworld.com/vb/post/700314 + http://www.doomworld.com/vb/post/712531 + several different people complaining about the music diff --git a/config.h b/config.h new file mode 100644 index 0000000..d9450a5 --- /dev/null +++ b/config.h @@ -0,0 +1,209 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Uncomment this to exhaustively run memory checks while the game is running + (this is EXTREMELY slow). */ +/* #undef CHECKHEAP */ + +/* Define for support for MBF helper dogs */ +#define DOGS 1 + +/* Define to be the path where Doom WADs are stored */ +#define DOOMWADDIR "/usr/local/share/games/doom" + +/* Define if you are building with OpenGL support */ +//#define GL_DOOM 1 + +/* Define to 1 if you have the header file. */ +//#define HAVE_ASM_BYTEORDER_H 1 + +/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL_SYS_SIGLIST 1 + +/* Define to 1 if you have the `getopt' function. */ +#define HAVE_GETOPT 1 + +/* Define to 1 if you have the `inet_aton' function. */ +#define HAVE_INET_ATON 1 + +/* Define to 1 if you have the `inet_ntop' function. */ +#define HAVE_INET_NTOP 1 + +/* Define to 1 if you have the `inet_pton' function. */ +#define HAVE_INET_PTON 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define if you have struct sockaddr_in6 */ +//#define HAVE_IPv6 1 + +/* Define to 1 if you have the `m' library (-lm). */ +//#define HAVE_LIBM 1 + +/* Define to 1 if you have the `png' library (-lpng). */ +//#define HAVE_LIBPNG 1 + +/* Define to 1 if you have the `SDL_mixer' library (-lSDL_mixer). */ +/* #undef HAVE_LIBSDL_MIXER */ + +/* Define if you have the SDL net library -lSDL_net */ +/* #undef HAVE_LIBSDL_NET */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mmap' function. */ +#define HAVE_MMAP 1 + +/* Define if you want network game support */ +#undef HAVE_NET + +/* Define to 1 if you have the header file. */ +#define HAVE_SCHED_H 1 + +/* Define to 1 if you have the `sched_setaffinity' function. */ +#define HAVE_SCHED_SETAFFINITY 1 + +/* Define to 1 if you have the `SDL_JoystickGetAxis' function. */ +#define HAVE_SDL_JOYSTICKGETAXIS 1 + +/* Define to 1 if you have the `snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* 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. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `usleep' function. */ +#define HAVE_USLEEP 1 + +/* Define to 1 if you have the `vsnprintf' function. */ +#define HAVE_VSNPRINTF 1 + +/* Uncomment this to cause heap dumps to be generated. Only useful if + INSTRUMENTED is also defined. */ +/* #undef HEAPDUMP */ + +/* Define for high resolution support */ +//#define HIGHRES 1 + +/* Define on targets supporting 386 assembly */ +//#define I386_ASM 1 + +/* Define this to see real-time memory allocation statistics, and enable extra + debugging features */ +/* #undef INSTRUMENTED */ + +/* If your platform has a fast version of max, define MAX to it */ +/* #undef MAX */ + +/* If your platform has a fast version of min, define MIN to it */ +/* #undef MIN */ + +/* Name of package */ +#define PACKAGE "prboom" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "prboom" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "prboom 2.5.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "prboom" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "2.5.0" + +/* Set to the attribute to apply to struct definitions to make them packed */ +#define PACKEDATTR __attribute__((packed)) + +/* Define to enable internal range checking */ +/* #undef RANGECHECK */ + +/* Define if you have an old SDL_net, such that the UDPpacket structure has a + src member instead of an address member */ +/* #undef SDL_NET_UDP_PACKET_SRC */ + +/* When defined this causes quick checks which only impose significant + overhead if a posible error is detected. */ +#define SIMPLECHECKS 1 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Defining this causes time stamps to be created each time a lump is locked, + and lumps locked for long periods of time are reported */ +/* #undef TIMEDIAG */ + +/* Define if you want to use gluImageScale */ +#define USE_GLU_IMAGESCALE 1 + +/* Define if you want to use gluBuild2DMipmaps */ +#define USE_GLU_MIPMAP 1 + +/* Define if you want to use the SDL net lib */ +/* #undef USE_SDL_NET */ + +/* Version number of package */ +#define VERSION "2.5.0" + +/* Define if using the dmalloc debugging malloc package */ +/* #undef WITH_DMALLOC */ + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define this to perform id checks on zone blocks, to detect corrupted and + illegally freed blocks */ +#define ZONEIDCHECK 1 + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to strcasecmp, if we have it */ +#define stricmp strcasecmp + +/* Define to strncasecmp, if we have it */ +#define strnicmp strncasecmp + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ diff --git a/data/Makefile.am b/data/Makefile.am new file mode 100644 index 0000000..8f0e6d0 --- /dev/null +++ b/data/Makefile.am @@ -0,0 +1,12 @@ +# +# Install, and make if needed, prboom.wad +# + +waddir=$(DOOMWADDIR) +wad_DATA=prboom.wad +EXTRA_DIST=prboom.wad prboom.txt +MAINTAINERCLEANFILES=prboom.wad + +prboom.wad : prboom.txt $(wildcard graphics/*.ppm sprites/*.ppm lumps/*.lmp sounds/*.wav) + -rm -f $@ + deutex -make prboom.txt $@ diff --git a/data/Makefile.in b/data/Makefile.in new file mode 100644 index 0000000..f4a4e8a --- /dev/null +++ b/data/Makefile.in @@ -0,0 +1,362 @@ +# Makefile.in generated by automake 1.10 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Install, and make if needed, prboom.wad +# + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = data +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/autotools/ac_c_compile_flags.m4 \ + $(top_srcdir)/autotools/ac_cpu_optimisations.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(waddir)" +wadDATA_INSTALL = $(INSTALL_DATA) +DATA = $(wad_DATA) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DOOMWADDIR = @DOOMWADDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GL_LIBS = @GL_LIBS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MATH_LIB = @MATH_LIB@ +MIXER_CFLAGS = @MIXER_CFLAGS@ +MIXER_LIBS = @MIXER_LIBS@ +MKDIR_P = @MKDIR_P@ +NET_CFLAGS = @NET_CFLAGS@ +NET_LIBS = @NET_LIBS@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SDL_CFLAGS = @SDL_CFLAGS@ +SDL_CONFIG = @SDL_CONFIG@ +SDL_LIBS = @SDL_LIBS@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +waddir = $(DOOMWADDIR) +wad_DATA = prboom.wad +EXTRA_DIST = prboom.wad prboom.txt +MAINTAINERCLEANFILES = prboom.wad +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign data/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign data/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-wadDATA: $(wad_DATA) + @$(NORMAL_INSTALL) + test -z "$(waddir)" || $(MKDIR_P) "$(DESTDIR)$(waddir)" + @list='$(wad_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(wadDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(waddir)/$$f'"; \ + $(wadDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(waddir)/$$f"; \ + done + +uninstall-wadDATA: + @$(NORMAL_UNINSTALL) + @list='$(wad_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(waddir)/$$f'"; \ + rm -f "$(DESTDIR)$(waddir)/$$f"; \ + done +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(waddir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-wadDATA + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-wadDATA + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip install-wadDATA installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic pdf pdf-am ps ps-am uninstall \ + uninstall-am uninstall-wadDATA + + +prboom.wad : prboom.txt $(wildcard graphics/*.ppm sprites/*.ppm lumps/*.lmp sounds/*.wav) + -rm -f $@ + deutex -make prboom.txt $@ +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/data/prboom.txt b/data/prboom.txt new file mode 100644 index 0000000..a3bd1f7 --- /dev/null +++ b/data/prboom.txt @@ -0,0 +1,207 @@ +# PWAD creation directives for prboom.wad +# Initially generated by DeuTex 4.4.0 + +# List of data Lumps +[lumps] +SWITCHES +ANIMATED +C_START +WATERMAP +C_END +CRBRICK +CRTAN +CRGRAY +CRGREEN +CRBROWN +CRGOLD +CRRED +CRBLUE +CRBLUE2 +CRORANGE +CRYELLOW + +# PrBoom internal data lumps (large data lumps removed from the source code) +B_START +SINETABL +TANGTABL +TANTOANG +GAMMATBL +B_END + +# List of Sounds +[sounds] +# MBF dog sounds +DSDGSIT +DSDGATK +DSDGACT +DSDGDTH +DSDGPAIN + +# List of Pictures (with insertion point) +[graphics] +M_HORSEN 0 0 +M_VERSEN 0 0 +M_COMPAT 0 0 +M_GENERL 0 0 +STBR123 0 0 +STBR124 0 0 +STBR125 0 0 +STBR126 0 0 +STBR127 0 0 +DIG0 0 0 +DIG1 0 0 +DIG2 0 0 +DIG3 0 0 +DIG4 0 0 +DIG5 0 0 +DIG6 0 0 +DIG7 0 0 +DIG8 0 0 +DIG9 0 0 +DIGA 0 0 +DIGB 0 0 +DIGC 0 0 +DIGD 0 0 +DIGE 0 0 +DIGF 0 0 +DIGG 0 0 +DIGH 0 0 +DIGI 0 0 +DIGJ 0 0 +DIGK 0 0 +DIGL 0 0 +DIGM 0 0 +DIGN 0 0 +DIGO 0 0 +DIGP 0 0 +DIGQ 0 0 +DIGR 0 0 +DIGS 0 0 +DIGT 0 0 +DIGU 0 0 +DIGV 0 0 +DIGW 0 0 +DIGX 0 0 +DIGY 0 0 +DIGZ 0 0 +DIG45 0 0 +DIG47 0 0 +DIG58 0 0 +DIG91 0 0 +DIG93 0 0 +STKEYS6 0 0 +STKEYS7 0 0 +STKEYS8 0 0 +BOXUL 0 0 +BOXUC 0 0 +BOXUR 0 0 +BOXCL 0 0 +BOXCC 0 0 +BOXCR 0 0 +BOXLL 0 0 +BOXLC 0 0 +BOXLR 0 0 +PRBOOM 0 0 +HU_FRAGS 0 0 +HU_FRGBX 0 0 +M_SETUP 0 0 +M_KEYBND 0 0 +M_AUTO 0 0 +M_CHAT 0 0 +M_ENEM 0 0 +M_STAT 0 0 +M_WEAP 0 0 +M_MESS 0 0 +M_COLORS 0 0 +M_PALSEL 0 0 +M_PALNO 0 0 +M_SLIDEM 0 0 +M_SLIDEL 0 0 +M_SLIDEO 0 0 +M_SLIDER 0 0 +M_FEAT 0 0 +M_MULTI 0 0 +M_ABOUT 0 0 +M_DEMOS 0 0 +M_WAD 0 0 +M_SOUND 0 0 +M_VIDEO 0 0 +M_MOUSE 0 0 +M_KEYBND 0 0 +M_STAT 0 0 +M_HUD 0 0 +M_COMPAT 0 0 +M_VBOX 0 0 +STCFN096 0 0 +STCFN123 0 0 +STCFN124 0 0 +STCFN125 0 0 +M_BUTT1 0 0 +M_BUTT2 0 0 + +# List of Sprites +[sprites] +# Empty sprite +TNT1A0 0 0 + +# MBF dog sprites +DOGSD5 32 59 +DOGSH5 32 59 +DOGSC5 32 59 +DOGSG5 32 59 +DOGSB1 32 59 +DOGSA5 32 59 +DOGSE5 32 59 +DOGSC1 32 59 +DOGSD1 32 59 +DOGSB5 32 59 +DOGSF5 32 59 +DOGSA1 32 59 +DOGSE1 32 59 +DOGSF1 32 59 +DOGSD2D8 32 59 +DOGSH2 32 59 +DOGSG1 32 59 +DOGSH8 32 59 +DOGSE8 32 59 +DOGSD4D6 32 59 +DOGSH4 32 59 +DOGSA2A8 32 59 +DOGSE2 32 59 +DOGSF8 32 59 +DOGSH1 32 59 +DOGSA4A6 32 59 +DOGSE4 32 59 +DOGSB4B6 32 59 +DOGSF4 32 59 +DOGSH6 32 59 +DOGSB2B8 32 59 +DOGSF2 32 59 +DOGSC2C8 32 59 +DOGSG2 32 59 +DOGSG6 32 59 +DOGSC4C6 32 59 +DOGSG4 32 59 +DOGSG8 32 59 +DOGSF6 32 59 +DOGSN0 32 59 +DOGSE6 32 59 +DOGSD3D7 32 59 +DOGSH3 32 59 +DOGSH7 32 59 +DOGSI0 32 59 +DOGSA3A7 32 59 +DOGSE3 32 59 +DOGSB3B7 32 59 +DOGSF3 32 59 +DOGSF7 32 59 +DOGSE7 32 59 +DOGSC3C7 32 59 +DOGSG3 32 59 +DOGSG7 32 59 +DOGSJ0 32 59 +DOGSK0 32 59 +DOGSL0 32 59 +DOGSM0 32 59 + +# End of extraction diff --git a/data/prboom.wad b/data/prboom.wad new file mode 100644 index 0000000..85dc155 Binary files /dev/null and b/data/prboom.wad differ diff --git a/extensions/prboom/config.xml b/extensions/prboom/config.xml new file mode 100644 index 0000000..4dfc52e --- /dev/null +++ b/extensions/prboom/config.xml @@ -0,0 +1,12 @@ + + + + PrBoom + 1.0 + simsor + SIMSOR-PRBOOM + + + menu.json + + \ No newline at end of file diff --git a/extensions/prboom/menu.json b/extensions/prboom/menu.json new file mode 100644 index 0000000..3d8ed33 --- /dev/null +++ b/extensions/prboom/menu.json @@ -0,0 +1,15 @@ +{ + "items": [ + { + "name": "Simon's Fun Land", + "items": [ + { + "name": "PrBoom", + "action": "./run.sh", + "refresh": false, + "exitmenu": false + } + ] + } + ] + } \ No newline at end of file diff --git a/extensions/prboom/run.sh b/extensions/prboom/run.sh new file mode 100644 index 0000000..efe6746 --- /dev/null +++ b/extensions/prboom/run.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +/etc/init.d/framework stop +/usr/bin/lipc-set-prop -- com.lab126.powerd preventScreenSaver 1 +./prboom -iwad /mnt/us/doom.wad -file /mnt/us/prboom.wad -nosound -nomusic -nosfx -warp 1 1 +/usr/bin/lipc-set-prop -- com.lab126.powerd preventScreenSaver 0 +/etc/init.d/framework start \ No newline at end of file diff --git a/src/KINDLE/i_joy.c b/src/KINDLE/i_joy.c new file mode 100644 index 0000000..e436b33 --- /dev/null +++ b/src/KINDLE/i_joy.c @@ -0,0 +1,68 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Joystick handling for Linux + * + *----------------------------------------------------------------------------- + */ + +#ifndef lint +#endif /* lint */ + +#include + +#include "doomdef.h" +#include "doomtype.h" +#include "m_argv.h" +#include "d_event.h" +#include "d_main.h" +#include "i_joy.h" +#include "lprintf.h" + +int joyleft; +int joyright; +int joyup; +int joydown; + +int usejoystick; + +static void I_EndJoystick(void) +{ + lprintf(LO_DEBUG, "I_EndJoystick : closing joystick\n"); +} + +void I_PollJoystick(void) +{ + +} + +void I_InitJoystick(void) +{ + +} diff --git a/src/KINDLE/i_main.c b/src/KINDLE/i_main.c new file mode 100644 index 0000000..8c929b6 --- /dev/null +++ b/src/KINDLE/i_main.c @@ -0,0 +1,409 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Startup and quit functions. Handles signals, inits the + * memory management, then calls D_DoomMain. Also contains + * I_Init which does other system-related startup stuff. + * + *----------------------------------------------------------------------------- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef USE_SDL +#include "SDL.h" +#endif +#include "doomdef.h" +#include "m_argv.h" +#include "d_main.h" +#include "m_fixed.h" +#include "i_system.h" +#include "i_video.h" +#include "z_zone.h" +#include "lprintf.h" +#include "m_random.h" +#include "doomstat.h" +#include "g_game.h" +#include "m_misc.h" +#include "i_sound.h" +#include "i_main.h" +#include "r_fps.h" +#include "lprintf.h" + +#include +#include +#include + +/* Most of the following has been rewritten by Lee Killough + * + * I_GetTime + * killough 4/13/98: Make clock rate adjustable by scale factor + * cphipps - much made static + */ + +int realtic_clock_rate = 100; +static int_64_t I_GetTime_Scale = 1<<24; + +static int I_GetTime_Scaled(void) +{ + return (int)( (int_64_t) I_GetTime_RealTime() * I_GetTime_Scale >> 24); +} + + + +static int I_GetTime_FastDemo(void) +{ + static int fasttic; + return fasttic++; +} + + + +static int I_GetTime_Error(void) +{ + I_Error("I_GetTime_Error: GetTime() used before initialization"); + return 0; +} + + + +int (*I_GetTime)(void) = I_GetTime_Error; + +void I_Init(void) +{ + /* killough 4/14/98: Adjustable speedup based on realtic_clock_rate */ + if (fastdemo) + I_GetTime = I_GetTime_FastDemo; + else + if (realtic_clock_rate != 100) + { + I_GetTime_Scale = ((int_64_t) realtic_clock_rate << 24) / 100; + I_GetTime = I_GetTime_Scaled; + } + else + I_GetTime = I_GetTime_RealTime; + + { + /* killough 2/21/98: avoid sound initialization if no sound & no music */ + if (!(nomusicparm && nosfxparm)) + I_InitSound(); + } + + R_InitInterpolation(); +} + +/* cleanup handling -- killough: + */ +static void I_SignalHandler(int s) +{ + char buf[2048]; + + signal(s,SIG_IGN); /* Ignore future instances of this signal.*/ + + strcpy(buf,"Exiting on signal: "); + I_SigString(buf+strlen(buf),2000-strlen(buf),s); + + /* If corrupted memory could cause crash, dump memory + * allocation history, which points out probable causes + */ + if (s==SIGSEGV || s==SIGILL || s==SIGFPE) + Z_DumpHistory(buf); + + I_Error("I_SignalHandler: %s", buf); +} + + + +/* killough 2/22/98: Add support for ENDBOOM, which is PC-specific + * + * this converts BIOS color codes to ANSI codes. + * Its not pretty, but it does the job - rain + * CPhipps - made static + */ + +inline static int convert(int color, int *bold) +{ + if (color > 7) { + color -= 8; + *bold = 1; + } + switch (color) { + case 0: + return 0; + case 1: + return 4; + case 2: + return 2; + case 3: + return 6; + case 4: + return 1; + case 5: + return 5; + case 6: + return 3; + case 7: + return 7; + } + return 0; +} + +/* CPhipps - flags controlling ENDOOM behaviour */ +enum { + endoom_colours = 1, + endoom_nonasciichars = 2, + endoom_droplastline = 4 +}; + +unsigned int endoom_mode; + +static void PrintVer(void) +{ + char vbuf[200]; + lprintf(LO_INFO,"%s\n",I_GetVersionString(vbuf,200)); +} + +/* I_EndDoom + * Prints out ENDOOM or ENDBOOM, using some common sense to decide which. + * cphipps - moved to l_main.c, made static + */ +static void I_EndDoom(void) +{ + int lump_eb, lump_ed, lump = -1; + + /* CPhipps - ENDOOM/ENDBOOM selection */ + lump_eb = W_CheckNumForName("ENDBOOM");/* jff 4/1/98 sign our work */ + lump_ed = W_CheckNumForName("ENDOOM"); /* CPhipps - also maybe ENDOOM */ + + if (lump_eb == -1) + lump = lump_ed; + else if (lump_ed == -1) + lump = lump_eb; + else + { /* Both ENDOOM and ENDBOOM are present */ +#define LUMP_IS_NEW(num) (!((lumpinfo[num].source == source_iwad) || (lumpinfo[num].source == source_auto_load))) + switch ((LUMP_IS_NEW(lump_ed) ? 1 : 0 ) | + (LUMP_IS_NEW(lump_eb) ? 2 : 0)) { + case 1: + lump = lump_ed; + break; + case 2: + lump = lump_eb; + break; + default: + /* Both lumps have equal priority, both present */ + lump = (P_Random(pr_misc) & 1) ? lump_ed : lump_eb; + break; + } + } + + if (lump != -1) + { + const char (*endoom)[2] = (const void*)W_CacheLumpNum(lump); + int i, l = W_LumpLength(lump) / 2; + + /* cph - colour ENDOOM by rain */ + int oldbg = -1, oldcolor = -1, bold = 0, oldbold = -1, color = 0; +#ifndef _WIN32 + if (endoom_mode & endoom_nonasciichars) + /* switch to secondary charset, and set to cp437 (IBM charset) */ + printf("\e)K\016"); +#endif /* _WIN32 */ + + /* cph - optionally drop the last line, so everything fits on one screen */ + if (endoom_mode & endoom_droplastline) + l -= 80; + lprintf(LO_INFO,"\n"); + for (i=0; i +#endif +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include + +#ifdef HAVE_NET + +#include "SDL.h" +#include "SDL_net.h" + +#include "protocol.h" +#include "i_network.h" +#include "lprintf.h" +//#include "doomstat.h" + +/* cph - + * Each client will either use the IPv4 socket or the IPv6 socket + * Each server will use whichever or both that are available + */ +UDP_CHANNEL sentfrom; +IPaddress sentfrom_addr; +UDP_SOCKET udp_socket; + +/* Statistics */ +size_t sentbytes, recvdbytes; + +UDP_PACKET *udp_packet; + +/* I_ShutdownNetwork + * + * Shutdown the network code + */ +void I_ShutdownNetwork(void) +{ + SDLNet_FreePacket(udp_packet); + SDLNet_Quit(); +} + +/* I_InitNetwork + * + * Sets up the network code + */ +void I_InitNetwork(void) +{ + SDLNet_Init(); + atexit(I_ShutdownNetwork); + udp_packet = SDLNet_AllocPacket(10000); +} + +UDP_PACKET *I_AllocPacket(int size) +{ + return(SDLNet_AllocPacket(size)); +} + +void I_FreePacket(UDP_PACKET *packet) +{ + SDLNet_FreePacket(packet); +} + + +/* cph - I_WaitForPacket - use select(2) via SDL_net's interface + * No more I_uSleep loop kludge */ + +void I_WaitForPacket(int ms) +{ + SDLNet_SocketSet ss = SDLNet_AllocSocketSet(1); + SDLNet_UDP_AddSocket(ss, udp_socket); + SDLNet_CheckSockets(ss,ms); + SDLNet_FreeSocketSet(ss); +#if (defined _WIN32 && !defined PRBOOM_SERVER) + I_UpdateConsole(); +#endif +} + +/* I_ConnectToServer + * + * Connect to a server + */ +IPaddress serverIP; + +int I_ConnectToServer(const char *serv) +{ + char server[500], *p; + Uint16 port; + + /* Split serv into address and port */ + if (strlen(serv)>500) return 0; + strcpy(server,serv); + p = strchr(server, ':'); + if(p) + { + *p++ = '\0'; + port = atoi(p); + } + else + port = 5030; /* Default server port */ + + SDLNet_ResolveHost(&serverIP, server, port); + if ( serverIP.host == INADDR_NONE ) + return -1; + + if (SDLNet_UDP_Bind(udp_socket, 0, &serverIP) == -1) + return -1; + + return 0; +} + +/* I_Disconnect + * + * Disconnect from server + */ +void I_Disconnect(void) +{ +/* int i; + UDP_PACKET *packet; + packet_header_t *pdata = (packet_header_t *)packet->data; + packet = I_AllocPacket(sizeof(packet_header_t) + 1); + + packet->data[sizeof(packet_header_t)] = consoleplayer; + pdata->type = PKT_QUIT; pdata->tic = gametic; + + for (i=0; i<4; i++) { + I_SendPacket(packet); + I_uSleep(10000); + } + I_FreePacket(packet);*/ + SDLNet_UDP_Unbind(udp_socket, 0); +} + +/* + * I_Socket + * + * Sets the given socket non-blocking, binds to the given port, or first + * available if none is given + */ +UDP_SOCKET I_Socket(Uint16 port) +{ + if(port) + return (SDLNet_UDP_Open(port)); + else { + UDP_SOCKET sock; + port = IPPORT_RESERVED; + while( (sock = SDLNet_UDP_Open(port)) == NULL ) + port++; + return sock; + } +} + +void I_CloseSocket(UDP_SOCKET sock) +{ + SDLNet_UDP_Close(sock); +} + +UDP_CHANNEL I_RegisterPlayer(IPaddress *ipaddr) +{ + static int freechannel; + return(SDLNet_UDP_Bind(udp_socket, freechannel++, ipaddr)); +} + +void I_UnRegisterPlayer(UDP_CHANNEL channel) +{ + SDLNet_UDP_Unbind(udp_socket, channel); +} + +/* + * ChecksumPacket + * + * Returns the checksum of a given network packet + */ +static byte ChecksumPacket(const packet_header_t* buffer, size_t len) +{ + const byte* p = (const void*)buffer; + byte sum = 0; + + if (len==0) + return 0; + + while (p++, --len) + sum += *p; + + return sum; +} + +size_t I_GetPacket(packet_header_t* buffer, size_t buflen) +{ + int checksum; + size_t len; + int status; + + status = SDLNet_UDP_Recv(udp_socket, udp_packet); + len = udp_packet->len; + if (buflen0) ) + memcpy(buffer, udp_packet->data, len); + sentfrom=udp_packet->channel; +#ifndef SDL_NET_UDP_PACKET_SRC + sentfrom_addr=udp_packet->address; +#else + sentfrom_addr=udp_packet->src; /* cph - allow for old SDL_net library */ +#endif + checksum=buffer->checksum; + buffer->checksum=0; + if ( (status!=0) && (len>0)) { + byte psum = ChecksumPacket(buffer, udp_packet->len); +/* fprintf(stderr, "recvlen = %u, stolen = %u, csum = %u, psum = %u\n", + udp_packet->len, len, checksum, psum); */ + if (psum == checksum) return len; + } + return 0; +} + +void I_SendPacket(packet_header_t* packet, size_t len) +{ + packet->checksum = ChecksumPacket(packet, len); + memcpy(udp_packet->data, packet, udp_packet->len = len); + SDLNet_UDP_Send(udp_socket, 0, udp_packet); +} + +void I_SendPacketTo(packet_header_t* packet, size_t len, UDP_CHANNEL *to) +{ + packet->checksum = ChecksumPacket(packet, len); + memcpy(udp_packet->data, packet, udp_packet->len = len); + SDLNet_UDP_Send(udp_socket, *to, udp_packet); +} + +void I_PrintAddress(FILE* fp, UDP_CHANNEL *addr) +{ +/* + char *addy; + Uint16 port; + IPaddress *address; + + address = SDLNet_UDP_GetPeerAddress(udp_socket, player); + +//FIXME: if it cant resolv it may freeze up + addy = SDLNet_ResolveIP(address); + port = address->port; + + if(addy != NULL) + fprintf(fp, "%s:%d", addy, port); + else + fprintf(fp, "Error"); +*/ +} + +#endif /* HAVE_NET */ diff --git a/src/KINDLE/i_sound.c b/src/KINDLE/i_sound.c new file mode 100644 index 0000000..d020313 --- /dev/null +++ b/src/KINDLE/i_sound.c @@ -0,0 +1,534 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * System interface for sound. + * + *----------------------------------------------------------------------------- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LIBSDL_MIXER +#define HAVE_MIXER +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_MIXER +#include "SDL_mixer.h" +#endif + +#include "z_zone.h" + +#include "m_swap.h" +#include "i_sound.h" +#include "m_argv.h" +#include "m_misc.h" +#include "w_wad.h" +#include "lprintf.h" +#include "s_sound.h" + +#include "doomdef.h" +#include "doomstat.h" +#include "doomtype.h" + +#include "d_main.h" + +// 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. + +// Variables used by Boom from Allegro +// created here to avoid changes to core Boom files +int snd_card = 1; +int mus_card = 1; +int detect_voices = 0; // God knows + +static boolean sound_inited = false; +static boolean first_sound_init = true; + +// Needed for calling the actual sound output. +static int SAMPLECOUNT= 512; +#define MAX_CHANNELS 32 + +// MWM 2000-01-08: Sample rate in samples/second +int snd_samplerate=11025; + +// The actual output device. +int audio_fd; + +typedef struct { + // SFX id of the playing sound effect. + // Used to catch duplicates (like chainsaw). + int id; +// The channel step amount... + unsigned int step; +// ... and a 0.16 bit remainder of last step. + unsigned int stepremainder; + unsigned int samplerate; +// The channel data pointers, start and end. + const unsigned char* data; + const unsigned char* enddata; +// 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 starttime; + // Hardware left and right channel volume lookup. + int *leftvol_lookup; + int *rightvol_lookup; +} channel_info_t; + +channel_info_t channelinfo[MAX_CHANNELS]; + +// Pitch to stepping lookup, unused. +int steptable[256]; + +// Volume lookups. +int vol_lookup[128*256]; + +/* cph + * stopchan + * Stops a sound, unlocks the data + */ + +static void stopchan(int i) +{ + if (channelinfo[i].data) /* cph - prevent excess unlocks */ + { + channelinfo[i].data=NULL; + W_UnlockLumpNum(S_sfx[channelinfo[i].id].lumpnum); + } +} + +// +// This function adds a sound to the +// list of currently active sounds, +// which is maintained as a given number +// (eight, usually) of internal channels. +// Returns a handle. +// +static int addsfx(int sfxid, int channel, const unsigned char* data, size_t len) +{ + stopchan(channel); + + channelinfo[channel].data = data; + /* Set pointer to end of raw data. */ + channelinfo[channel].enddata = channelinfo[channel].data + len - 1; + channelinfo[channel].samplerate = (channelinfo[channel].data[3]<<8)+channelinfo[channel].data[2]; + channelinfo[channel].data += 8; /* Skip header */ + + channelinfo[channel].stepremainder = 0; + // Should be gametic, I presume. + channelinfo[channel].starttime = gametic; + + // Preserve sound SFX id, + // e.g. for avoiding duplicates of chainsaw. + channelinfo[channel].id = sfxid; + + return channel; +} + +static void updateSoundParams(int handle, int volume, int seperation, int pitch) +{ + int slot = handle; + int rightvol; + int leftvol; + int step = steptable[pitch]; + +#ifdef RANGECHECK + if ((handle < 0) || (handle >= MAX_CHANNELS)) + I_Error("I_UpdateSoundParams: handle out of range"); +#endif + // Set stepping + // MWM 2000-12-24: Calculates proportion of channel samplerate + // to global samplerate for mixing purposes. + // Patched to shift left *then* divide, to minimize roundoff errors + // as well as to use SAMPLERATE as defined above, not to assume 11025 Hz + if (pitched_sounds) + channelinfo[slot].step = step + (((channelinfo[slot].samplerate<<16)/snd_samplerate)-65536); + else + channelinfo[slot].step = ((channelinfo[slot].samplerate<<16)/snd_samplerate); + + // Separation, that is, orientation/stereo. + // range is: 1 - 256 + seperation += 1; + + // Per left/right channel. + // x^2 seperation, + // adjust volume properly. + leftvol = volume - ((volume*seperation*seperation) >> 16); + 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??? + channelinfo[slot].leftvol_lookup = &vol_lookup[leftvol*256]; + channelinfo[slot].rightvol_lookup = &vol_lookup[rightvol*256]; +} + +void I_UpdateSoundParams(int handle, int volume, int seperation, int pitch) +{ + +} + +// +// 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(void) +{ + // 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 channel, int vol, int sep, int pitch, int priority) +{ + return -1; +} + + + +void I_StopSound (int handle) +{ +#ifdef RANGECHECK + if ((handle < 0) || (handle >= MAX_CHANNELS)) + I_Error("I_StopSound: handle out of range"); +#endif +} + + +boolean I_SoundIsPlaying(int handle) +{ +#ifdef RANGECHECK + if ((handle < 0) || (handle >= MAX_CHANNELS)) + I_Error("I_SoundIsPlaying: handle out of range"); +#endif + return channelinfo[handle].data != NULL; +} + + +boolean I_AnySoundStillPlaying(void) +{ + boolean result = false; + int i; + + for (i=0; idata = 0; + song->handle = 0; + song->lumpnum = 0; + return 0; + } +#else + return 1; +#endif +} + +void I_SetMusicVolume(int volume) +{ +#ifdef HAVE_MIXER + Mix_VolumeMusic(volume*8); +#endif +} + +#endif /* HAVE_OWN_MUSIC */ + diff --git a/src/KINDLE/i_sshot.c b/src/KINDLE/i_sshot.c new file mode 100644 index 0000000..32a8b1f --- /dev/null +++ b/src/KINDLE/i_sshot.c @@ -0,0 +1,60 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2006 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Screenshot functions, moved out of i_video.c + * + *----------------------------------------------------------------------------- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + + +#ifdef HAVE_LIBPNG +#include +#endif + +#include "doomstat.h" +#include "doomdef.h" +#include "doomtype.h" +#include "v_video.h" +#include "i_video.h" +#include "z_zone.h" +#include "lprintf.h" + + + +int I_ScreenShot (const char *fname) +{ + +} + diff --git a/src/KINDLE/i_system.c b/src/KINDLE/i_system.c new file mode 100644 index 0000000..077e708 --- /dev/null +++ b/src/KINDLE/i_system.c @@ -0,0 +1,460 @@ + + +#include + +#include +#include +#include +#include +#ifdef _MSC_VER +#define F_OK 0 /* Check for file existence */ +#define W_OK 2 /* Check for write permission */ +#define R_OK 4 /* Check for read permission */ +#include +#include +#else +#include +#include +#include +#include +#include +#include +#endif +#include + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SCHED_H +#include +#endif +#ifdef _MSC_VER +#include +#endif +#include +#include +#include + +#ifndef PRBOOM_SERVER +#include "m_argv.h" +#endif +#include "lprintf.h" +#include "doomtype.h" +#include "doomdef.h" +#include "lprintf.h" +#ifndef PRBOOM_SERVER +#include "m_fixed.h" +#include "r_fps.h" +#endif +#include "i_system.h" + +#ifdef __GNUG__ +#pragma implementation "i_system.h" +#endif +#include "i_system.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +static unsigned int start_displaytime; +static unsigned int displaytime; +static boolean InDisplay = false; + +unsigned int SDL_GetTicks() { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + + return ((unsigned int)ts.tv_sec*1000) + (ts.tv_nsec/1000); +} + +boolean I_StartDisplay(void) +{ + if (InDisplay) + return false; + + start_displaytime = SDL_GetTicks(); + InDisplay = true; + return true; +} + +void I_EndDisplay(void) +{ + displaytime = SDL_GetTicks() - start_displaytime; + InDisplay = false; +} + +void I_uSleep(unsigned long usecs) +{ + sleep(usecs/1000); +} + +int ms_to_next_tick; + +int I_GetTime_RealTime (void) +{ + /* int t = SDL_GetTicks(); + int i = t*(TICRATE/5)/200; + ms_to_next_tick = (i+1)*200/(TICRATE/5) - t; + if (ms_to_next_tick > 1000/TICRATE || ms_to_next_tick<1) ms_to_next_tick = 1; + return i;*/ + struct timeval tv; +struct timezone tz; +unsigned long thistimereply; + +gettimeofday(&tv, &tz); + +//tv_sec is seconds tv_usec is microseconds +thistimereply = (tv.tv_sec * TICRATE + (tv.tv_usec * TICRATE) / +1000000); +return thistimereply; +} + +#ifndef PRBOOM_SERVER +fixed_t I_GetTimeFrac (void) +{ + unsigned long now; + fixed_t frac; + + now = SDL_GetTicks(); + + if (tic_vars.step == 0) + return FRACUNIT; + else + { + frac = (fixed_t)((now - tic_vars.start + displaytime) * FRACUNIT / tic_vars.step); + if (frac < 0) + frac = 0; + if (frac > FRACUNIT) + frac = FRACUNIT; + return frac; + } +} + +void I_GetTime_SaveMS(void) +{ + if (!movement_smooth) + return; + + tic_vars.start = SDL_GetTicks(); + tic_vars.next = (unsigned int) ((tic_vars.start * tic_vars.msec + 1.0f) / tic_vars.msec); + tic_vars.step = tic_vars.next - tic_vars.start; +} +#endif + +/* + * I_GetRandomTimeSeed + * + * CPhipps - extracted from G_ReloadDefaults because it is O/S based + */ +unsigned long I_GetRandomTimeSeed(void) +{ +/* This isnt very random */ + return(SDL_GetTicks()); +} + +/* cphipps - I_GetVersionString + * Returns a version string in the given buffer + */ +const char* I_GetVersionString(char* buf, size_t sz) +{ +#ifdef HAVE_SNPRINTF + snprintf(buf,sz,"%s v%s (http://prboom.sourceforge.net/)",PACKAGE,VERSION); +#else + sprintf(buf,"%s v%s (http://prboom.sourceforge.net/)",PACKAGE,VERSION); +#endif + return buf; +} + +/* cphipps - I_SigString + * Returns a string describing a signal number + */ +const char* I_SigString(char* buf, size_t sz, int signum) +{ +#ifdef SYS_SIGLIST_DECLARED + if (strlen(sys_siglist[signum]) < sz) + strcpy(buf,sys_siglist[signum]); + else +#endif +#ifdef HAVE_SNPRINTF + snprintf(buf,sz,"signal %d",signum); +#else + sprintf(buf,"signal %d",signum); +#endif + return buf; +} + + +/* + * I_Read + * + * cph 2001/11/18 - wrapper for read(2) which handles partial reads and aborts + * on error. + */ +void I_Read(int fd, void* vbuf, size_t sz) +{ + unsigned char* buf = vbuf; + + while (sz) { + int rc = read(fd,buf,sz); + if (rc <= 0) { + I_Error("I_Read: read failed: %s", rc ? strerror(errno) : "EOF"); + } + sz -= rc; buf += rc; + } +} + +/* + * I_Filelength + * + * Return length of an open file. + */ + +int I_Filelength(int handle) +{ + struct stat fileinfo; + if (fstat(handle,&fileinfo) == -1) + I_Error("I_Filelength: %s",strerror(errno)); + return fileinfo.st_size; +} + +#ifndef PRBOOM_SERVER + +// Return the path where the executable lies -- Lee Killough +// proff_fs 2002-07-04 - moved to i_system +#ifdef _WIN32 +const char *I_DoomExeDir(void) +{ + static const char current_dir_dummy[] = {"."}; // proff - rem extra slash 8/21/03 + static char *base; + if (!base) // cache multiple requests + { + size_t len = strlen(*myargv); + char *p = (base = malloc(len+1)) + len - 1; + strcpy(base,*myargv); + while (p > base && *p!='/' && *p!='\\') + *p--=0; + if (*p=='/' || *p=='\\') + *p--=0; + if (strlen(base)<2) + { + free(base); + base = malloc(1024); + if (!getcwd(base,1024)) + strcpy(base, current_dir_dummy); + } + } + return base; +} + +#elif defined(AMIGA) + +const char *I_DoomExeDir(void) +{ + return "PROGDIR:"; +} + +#elif defined(MACOSX) + +/* Defined elsewhere */ + +#else +// cph - V.Aguilar (5/30/99) suggested return ~/.lxdoom/, creating +// if non-existant +static const char prboom_dir[] = {"/.prboom"}; // Mead rem extra slash 8/21/03 + +const char *I_DoomExeDir(void) +{ + static char *base; + if (!base) // cache multiple requests + { + char *home = getenv("HOME"); + size_t len = strlen(home); + + base = malloc(len + strlen(prboom_dir) + 1); + strcpy(base, home); + // I've had trouble with trailing slashes before... + if (base[len-1] == '/') base[len-1] = 0; + strcat(base, prboom_dir); + mkdir(base, S_IRUSR | S_IWUSR | S_IXUSR); // Make sure it exists + } + return base; +} +#endif + +/* + * HasTrailingSlash + * + * cphipps - simple test for trailing slash on dir names + */ + +boolean HasTrailingSlash(const char* dn) +{ + return ( (dn[strlen(dn)-1] == '/') +#if defined(AMIGA) + || (dn[strlen(dn)-1] == ':') +#endif + ); +} + +/* + * I_FindFile + * + * proff_fs 2002-07-04 - moved to i_system + * + * cphipps 19/1999 - writen to unify the logic in FindIWADFile and the WAD + * autoloading code. + * Searches the standard dirs for a named WAD file + * The dirs are listed at the start of the function + */ + +#ifndef MACOSX /* OSX defines its search paths elsewhere. */ +char* I_FindFile(const char* wfname, const char* ext) +{ + // lookup table of directories to search + static const struct { + const char *dir; // directory + const char *sub; // subdirectory + const char *env; // environment variable + const char *(*func)(void); // for I_DoomExeDir + } search[] = { + {NULL}, // current working directory + {NULL, NULL, "DOOMWADDIR"}, // run-time $DOOMWADDIR + {DOOMWADDIR}, // build-time configured DOOMWADDIR + {NULL, "doom", "HOME"}, // ~/doom + {NULL, NULL, "HOME"}, // ~ + {NULL, NULL, NULL, I_DoomExeDir}, // config directory + {"/usr/local/share/games/doom"}, + {"/usr/share/games/doom"}, + {"/usr/local/share/doom"}, + {"/usr/share/doom"}, + }; + + int i; + /* Precalculate a length we will need in the loop */ + size_t pl = strlen(wfname) + strlen(ext) + 4; + + for (i = 0; i < sizeof(search)/sizeof(*search); i++) { + char * p; + const char * d = NULL; + const char * s = NULL; + /* Each entry in the switch sets d to the directory to look in, + * and optionally s to a subdirectory of d */ + // switch replaced with lookup table + if (search[i].env) { + if (!(d = getenv(search[i].env))) + continue; + } else if (search[i].func) + d = search[i].func(); + else + d = search[i].dir; + s = search[i].sub; + + p = malloc((d ? strlen(d) : 0) + (s ? strlen(s) : 0) + pl); + sprintf(p, "%s%s%s%s%s", d ? d : "", (d && !HasTrailingSlash(d)) ? "/" : "", + s ? s : "", (s && !HasTrailingSlash(s)) ? "/" : "", + wfname); + + if (access(p,F_OK)) + strcat(p, ext); + if (!access(p,F_OK)) { + lprintf(LO_INFO, " found %s\n", p); + return p; + } + free(p); + } + return NULL; +} +#endif + +#ifdef _WIN32 +static char* WINError(void) +{ + static char *WinEBuff = NULL; + DWORD err = GetLastError(); + char *ch; + + if (WinEBuff) + { + LocalFree(WinEBuff); + } + + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &WinEBuff, 0, NULL) == 0) + { + return "Unknown error"; + } + + if ((ch = strchr(WinEBuff, '\n')) != 0) + *ch = 0; + if ((ch = strchr(WinEBuff, '\r')) != 0) + *ch = 0; + + return WinEBuff; +} +#endif + +#define DEFAULT_AFFINITY_MASK 1 + +void I_SetAffinityMask(void) +{ + unsigned int process_affinity_mask = DEFAULT_AFFINITY_MASK; + int p = M_CheckParm("-affinity"); + + if (p && p < myargc-1) + process_affinity_mask = atoi(myargv[p+1]); + + // Set the process affinity mask so that all threads + // run on the same processor. This is a workaround for a bug in + // SDL_mixer that causes occasional crashes. + if (process_affinity_mask) + { + const char *errbuf = NULL; +#ifdef _WIN32 + if (!SetProcessAffinityMask(GetCurrentProcess(), process_affinity_mask)) + { + errbuf = WINError(); + } +#elif defined(HAVE_SCHED_SETAFFINITY) + // POSIX version: + int i; + { + cpu_set_t set; + + CPU_ZERO(&set); + + for(i = 0; i < 16; i++) + { + CPU_SET((process_affinity_mask>>i)&1, &set); + } + + if (sched_setaffinity(getpid(), sizeof(set), &set) == -1) + { + errbuf = strerror(errno); + } + } +#else + return; +#endif + + if (errbuf == NULL) + { + lprintf(LO_INFO, "I_SetAffinityMask: manual affinity mask is %d\n", process_affinity_mask); + } + else + { + lprintf(LO_ERROR, "I_SetAffinityMask: failed to set process affinity mask (%s)\n", errbuf); + } + } +} + +#endif // PRBOOM_SERVER diff --git a/src/KINDLE/i_video.c b/src/KINDLE/i_video.c new file mode 100644 index 0000000..6e926d2 --- /dev/null +++ b/src/KINDLE/i_video.c @@ -0,0 +1,529 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2006 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * DOOM graphics stuff for SDL + * + *----------------------------------------------------------------------------- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifdef HAVE_UNISTD_H +#include +#include +#include +#include +#include +#include +#include +#endif + + +#include "m_argv.h" +#include "doomstat.h" +#include "doomdef.h" +#include "doomtype.h" +#include "v_video.h" +#include "r_draw.h" +#include "d_main.h" +#include "d_event.h" +#include "i_joy.h" +#include "i_video.h" +#include "z_zone.h" +#include "s_sound.h" +#include "sounds.h" +#include "w_wad.h" +#include "st_stuff.h" +#include "lprintf.h" + +int gl_colorbuffer_bits=16; +int gl_depthbuffer_bits=16; + +extern void M_QuitDOOM(int choice); +#ifdef DISABLE_DOUBLEBUFFER +int use_doublebuffer = 0; +#else +int use_doublebuffer = 1; // Included not to break m_misc, but not relevant to SDL +#endif +int use_fullscreen; +int desired_fullscreen; +static byte *screen; +static int fbFd; +static int kindleKeysFd; +static int kindleKeysFd2; + +typedef struct { + int truc1; + int truc2; + unsigned short truc3; + unsigned short keyCode; + int status; +} kindle_key_t; + +static kindle_key_t kkey; + +#define SCREEN_WIDTH 600 +#define SCREEN_HEIGHT 800 + +/////////// FRAMEBUFFER STUFF +static void init_framebuffer() { + fbFd = open("/dev/fb0", O_RDWR); + if (fbFd == -1) { + perror("open(/dev/fb0)"); + exit(1); + } +} + +static void update_framebuffer(int full) { + if (full) { + ioctl(fbFd, 0x46db, 1); + } else { + ioctl(fbFd, 0x46db, 0); + } +} + +static void clear_framebuffer() { + ioctl(fbFd, 0x46e1, 0); +} + + +////// KINDLE EVENTS + +static void init_kindle_keys() { + kindleKeysFd = open("/dev/input/event1", O_RDONLY|O_NONBLOCK); + if (kindleKeysFd == -1) { + perror("open(/dev/input/event1)"); + exit(1); + } + + kindleKeysFd2 = open("/dev/input/event0", O_RDONLY|O_NONBLOCK); + if (kindleKeysFd2 == -1) { + perror("open(/dev/input/event0)"); + exit(1); + } +} + +static int kindle_poll_keys(kindle_key_t *k) { + int retval = read(kindleKeysFd, k, sizeof(kindle_key_t)); + if (retval == -1) { + if (errno != EAGAIN) { + perror("read()"); + exit(1); + } + } else if (retval > 0) { + return 1; + } + + // This SHOULD NOT WORK: /dev/input/event0 doesn't have the same structure as event1 + // For some reason it matches for the HOME key, but it's a kludge and doesn't allow us to detect the other buttons + retval = read(kindleKeysFd2, k, sizeof(kindle_key_t)); + if (retval == -1) { + if (errno != EAGAIN) { + perror("read()"); + exit(1); + } + } else if (retval > 0) { + return 1; + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////// +// Input code +int leds_always_off = 0; // Expected by m_misc, not relevant + +// Mouse handling +extern int usemouse; // config file var +static boolean mouse_enabled; // usemouse, but can be overriden by -nomouse +static boolean mouse_currently_grabbed; + +///////////////////////////////////////////////////////////////////////////////// +// Keyboard handling + +// +// Translates the key currently in key +// + +#define KINDLE_LEFT 105 +#define KINDLE_RIGHT 106 +#define KINDLE_UP 103 +#define KINDLE_DOWN 108 +#define KINDE_OK 194 +#define KINDLE_HOME 102 +#define KINDLE_MENU 139 +#define KINDLE_BACK 158 + +static int I_TranslateKey(unsigned short code) +{ + int rc = 0; + + switch (code) { + case KINDLE_LEFT: rc = KEYD_LEFTARROW; break; + case KINDLE_RIGHT: rc = KEYD_RIGHTARROW; break; + case KINDLE_UP: rc = KEYD_UPARROW; break; + case KINDLE_DOWN: rc = KEYD_DOWNARROW; break; + case KINDE_OK: rc = KEYD_RCTRL; break; + default: break; + } + + + return rc; + +} + +///////////////////////////////////////////////////////////////////////////////// +// Main input code + +/* cph - pulled out common button code logic */ +static int I_SDLtoDoomMouseState(int buttonstate) +{ + return 0; +} + +static void I_GetEvent(kindle_key_t k) +{ + event_t event; + + if (k.keyCode == 102 && k.status == 1) { + // Press HOME + exit(0); + } + + switch (k.status) { + case 1: // SDL_KEYDOWN + event.type = ev_keydown; + event.data1 = I_TranslateKey(k.keyCode); + D_PostEvent(&event); + break; + + case 0: // SDL_KEYUP + { + event.type = ev_keyup; + event.data1 = I_TranslateKey(k.keyCode); + D_PostEvent(&event); + } + break; + + default: + break; + } +} + + +// +// I_StartTic +// + +void I_StartTic (void) +{ + while ( kindle_poll_keys(&kkey)) { + //printf("Keycode: %d // Status: %d\n", kkey.keyCode, kkey.status); + I_GetEvent(kkey); + } +} + +// +// I_StartFrame +// +void I_StartFrame (void) +{ +} + +// +// I_InitInputs +// + +static void I_InitInputs(void) +{ + init_kindle_keys(); +} +///////////////////////////////////////////////////////////////////////////// + +// I_SkipFrame +// +// Returns true if it thinks we can afford to skip this frame + +inline static boolean I_SkipFrame(void) +{ + static int frameno; + + frameno++; + switch (gamestate) { + case GS_LEVEL: + if (!paused) + return false; + default: + // Skip odd frames + return (frameno & 1) ? true : false; + } +} + +/////////////////////////////////////////////////////////// +// Palette stuff. +// +static void I_UploadNewPalette(int pal) +{ +} + +////////////////////////////////////////////////////////////////////////////// +// Graphics API + +void I_ShutdownGraphics(void) +{ +} + +// +// I_UpdateNoBlit +// +void I_UpdateNoBlit (void) +{ +} + +// +// I_FinishUpdate +// +static int newpal = 0; +#define NO_PALETTE_CHANGE 1000 + +void I_FinishUpdate (void) +{ + if (I_SkipFrame()) return; + + + int h; + byte *src; + byte *dest; + + + dest=screen; + src=screens[0].data; + h=SCREEN_HEIGHT; + for (; h>0; h--) + { + memcpy(dest,src,SCREENWIDTH); //*V_GetPixelDepth() + for (byte* off=dest; off < dest+SCREENWIDTH; off++) { + *off = ~*off; // Invert pixel color, 0xFF == black on the e-ink display + } + dest+=SCREEN_WIDTH; + src+=screens[0].byte_pitch; + } + + + update_framebuffer(0); +} + +// +// I_ScreenShot - moved to i_sshot.c +// + +// +// I_SetPalette +// +void I_SetPalette (int pal) +{ + newpal = pal; +} + +// I_PreInitGraphics + +static void I_ShutdownSDL(void) +{ + clear_framebuffer(); + close(fbFd); + return; +} + +void I_PreInitGraphics(void) +{ + init_framebuffer(); + + atexit(I_ShutdownSDL); +} + +// e6y +// GLBoom use this function for trying to set the closest supported resolution if the requested mode can't be set correctly. +// For example glboom.exe -geom 1025x768 -nowindow will set 1024x768. +// It should be used only for fullscreen modes. +static void I_ClosestResolution (int *width, int *height, int flags) +{ + *width=600; + *height=800; +} + +// CPhipps - +// I_CalculateRes +// Calculates the screen resolution, possibly using the supplied guide +void I_CalculateRes(unsigned int width, unsigned int height) +{ + // e6y: how about 1680x1050? + /* + SCREENWIDTH = (width+3) & ~3; + SCREENHEIGHT = (height+3) & ~3; + */ + +// e6y +// GLBoom will try to set the closest supported resolution +// if the requested mode can't be set correctly. +// For example glboom.exe -geom 1025x768 -nowindow will set 1024x768. +// It affects only fullscreen modes. + if (V_GetMode() == VID_MODEGL) { + if ( desired_fullscreen ) + { + I_ClosestResolution(&width, &height, 0); + } + SCREENWIDTH = width; + SCREENHEIGHT = height; + SCREENPITCH = SCREENWIDTH; + } else { + SCREENWIDTH = 600;//(width+15) & ~15; + SCREENHEIGHT = height; + if (!(SCREENWIDTH % 1024)) { + SCREENPITCH = SCREENWIDTH*V_GetPixelDepth()+32; + } else { + SCREENPITCH = SCREENWIDTH*V_GetPixelDepth(); + } + } +} + +// CPhipps - +// I_SetRes +// Sets the screen resolution +void I_SetRes(void) +{ + int i; + + I_CalculateRes(SCREENWIDTH, SCREENHEIGHT); + + // set first three to standard values + for (i=0; i<3; i++) { + screens[i].width = SCREENWIDTH; + screens[i].height = SCREENHEIGHT; + screens[i].byte_pitch = SCREENPITCH; + screens[i].short_pitch = SCREENPITCH / V_GetModePixelDepth(VID_MODE16); + screens[i].int_pitch = SCREENPITCH / V_GetModePixelDepth(VID_MODE32); + } + + // statusbar + screens[4].width = SCREENWIDTH; + screens[4].height = (ST_SCALED_HEIGHT+1); + screens[4].byte_pitch = SCREENPITCH; + screens[4].short_pitch = SCREENPITCH / V_GetModePixelDepth(VID_MODE16); + screens[4].int_pitch = SCREENPITCH / V_GetModePixelDepth(VID_MODE32); + + lprintf(LO_INFO,"I_SetRes: Using resolution %dx%d\n", SCREENWIDTH, SCREENHEIGHT); +} + +void I_InitGraphics(void) +{ + char titlebuffer[2048]; + static int firsttime=1; + + if (firsttime) + { + firsttime = 0; + + atexit(I_ShutdownGraphics); + lprintf(LO_INFO, "I_InitGraphics: %dx%d\n", SCREENWIDTH, SCREENHEIGHT); + + /* Set the video mode */ + I_UpdateVideoMode(); + + /* Setup the window title */ + strcpy(titlebuffer,PACKAGE); + strcat(titlebuffer," "); + strcat(titlebuffer,VERSION); + printf("Title: %s\n", titlebuffer); + + /* Initialize the input system */ + I_InitInputs(); + } +} + +int I_GetModeFromString(const char *modestr) +{ + video_mode_t mode; + + + mode = VID_MODE8; + + return mode; +} + +void I_UpdateVideoMode(void) +{ + int init_flags; + int i; + video_mode_t mode; + + lprintf(LO_INFO, "I_UpdateVideoMode: %dx%d (%s)\n", SCREENWIDTH, SCREENHEIGHT, desired_fullscreen ? "fullscreen" : "nofullscreen"); + + mode = I_GetModeFromString(default_videomode); + if ((i=M_CheckParm("-vidmode")) && ipitch / V_GetModePixelDepth(VID_MODE16); + screens[0].int_pitch = SCREEN_WIDTH; // screen->pitch / V_GetModePixelDepth(VID_MODE32); + + + V_AllocScreens(); + + // Hide pointer while over this window + //SDL_ShowCursor(0); + + R_InitBuffer(SCREENWIDTH, SCREENHEIGHT); + +} diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..a972643 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,72 @@ +# +# automake Makefile.am for the PrBoom source directory +# +# +# Process this file with automake to produce Makefile.in +# +# + +SUBDIRS = SDL POSIX MAC + +gamesdir=$(prefix)/games +games_PROGRAMS = prboom prboom-game-server + +CFLAGS = @CFLAGS@ @SDL_CFLAGS@ + +prboom_game_server_SOURCES = d_server.c protocol.h +prboom_game_server_LDADD = POSIX/libposixdoom.a SDL/i_network.o @NET_LIBS@ @SDL_LIBS@ + +COMMON_SRC = \ + am_map.c g_game.c p_maputl.h r_plane.h \ + am_map.h g_game.h p_mobj.c r_demo.c r_segs.c \ + hu_lib.c lprintf.c p_mobj.h r_demo.h r_segs.h \ + hu_lib.h lprintf.h p_plats.c r_sky.c \ + d_deh.c hu_stuff.c m_argv.c p_pspr.c r_sky.h \ + d_deh.h hu_stuff.h m_argv.h p_pspr.h r_state.h \ + d_englsh.h i_joy.h m_bbox.c p_saveg.c r_things.c \ + d_event.h m_bbox.h p_saveg.h r_things.h \ + d_items.c i_network.h m_cheat.c p_setup.c s_sound.c \ + d_items.h i_sound.h m_cheat.h p_setup.h s_sound.h \ + d_main.c i_system.h m_fixed.h p_sight.c sounds.c \ + d_main.h i_video.h m_menu.c p_spec.c sounds.h \ + info.c m_menu.h p_spec.h st_lib.c \ + d_net.h info.h m_misc.c p_switch.c st_lib.h \ + d_player.h m_misc.h p_telept.c st_stuff.c \ + m_random.c p_tick.c st_stuff.h i_main.h \ + d_think.h m_random.h p_tick.h tables.c \ + d_ticcmd.h m_swap.h p_user.c tables.h \ + doomdata.h p_ceilng.c p_user.h v_video.c \ + doomdef.c p_doors.c protocol.h v_video.h \ + doomdef.h p_enemy.c r_bsp.c version.c \ + doomstat.c p_enemy.h r_bsp.h version.h \ + doomstat.h p_floor.c r_data.c w_wad.c \ + doomtype.h p_genlin.c r_data.h w_wad.h \ + dstrings.c p_inter.c r_defs.h wi_stuff.c \ + dstrings.h p_inter.h r_draw.c wi_stuff.h \ + f_finale.c p_lights.c r_draw.h z_bmalloc.c \ + f_finale.h p_map.c r_main.c z_bmalloc.h \ + f_wipe.c p_map.h r_main.h z_zone.c \ + f_wipe.h p_maputl.c r_plane.c z_zone.h \ + md5.c md5.h p_checksum.h p_checksum.c \ + r_patch.c r_patch.h r_fps.c r_fps.h \ + r_filter.c r_filter.h + +NET_CLIENT_SRC = d_client.c + +if BUILD_GL +USE_GL_SRC = gl_intern.h gl_main.c gl_struct.h gl_texture.c +else +USE_GL_SRC = +endif + +if WAD_MMAP +WAD_SRC = w_mmap.c +else +WAD_SRC = w_memcache.c +endif + +prboom_SOURCES = mmus2mid.c mmus2mid.h $(COMMON_SRC) $(NET_CLIENT_SRC) $(USE_GL_SRC) $(WAD_SRC) +prboom_LDADD = SDL/libsdldoom.a @MIXER_LIBS@ @NET_LIBS@ @SDL_LIBS@ @GL_LIBS@ @MATH_LIB@ + +EXTRA_DIST = \ + r_drawcolumn.inl r_drawflush.inl r_drawspan.inl r_drawcolpipeline.inl diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..511760b --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,736 @@ +# Makefile.in generated by automake 1.10 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# automake Makefile.am for the PrBoom source directory +# +# +# Process this file with automake to produce Makefile.in +# +# + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +games_PROGRAMS = prboom$(EXEEXT) prboom-game-server$(EXEEXT) +subdir = src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/autotools/ac_c_compile_flags.m4 \ + $(top_srcdir)/autotools/ac_cpu_optimisations.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(gamesdir)" +gamesPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(games_PROGRAMS) +am__prboom_SOURCES_DIST = mmus2mid.c mmus2mid.h am_map.c g_game.c \ + p_maputl.h r_plane.h am_map.h g_game.h p_mobj.c r_demo.c \ + r_segs.c hu_lib.c lprintf.c p_mobj.h r_demo.h r_segs.h \ + hu_lib.h lprintf.h p_plats.c r_sky.c d_deh.c hu_stuff.c \ + m_argv.c p_pspr.c r_sky.h d_deh.h hu_stuff.h m_argv.h p_pspr.h \ + r_state.h d_englsh.h i_joy.h m_bbox.c p_saveg.c r_things.c \ + d_event.h m_bbox.h p_saveg.h r_things.h d_items.c i_network.h \ + m_cheat.c p_setup.c s_sound.c d_items.h i_sound.h m_cheat.h \ + p_setup.h s_sound.h d_main.c i_system.h m_fixed.h p_sight.c \ + sounds.c d_main.h i_video.h m_menu.c p_spec.c sounds.h info.c \ + m_menu.h p_spec.h st_lib.c d_net.h info.h m_misc.c p_switch.c \ + st_lib.h d_player.h m_misc.h p_telept.c st_stuff.c m_random.c \ + p_tick.c st_stuff.h i_main.h d_think.h m_random.h p_tick.h \ + tables.c d_ticcmd.h m_swap.h p_user.c tables.h doomdata.h \ + p_ceilng.c p_user.h v_video.c doomdef.c p_doors.c protocol.h \ + v_video.h doomdef.h p_enemy.c r_bsp.c version.c doomstat.c \ + p_enemy.h r_bsp.h version.h doomstat.h p_floor.c r_data.c \ + w_wad.c doomtype.h p_genlin.c r_data.h w_wad.h dstrings.c \ + p_inter.c r_defs.h wi_stuff.c dstrings.h p_inter.h r_draw.c \ + wi_stuff.h f_finale.c p_lights.c r_draw.h z_bmalloc.c \ + f_finale.h p_map.c r_main.c z_bmalloc.h f_wipe.c p_map.h \ + r_main.h z_zone.c f_wipe.h p_maputl.c r_plane.c z_zone.h md5.c \ + md5.h p_checksum.h p_checksum.c r_patch.c r_patch.h r_fps.c \ + r_fps.h r_filter.c r_filter.h d_client.c gl_intern.h gl_main.c \ + gl_struct.h gl_texture.c w_memcache.c w_mmap.c +am__objects_1 = am_map.$(OBJEXT) g_game.$(OBJEXT) p_mobj.$(OBJEXT) \ + r_demo.$(OBJEXT) r_segs.$(OBJEXT) hu_lib.$(OBJEXT) \ + lprintf.$(OBJEXT) p_plats.$(OBJEXT) r_sky.$(OBJEXT) \ + d_deh.$(OBJEXT) hu_stuff.$(OBJEXT) m_argv.$(OBJEXT) \ + p_pspr.$(OBJEXT) m_bbox.$(OBJEXT) p_saveg.$(OBJEXT) \ + r_things.$(OBJEXT) d_items.$(OBJEXT) m_cheat.$(OBJEXT) \ + p_setup.$(OBJEXT) s_sound.$(OBJEXT) d_main.$(OBJEXT) \ + p_sight.$(OBJEXT) sounds.$(OBJEXT) m_menu.$(OBJEXT) \ + p_spec.$(OBJEXT) info.$(OBJEXT) st_lib.$(OBJEXT) \ + m_misc.$(OBJEXT) p_switch.$(OBJEXT) p_telept.$(OBJEXT) \ + st_stuff.$(OBJEXT) m_random.$(OBJEXT) p_tick.$(OBJEXT) \ + tables.$(OBJEXT) p_user.$(OBJEXT) p_ceilng.$(OBJEXT) \ + v_video.$(OBJEXT) doomdef.$(OBJEXT) p_doors.$(OBJEXT) \ + p_enemy.$(OBJEXT) r_bsp.$(OBJEXT) version.$(OBJEXT) \ + doomstat.$(OBJEXT) p_floor.$(OBJEXT) r_data.$(OBJEXT) \ + w_wad.$(OBJEXT) p_genlin.$(OBJEXT) dstrings.$(OBJEXT) \ + p_inter.$(OBJEXT) wi_stuff.$(OBJEXT) r_draw.$(OBJEXT) \ + f_finale.$(OBJEXT) p_lights.$(OBJEXT) z_bmalloc.$(OBJEXT) \ + p_map.$(OBJEXT) r_main.$(OBJEXT) f_wipe.$(OBJEXT) \ + z_zone.$(OBJEXT) p_maputl.$(OBJEXT) r_plane.$(OBJEXT) \ + md5.$(OBJEXT) p_checksum.$(OBJEXT) r_patch.$(OBJEXT) \ + r_fps.$(OBJEXT) r_filter.$(OBJEXT) +am__objects_2 = d_client.$(OBJEXT) +@BUILD_GL_TRUE@am__objects_3 = gl_main.$(OBJEXT) gl_texture.$(OBJEXT) +@WAD_MMAP_FALSE@am__objects_4 = w_memcache.$(OBJEXT) +@WAD_MMAP_TRUE@am__objects_4 = w_mmap.$(OBJEXT) +am_prboom_OBJECTS = mmus2mid.$(OBJEXT) $(am__objects_1) \ + $(am__objects_2) $(am__objects_3) $(am__objects_4) +prboom_OBJECTS = $(am_prboom_OBJECTS) +prboom_DEPENDENCIES = SDL/libsdldoom.a +am_prboom_game_server_OBJECTS = d_server.$(OBJEXT) +prboom_game_server_OBJECTS = $(am_prboom_game_server_OBJECTS) +prboom_game_server_DEPENDENCIES = POSIX/libposixdoom.a SDL/i_network.o +DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/autotools/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(prboom_SOURCES) $(prboom_game_server_SOURCES) +DIST_SOURCES = $(am__prboom_SOURCES_DIST) \ + $(prboom_game_server_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ @SDL_CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DOOMWADDIR = @DOOMWADDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GL_LIBS = @GL_LIBS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MATH_LIB = @MATH_LIB@ +MIXER_CFLAGS = @MIXER_CFLAGS@ +MIXER_LIBS = @MIXER_LIBS@ +MKDIR_P = @MKDIR_P@ +NET_CFLAGS = @NET_CFLAGS@ +NET_LIBS = @NET_LIBS@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SDL_CFLAGS = @SDL_CFLAGS@ +SDL_CONFIG = @SDL_CONFIG@ +SDL_LIBS = @SDL_LIBS@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = SDL POSIX MAC +gamesdir = $(prefix)/games +prboom_game_server_SOURCES = d_server.c protocol.h +prboom_game_server_LDADD = POSIX/libposixdoom.a SDL/i_network.o @NET_LIBS@ @SDL_LIBS@ +COMMON_SRC = \ + am_map.c g_game.c p_maputl.h r_plane.h \ + am_map.h g_game.h p_mobj.c r_demo.c r_segs.c \ + hu_lib.c lprintf.c p_mobj.h r_demo.h r_segs.h \ + hu_lib.h lprintf.h p_plats.c r_sky.c \ + d_deh.c hu_stuff.c m_argv.c p_pspr.c r_sky.h \ + d_deh.h hu_stuff.h m_argv.h p_pspr.h r_state.h \ + d_englsh.h i_joy.h m_bbox.c p_saveg.c r_things.c \ + d_event.h m_bbox.h p_saveg.h r_things.h \ + d_items.c i_network.h m_cheat.c p_setup.c s_sound.c \ + d_items.h i_sound.h m_cheat.h p_setup.h s_sound.h \ + d_main.c i_system.h m_fixed.h p_sight.c sounds.c \ + d_main.h i_video.h m_menu.c p_spec.c sounds.h \ + info.c m_menu.h p_spec.h st_lib.c \ + d_net.h info.h m_misc.c p_switch.c st_lib.h \ + d_player.h m_misc.h p_telept.c st_stuff.c \ + m_random.c p_tick.c st_stuff.h i_main.h \ + d_think.h m_random.h p_tick.h tables.c \ + d_ticcmd.h m_swap.h p_user.c tables.h \ + doomdata.h p_ceilng.c p_user.h v_video.c \ + doomdef.c p_doors.c protocol.h v_video.h \ + doomdef.h p_enemy.c r_bsp.c version.c \ + doomstat.c p_enemy.h r_bsp.h version.h \ + doomstat.h p_floor.c r_data.c w_wad.c \ + doomtype.h p_genlin.c r_data.h w_wad.h \ + dstrings.c p_inter.c r_defs.h wi_stuff.c \ + dstrings.h p_inter.h r_draw.c wi_stuff.h \ + f_finale.c p_lights.c r_draw.h z_bmalloc.c \ + f_finale.h p_map.c r_main.c z_bmalloc.h \ + f_wipe.c p_map.h r_main.h z_zone.c \ + f_wipe.h p_maputl.c r_plane.c z_zone.h \ + md5.c md5.h p_checksum.h p_checksum.c \ + r_patch.c r_patch.h r_fps.c r_fps.h \ + r_filter.c r_filter.h + +NET_CLIENT_SRC = d_client.c +@BUILD_GL_FALSE@USE_GL_SRC = +@BUILD_GL_TRUE@USE_GL_SRC = gl_intern.h gl_main.c gl_struct.h gl_texture.c +@WAD_MMAP_FALSE@WAD_SRC = w_memcache.c +@WAD_MMAP_TRUE@WAD_SRC = w_mmap.c +prboom_SOURCES = mmus2mid.c mmus2mid.h $(COMMON_SRC) $(NET_CLIENT_SRC) $(USE_GL_SRC) $(WAD_SRC) +prboom_LDADD = SDL/libsdldoom.a @MIXER_LIBS@ @NET_LIBS@ @SDL_LIBS@ @GL_LIBS@ @MATH_LIB@ +EXTRA_DIST = \ + r_drawcolumn.inl r_drawflush.inl r_drawspan.inl r_drawcolpipeline.inl + +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-gamesPROGRAMS: $(games_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(gamesdir)" || $(MKDIR_P) "$(DESTDIR)$(gamesdir)" + @list='$(games_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(gamesPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(gamesdir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(gamesPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(gamesdir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-gamesPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(games_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(gamesdir)/$$f'"; \ + rm -f "$(DESTDIR)$(gamesdir)/$$f"; \ + done + +clean-gamesPROGRAMS: + -test -z "$(games_PROGRAMS)" || rm -f $(games_PROGRAMS) +prboom$(EXEEXT): $(prboom_OBJECTS) $(prboom_DEPENDENCIES) + @rm -f prboom$(EXEEXT) + $(LINK) $(prboom_OBJECTS) $(prboom_LDADD) $(LIBS) +prboom-game-server$(EXEEXT): $(prboom_game_server_OBJECTS) $(prboom_game_server_DEPENDENCIES) + @rm -f prboom-game-server$(EXEEXT) + $(LINK) $(prboom_game_server_OBJECTS) $(prboom_game_server_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/am_map.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/d_client.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/d_deh.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/d_items.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/d_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/d_server.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doomdef.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doomstat.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dstrings.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/f_finale.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/f_wipe.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/g_game.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gl_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gl_texture.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hu_lib.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hu_stuff.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/info.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lprintf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_argv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_bbox.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_cheat.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_menu.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_misc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_random.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mmus2mid.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_ceilng.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_checksum.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_doors.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_enemy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_floor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_genlin.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_inter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_lights.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_map.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_maputl.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_mobj.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_plats.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_pspr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_saveg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_setup.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_sight.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_spec.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_switch.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_telept.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_tick.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/p_user.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_bsp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_data.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_demo.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_draw.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_filter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_fps.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_patch.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_plane.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_segs.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_sky.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r_things.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_sound.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sounds.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/st_lib.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/st_stuff.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tables.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/v_video.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w_memcache.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w_mmap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w_wad.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wi_stuff.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/z_bmalloc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/z_zone.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(PROGRAMS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(gamesdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-gamesPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: install-gamesPROGRAMS + +install-dvi: install-dvi-recursive + +install-exec-am: + +install-html: install-html-recursive + +install-info: install-info-recursive + +install-man: + +install-pdf: install-pdf-recursive + +install-ps: install-ps-recursive + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-gamesPROGRAMS + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \ + install-strip + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-gamesPROGRAMS \ + clean-generic ctags ctags-recursive distclean \ + distclean-compile distclean-generic distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-gamesPROGRAMS \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-gamesPROGRAMS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/am_map.c b/src/am_map.c new file mode 100644 index 0000000..040c40b --- /dev/null +++ b/src/am_map.c @@ -0,0 +1,1585 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * the automap code + * + *----------------------------------------------------------------------------- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "doomstat.h" +#include "st_stuff.h" +#include "r_main.h" +#include "p_setup.h" +#include "p_maputl.h" +#include "w_wad.h" +#include "v_video.h" +#include "p_spec.h" +#include "am_map.h" +#include "dstrings.h" +#include "d_deh.h" // Ty 03/27/98 - externalizations +#include "lprintf.h" // jff 08/03/98 - declaration of lprintf +#include "g_game.h" + +//jff 1/7/98 default automap colors added +int mapcolor_back; // map background +int mapcolor_grid; // grid lines color +int mapcolor_wall; // normal 1s wall color +int mapcolor_fchg; // line at floor height change color +int mapcolor_cchg; // line at ceiling height change color +int mapcolor_clsd; // line at sector with floor=ceiling color +int mapcolor_rkey; // red key color +int mapcolor_bkey; // blue key color +int mapcolor_ykey; // yellow key color +int mapcolor_rdor; // red door color (diff from keys to allow option) +int mapcolor_bdor; // blue door color (of enabling one but not other ) +int mapcolor_ydor; // yellow door color +int mapcolor_tele; // teleporter line color +int mapcolor_secr; // secret sector boundary color +int mapcolor_exit; // jff 4/23/98 add exit line color +int mapcolor_unsn; // computer map unseen line color +int mapcolor_flat; // line with no floor/ceiling changes +int mapcolor_sprt; // general sprite color +int mapcolor_item; // item sprite color +int mapcolor_frnd; // friendly sprite color +int mapcolor_enemy; // enemy sprite color +int mapcolor_hair; // crosshair color +int mapcolor_sngl; // single player arrow color +int mapcolor_plyr[4] = { 112, 88, 64, 32 }; // colors for player arrows in multiplayer + +//jff 3/9/98 add option to not show secret sectors until entered +int map_secret_after; +//jff 4/3/98 add symbols for "no-color" for disable and "black color" for black +#define NC 0 +#define BC 247 + +// drawing stuff +#define FB 0 + +// scale on entry +#define INITSCALEMTOF (.2*FRACUNIT) +// how much the automap moves window per tic in frame-buffer coordinates +// moves 140 pixels in 1 second +#define F_PANINC 4 +// how much zoom-in per tic +// goes to 2x in 1 second +#define M_ZOOMIN ((int) (1.02*FRACUNIT)) +// how much zoom-out per tic +// pulls out to 0.5x in 1 second +#define M_ZOOMOUT ((int) (FRACUNIT/1.02)) + +#define PLAYERRADIUS (16*(1<>16) +// translates between frame-buffer and map coordinates +#define CXMTOF(x) (f_x + MTOF((x)-m_x)) +#define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y))) + +typedef struct +{ + mpoint_t a, b; +} mline_t; + +// +// The vector graphics for the automap. +// A line drawing of the player pointing right, +// starting from the middle. +// +#define R ((8*PLAYERRADIUS)/7) +mline_t player_arrow[] = +{ + { { -R+R/8, 0 }, { R, 0 } }, // ----- + { { R, 0 }, { R-R/2, R/4 } }, // -----> + { { R, 0 }, { R-R/2, -R/4 } }, + { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> + { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, + { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> + { { -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[] = +{ // killough 3/22/98: He's alive, Jim :) + { { -R+R/8, 0 }, { R, 0 } }, // ----- + { { R, 0 }, { R-R/2, R/4 } }, // -----> + { { R, 0 }, { R-R/2, -R/4 } }, + { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> + { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, + { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> + { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }, + { { -R/10-R/6, R/4}, {-R/10-R/6, -R/4} }, // J + { { -R/10-R/6, -R/4}, {-R/10-R/6-R/8, -R/4} }, + { { -R/10-R/6-R/8, -R/4}, {-R/10-R/6-R/8, -R/8} }, + { { -R/10, R/4}, {-R/10, -R/4}}, // F + { { -R/10, R/4}, {-R/10+R/8, R/4}}, + { { -R/10+R/4, R/4}, {-R/10+R/4, -R/4}}, // F + { { -R/10+R/4, R/4}, {-R/10+R/4+R/8, R/4}}, +}; +#undef R +#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t)) + +#define R (FRACUNIT) +mline_t triangle_guy[] = +{ +{ { (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)) + +//jff 1/5/98 new symbol for keys on automap +#define R (FRACUNIT) +mline_t cross_mark[] = +{ + { { -R, 0 }, { R, 0} }, + { { 0, -R }, { 0, R } }, +}; +#undef R +#define NUMCROSSMARKLINES (sizeof(cross_mark)/sizeof(mline_t)) +//jff 1/5/98 end of new symbol + +#define R (FRACUNIT) +mline_t thintriangle_guy[] = +{ +{ { (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)) + +int ddt_cheating = 0; // killough 2/7/98: make global, rename to ddt_* + +static int leveljuststarted = 1; // kluge until AM_LevelInit() is called + +enum automapmode_e automapmode; // Mode that the automap is in + +// location of window on screen +static int f_x; +static int f_y; + +// size of window on screen +static int f_w; +static int f_h; + +static mpoint_t m_paninc; // how far the window pans each tic (map coords) +static fixed_t mtof_zoommul; // how far the window zooms each tic (map coords) +static fixed_t ftom_zoommul; // how far the window zooms each tic (fb coords) + +static fixed_t m_x, m_y; // LL x,y window location on the map (map coords) +static fixed_t m_x2, m_y2; // UR x,y window location on the map (map coords) + +// +// width/height of window on map (map coords) +// +static fixed_t m_w; +static fixed_t m_h; + +// based on level size +static fixed_t min_x; +static fixed_t min_y; +static fixed_t max_x; +static fixed_t max_y; + +static fixed_t max_w; // max_x-min_x, +static fixed_t max_h; // max_y-min_y + +// based on player size +static fixed_t min_w; +static fixed_t min_h; + + +static fixed_t min_scale_mtof; // used to tell when to stop zooming out +static fixed_t max_scale_mtof; // used to tell when to stop zooming in + +// old stuff for recovery later +static fixed_t old_m_w, old_m_h; +static fixed_t old_m_x, old_m_y; + +// old location used by the Follower routine +static mpoint_t f_oldloc; + +// used by MTOF to scale from map-to-frame-buffer coords +static fixed_t scale_mtof = (fixed_t)INITSCALEMTOF; +// used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof) +static fixed_t scale_ftom; + +static player_t *plr; // the player represented by an arrow + +// killough 2/22/98: Remove limit on automap marks, +// and make variables external for use in savegames. + +mpoint_t *markpoints = NULL; // where the points are +int markpointnum = 0; // next point to be assigned (also number of points now) +int markpointnum_max = 0; // killough 2/22/98 + +static boolean stopped = true; + +// +// AM_activateNewScale() +// +// Changes the map scale after zooming or translating +// +// Passed nothing, returns nothing +// +static void AM_activateNewScale(void) +{ + m_x += m_w/2; + m_y += m_h/2; + m_w = FTOM(f_w); + m_h = FTOM(f_h); + m_x -= m_w/2; + m_y -= m_h/2; + m_x2 = m_x + m_w; + m_y2 = m_y + m_h; +} + +// +// AM_saveScaleAndLoc() +// +// Saves the current center and zoom +// Affects the variables that remember old scale and loc +// +// Passed nothing, returns nothing +// +static void AM_saveScaleAndLoc(void) +{ + old_m_x = m_x; + old_m_y = m_y; + old_m_w = m_w; + old_m_h = m_h; +} + +// +// AM_restoreScaleAndLoc() +// +// restores the center and zoom from locally saved values +// Affects global variables for location and scale +// +// Passed nothing, returns nothing +// +static void AM_restoreScaleAndLoc(void) +{ + m_w = old_m_w; + m_h = old_m_h; + if (!(automapmode & am_follow)) + { + m_x = old_m_x; + m_y = old_m_y; + } + else + { + m_x = (plr->mo->x >> FRACTOMAPBITS) - m_w/2;//e6y + m_y = (plr->mo->y >> FRACTOMAPBITS) - m_h/2;//e6y + } + m_x2 = m_x + m_w; + m_y2 = m_y + m_h; + + // Change the scaling multipliers + scale_mtof = FixedDiv(f_w<= markpointnum_max) + markpoints = realloc(markpoints, + (markpointnum_max = markpointnum_max ? + markpointnum_max*2 : 16) * sizeof(*markpoints)); + + markpoints[markpointnum].x = m_x + m_w/2; + markpoints[markpointnum].y = m_y + m_h/2; + markpointnum++; +} + +// +// AM_findMinMaxBoundaries() +// +// Determines bounding box of all vertices, +// sets global variables controlling zoom range. +// +// Passed nothing, returns nothing +// +static void AM_findMinMaxBoundaries(void) +{ + int i; + fixed_t a; + fixed_t b; + + min_x = min_y = INT_MAX; + max_x = max_y = -INT_MAX; + + for (i=0;i max_x) + max_x = vertexes[i].x; + + if (vertexes[i].y < min_y) + min_y = vertexes[i].y; + else if (vertexes[i].y > max_y) + max_y = vertexes[i].y; + } + + max_w = (max_x >>= FRACTOMAPBITS) - (min_x >>= FRACTOMAPBITS);//e6y + max_h = (max_y >>= FRACTOMAPBITS) - (min_y >>= FRACTOMAPBITS);//e6y + + min_w = 2*PLAYERRADIUS; // const? never changed? + min_h = 2*PLAYERRADIUS; + + a = FixedDiv(f_w< max_x) + m_x = max_x - m_w/2; + else if (m_x + m_w/2 < min_x) + m_x = min_x - m_w/2; + + if (m_y + m_h/2 > max_y) + m_y = max_y - m_h/2; + else if (m_y + m_h/2 < min_y) + m_y = min_y - m_h/2; + + m_x2 = m_x + m_w; + m_y2 = m_y + m_h; +} + + +// +// AM_initVariables() +// +// Initialize the variables for the automap +// +// Affects the automap global variables +// Status bar is notified that the automap has been entered +// Passed nothing, returns nothing +// +static void AM_initVariables(void) +{ + int pnum; + static event_t st_notify = { ev_keyup, AM_MSGENTERED, 0, 0 }; + + automapmode |= am_active; + + f_oldloc.x = INT_MAX; + + m_paninc.x = m_paninc.y = 0; + ftom_zoommul = FRACUNIT; + mtof_zoommul = FRACUNIT; + + m_w = FTOM(f_w); + m_h = FTOM(f_h); + + // find player to center on initially + if (!playeringame[pnum = consoleplayer]) + for (pnum=0;pnummo->x >> FRACTOMAPBITS) - m_w/2;//e6y + m_y = (plr->mo->y >> FRACTOMAPBITS) - m_h/2;//e6y + AM_changeWindowLoc(); + + // for saving & restoring + old_m_x = m_x; + old_m_y = m_y; + old_m_w = m_w; + old_m_h = m_h; + + // inform the status bar of the change + ST_Responder(&st_notify); +} + +// +// AM_loadPics() +// +static void AM_loadPics(void) +{ + // cph - mark numbers no longer needed cached +} + +// +// AM_unloadPics() +// +static void AM_unloadPics(void) +{ + // cph - mark numbers no longer needed cached +} + +// +// AM_clearMarks() +// +// Sets the number of marks to 0, thereby clearing them from the display +// +// Affects the global variable markpointnum +// Passed nothing, returns nothing +// +void AM_clearMarks(void) +{ + markpointnum = 0; +} + +// +// AM_LevelInit() +// +// Initialize the automap at the start of a new level +// should be called at the start of every level +// +// Passed nothing, returns nothing +// Affects automap's global variables +// +// CPhipps - get status bar height from status bar code +static void AM_LevelInit(void) +{ + leveljuststarted = 0; + + f_x = f_y = 0; + f_w = SCREENWIDTH; // killough 2/7/98: get rid of finit_ vars + f_h = SCREENHEIGHT-ST_SCALED_HEIGHT;// to allow runtime setting of width/height + + AM_findMinMaxBoundaries(); + scale_mtof = FixedDiv(min_scale_mtof, (int) (0.7*FRACUNIT)); + if (scale_mtof > max_scale_mtof) + scale_mtof = min_scale_mtof; + scale_ftom = FixedDiv(FRACUNIT, scale_mtof); +} + +// +// AM_Stop() +// +// Cease automap operations, unload patches, notify status bar +// +// Passed nothing, returns nothing +// +void AM_Stop (void) +{ + static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED, 0 }; + + AM_unloadPics(); + automapmode &= ~am_active; + ST_Responder(&st_notify); + stopped = true; +} + +// +// AM_Start() +// +// Start up automap operations, +// if a new level, or game start, (re)initialize level variables +// init map variables +// load mark patches +// +// Passed nothing, returns nothing +// +void AM_Start(void) +{ + static int lastlevel = -1, lastepisode = -1; + + if (!stopped) + AM_Stop(); + stopped = false; + if (lastlevel != gamemap || lastepisode != gameepisode) + { + AM_LevelInit(); + lastlevel = gamemap; + lastepisode = gameepisode; + } + AM_initVariables(); + AM_loadPics(); +} + +// +// AM_minOutWindowScale() +// +// Set the window scale to the maximum size +// +// Passed nothing, returns nothing +// +static void AM_minOutWindowScale(void) +{ + scale_mtof = min_scale_mtof; + scale_ftom = FixedDiv(FRACUNIT, scale_mtof); + AM_activateNewScale(); +} + +// +// AM_maxOutWindowScale(void) +// +// Set the window scale to the minimum size +// +// Passed nothing, returns nothing +// +static void AM_maxOutWindowScale(void) +{ + scale_mtof = max_scale_mtof; + scale_ftom = FixedDiv(FRACUNIT, scale_mtof); + AM_activateNewScale(); +} + +// +// AM_Responder() +// +// Handle events (user inputs) in automap mode +// +// Passed an input event, returns true if its handled +// +boolean AM_Responder +( event_t* ev ) +{ + int rc; + static int cheatstate=0; + static int bigstate=0; + int ch; // phares + + rc = false; + + if (!(automapmode & am_active)) + { + if (ev->type == ev_keydown && ev->data1 == key_map) // phares + { + AM_Start (); + rc = true; + } + } + else if (ev->type == ev_keydown) + { + rc = true; + ch = ev->data1; // phares + if (ch == key_map_right) // | + if (!(automapmode & am_follow)) // V + m_paninc.x = FTOM(F_PANINC); + else + rc = false; + else if (ch == key_map_left) + if (!(automapmode & am_follow)) + m_paninc.x = -FTOM(F_PANINC); + else + rc = false; + else if (ch == key_map_up) + if (!(automapmode & am_follow)) + m_paninc.y = FTOM(F_PANINC); + else + rc = false; + else if (ch == key_map_down) + if (!(automapmode & am_follow)) + m_paninc.y = -FTOM(F_PANINC); + else + rc = false; + else if (ch == key_map_zoomout) + { + mtof_zoommul = M_ZOOMOUT; + ftom_zoommul = M_ZOOMIN; + } + else if (ch == key_map_zoomin) + { + mtof_zoommul = M_ZOOMIN; + ftom_zoommul = M_ZOOMOUT; + } + else if (ch == key_map) + { + bigstate = 0; + AM_Stop (); + } + else if (ch == key_map_gobig) + { + bigstate = !bigstate; + if (bigstate) + { + AM_saveScaleAndLoc(); + AM_minOutWindowScale(); + } + else + AM_restoreScaleAndLoc(); + } + else if (ch == key_map_follow) + { + automapmode ^= am_follow; // CPhipps - put all automap mode stuff into one enum + f_oldloc.x = INT_MAX; + // Ty 03/27/98 - externalized + plr->message = (automapmode & am_follow) ? s_AMSTR_FOLLOWON : s_AMSTR_FOLLOWOFF; + } + else if (ch == key_map_grid) + { + automapmode ^= am_grid; // CPhipps + // Ty 03/27/98 - *not* externalized + plr->message = (automapmode & am_grid) ? s_AMSTR_GRIDON : s_AMSTR_GRIDOFF; + } + else if (ch == key_map_mark) + { + /* Ty 03/27/98 - *not* externalized + * cph 2001/11/20 - use doom_printf so we don't have our own buffer */ + doom_printf("%s %d", s_AMSTR_MARKEDSPOT, markpointnum); + AM_addMark(); + } + else if (ch == key_map_clear) + { + AM_clearMarks(); // Ty 03/27/98 - *not* externalized + plr->message = s_AMSTR_MARKSCLEARED; // ^ + } // | + else if (ch == key_map_rotate) { + automapmode ^= am_rotate; + plr->message = (automapmode & am_rotate) ? s_AMSTR_ROTATEON : s_AMSTR_ROTATEOFF; + } + else if (ch == key_map_overlay) { + automapmode ^= am_overlay; + plr->message = (automapmode & am_overlay) ? s_AMSTR_OVERLAYON : s_AMSTR_OVERLAYOFF; + } + else // phares + { + cheatstate=0; + rc = false; + } + } + else if (ev->type == ev_keyup) + { + rc = false; + ch = ev->data1; + if (ch == key_map_right) + { + if (!(automapmode & am_follow)) + m_paninc.x = 0; + } + else if (ch == key_map_left) + { + if (!(automapmode & am_follow)) + m_paninc.x = 0; + } + else if (ch == key_map_up) + { + if (!(automapmode & am_follow)) + m_paninc.y = 0; + } + else if (ch == key_map_down) + { + if (!(automapmode & am_follow)) + m_paninc.y = 0; + } + else if ((ch == key_map_zoomout) || (ch == key_map_zoomin)) + { + mtof_zoommul = FRACUNIT; + ftom_zoommul = FRACUNIT; + } + } + return rc; +} + +// +// AM_rotate() +// +// Rotation in 2D. +// Used to rotate player arrow line character. +// +// Passed the coordinates of a point, and an angle +// Returns the coordinates rotated by the angle +// +// CPhipps - made static & enhanced for automap rotation + +static void AM_rotate(fixed_t* x, fixed_t* y, angle_t a, fixed_t xorig, fixed_t yorig) +{ + fixed_t tmpx; + + //e6y + xorig>>=FRACTOMAPBITS; + yorig>>=FRACTOMAPBITS; + + tmpx = + FixedMul(*x - xorig,finecosine[a>>ANGLETOFINESHIFT]) + - FixedMul(*y - yorig,finesine[a>>ANGLETOFINESHIFT]); + + *y = yorig + + FixedMul(*x - xorig,finesine[a>>ANGLETOFINESHIFT]) + + FixedMul(*y - yorig,finecosine[a>>ANGLETOFINESHIFT]); + + *x = tmpx + xorig; +} + +// +// AM_changeWindowScale() +// +// Automap zooming +// +// Passed nothing, returns nothing +// +static void AM_changeWindowScale(void) +{ + // Change the scaling multipliers + scale_mtof = FixedMul(scale_mtof, mtof_zoommul); + scale_ftom = FixedDiv(FRACUNIT, scale_mtof); + + if (scale_mtof < min_scale_mtof) + AM_minOutWindowScale(); + else if (scale_mtof > max_scale_mtof) + AM_maxOutWindowScale(); + else + AM_activateNewScale(); +} + +// +// AM_doFollowPlayer() +// +// Turn on follow mode - the map scrolls opposite to player motion +// +// Passed nothing, returns nothing +// +static void AM_doFollowPlayer(void) +{ + if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y) + { + m_x = FTOM(MTOF(plr->mo->x >> FRACTOMAPBITS)) - m_w/2;//e6y + m_y = FTOM(MTOF(plr->mo->y >> FRACTOMAPBITS)) - m_h/2;//e6y + m_x2 = m_x + m_w; + m_y2 = m_y + m_h; + f_oldloc.x = plr->mo->x; + f_oldloc.y = plr->mo->y; + } +} + +// +// AM_Ticker() +// +// Updates on gametic - enter follow mode, zoom, or change map location +// +// Passed nothing, returns nothing +// +void AM_Ticker (void) +{ + if (!(automapmode & am_active)) + return; + + if (automapmode & am_follow) + AM_doFollowPlayer(); + + // Change the zoom if necessary + if (ftom_zoommul != FRACUNIT) + AM_changeWindowScale(); + + // Change x,y location + if (m_paninc.x || m_paninc.y) + AM_changeWindowLoc(); +} + +// +// AM_clipMline() +// +// Automap clipping of lines. +// +// Based on Cohen-Sutherland clipping algorithm but with a slightly +// faster reject and precalculated slopes. If the speed is needed, +// use a hash algorithm to handle the common cases. +// +// Passed the line's coordinates on map and in the frame buffer performs +// clipping on them in the lines frame coordinates. +// Returns true if any part of line was not clipped +// +static boolean AM_clipMline +( mline_t* ml, + fline_t* fl ) +{ + enum + { + LEFT =1, + RIGHT =2, + BOTTOM =4, + TOP =8 + }; + + register int outcode1 = 0; + register int outcode2 = 0; + register int outside; + + fpoint_t tmp; + int dx; + int dy; + + +#define DOOUTCODE(oc, mx, my) \ + (oc) = 0; \ + if ((my) < 0) (oc) |= TOP; \ + else if ((my) >= f_h) (oc) |= BOTTOM; \ + if ((mx) < 0) (oc) |= LEFT; \ + else if ((mx) >= f_w) (oc) |= RIGHT; + + + // do trivial rejects and outcodes + if (ml->a.y > m_y2) + outcode1 = TOP; + else if (ml->a.y < m_y) + outcode1 = BOTTOM; + + if (ml->b.y > m_y2) + outcode2 = TOP; + else if (ml->b.y < m_y) + outcode2 = BOTTOM; + + if (outcode1 & outcode2) + return false; // trivially outside + + if (ml->a.x < m_x) + outcode1 |= LEFT; + else if (ml->a.x > m_x2) + outcode1 |= RIGHT; + + if (ml->b.x < m_x) + outcode2 |= LEFT; + else if (ml->b.x > m_x2) + outcode2 |= RIGHT; + + if (outcode1 & outcode2) + return false; // trivially outside + + // transform to frame-buffer coordinates. + fl->a.x = CXMTOF(ml->a.x); + fl->a.y = CYMTOF(ml->a.y); + fl->b.x = CXMTOF(ml->b.x); + fl->b.y = CYMTOF(ml->b.y); + + DOOUTCODE(outcode1, fl->a.x, fl->a.y); + DOOUTCODE(outcode2, fl->b.x, fl->b.y); + + if (outcode1 & outcode2) + return false; + + while (outcode1 | outcode2) + { + // may be partially inside box + // find an outside point + if (outcode1) + outside = outcode1; + else + outside = outcode2; + + // clip to each side + if (outside & TOP) + { + dy = fl->a.y - fl->b.y; + dx = fl->b.x - fl->a.x; + tmp.x = fl->a.x + (dx*(fl->a.y))/dy; + tmp.y = 0; + } + else if (outside & BOTTOM) + { + dy = fl->a.y - fl->b.y; + dx = fl->b.x - fl->a.x; + tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy; + tmp.y = f_h-1; + } + else if (outside & RIGHT) + { + dy = fl->b.y - fl->a.y; + dx = fl->b.x - fl->a.x; + tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx; + tmp.x = f_w-1; + } + else if (outside & LEFT) + { + dy = fl->b.y - fl->a.y; + dx = fl->b.x - fl->a.x; + tmp.y = fl->a.y + (dy*(-fl->a.x))/dx; + tmp.x = 0; + } + + if (outside == outcode1) + { + fl->a = tmp; + DOOUTCODE(outcode1, fl->a.x, fl->a.y); + } + else + { + fl->b = tmp; + DOOUTCODE(outcode2, fl->b.x, fl->b.y); + } + + if (outcode1 & outcode2) + return false; // trivially outside + } + + return true; +} +#undef DOOUTCODE + +// +// AM_drawMline() +// +// Clip lines, draw visible parts of lines. +// +// Passed the map coordinates of the line, and the color to draw it +// Color -1 is special and prevents drawing. Color 247 is special and +// is translated to black, allowing Color 0 to represent feature disable +// in the defaults file. +// Returns nothing. +// +static void AM_drawMline +( mline_t* ml, + int color ) +{ + static fline_t fl; + + if (color==-1) // jff 4/3/98 allow not drawing any sort of line + return; // by setting its color to -1 + if (color==247) // jff 4/3/98 if color is 247 (xparent), use black + color=0; + + if (AM_clipMline(ml, &fl)) + V_DrawLine(&fl, color); // draws it on frame buffer using fb coords +} + +// +// AM_drawGrid() +// +// Draws blockmap aligned grid lines. +// +// Passed the color to draw the grid lines +// Returns nothing +// +static void AM_drawGrid(int color) +{ + fixed_t x, y; + fixed_t start, end; + mline_t ml; + + // Figure out start of vertical gridlines + start = m_x; + if ((start-bmaporgx)%(MAPBLOCKUNITS<> LockedKeyShift; + if (!type || type==7) + return 3; //any or all keys + else return (type-1)%3; + } + switch (type) // closed keyed door + { + case 26: case 32: case 99: case 133: + /*bluekey*/ + return 1; + case 27: case 34: case 136: case 137: + /*yellowkey*/ + return 2; + case 28: case 33: case 134: case 135: + /*redkey*/ + return 0; + default: + return -1; //not a keyed door + } +} + +// +// Determines visible lines, draws them. +// This is LineDef based, not LineSeg based. +// +// jff 1/5/98 many changes in this routine +// backward compatibility not needed, so just changes, no ifs +// addition of clauses for: +// doors opening, keyed door id, secret sectors, +// teleports, exit lines, key things +// ability to suppress any of added features or lines with no height changes +// +// support for gamma correction in automap abandoned +// +// jff 4/3/98 changed mapcolor_xxxx=0 as control to disable feature +// jff 4/3/98 changed mapcolor_xxxx=-1 to disable drawing line completely +// +static void AM_drawWalls(void) +{ + int i; + static mline_t l; + + // draw the unclipped visible portions of all lines + for (i=0;ix >> FRACTOMAPBITS;//e6y + l.a.y = lines[i].v1->y >> FRACTOMAPBITS;//e6y + l.b.x = lines[i].v2->x >> FRACTOMAPBITS;//e6y + l.b.y = lines[i].v2->y >> FRACTOMAPBITS;//e6y + + if (automapmode & am_rotate) { + AM_rotate(&l.a.x, &l.a.y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y); + AM_rotate(&l.b.x, &l.b.y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y); + } + + // if line has been seen or IDDT has been used + if (ddt_cheating || (lines[i].flags & ML_MAPPED)) + { + if ((lines[i].flags & ML_DONTDRAW) && !ddt_cheating) + continue; + { + /* cph - show keyed doors and lines */ + int amd; + if ((mapcolor_bdor || mapcolor_ydor || mapcolor_rdor) && + !(lines[i].flags & ML_SECRET) && /* non-secret */ + (amd = AM_DoorColor(lines[i].special)) != -1 + ) + { + { + switch (amd) /* closed keyed door */ + { + case 1: + /*bluekey*/ + AM_drawMline(&l, + mapcolor_bdor? mapcolor_bdor : mapcolor_cchg); + continue; + case 2: + /*yellowkey*/ + AM_drawMline(&l, + mapcolor_ydor? mapcolor_ydor : mapcolor_cchg); + continue; + case 0: + /*redkey*/ + AM_drawMline(&l, + mapcolor_rdor? mapcolor_rdor : mapcolor_cchg); + continue; + case 3: + /*any or all*/ + AM_drawMline(&l, + mapcolor_clsd? mapcolor_clsd : mapcolor_cchg); + continue; + } + } + } + } + if /* jff 4/23/98 add exit lines to automap */ + ( + mapcolor_exit && + ( + lines[i].special==11 || + lines[i].special==52 || + lines[i].special==197 || + lines[i].special==51 || + lines[i].special==124 || + lines[i].special==198 + ) + ) { + AM_drawMline(&l, mapcolor_exit); /* exit line */ + continue; + } + + if (!lines[i].backsector) + { + // jff 1/10/98 add new color for 1S secret sector boundary + if (mapcolor_secr && //jff 4/3/98 0 is disable + ( + ( + map_secret_after && + P_WasSecret(lines[i].frontsector) && + !P_IsSecret(lines[i].frontsector) + ) + || + ( + !map_secret_after && + P_WasSecret(lines[i].frontsector) + ) + ) + ) + AM_drawMline(&l, mapcolor_secr); // line bounding secret sector + else //jff 2/16/98 fixed bug + AM_drawMline(&l, mapcolor_wall); // special was cleared + } + else /* now for 2S lines */ + { + // jff 1/10/98 add color change for all teleporter types + if + ( + mapcolor_tele && !(lines[i].flags & ML_SECRET) && + (lines[i].special == 39 || lines[i].special == 97 || + lines[i].special == 125 || lines[i].special == 126) + ) + { // teleporters + AM_drawMline(&l, mapcolor_tele); + } + else if (lines[i].flags & ML_SECRET) // secret door + { + AM_drawMline(&l, mapcolor_wall); // wall color + } + else if + ( + mapcolor_clsd && + !(lines[i].flags & ML_SECRET) && // non-secret closed door + ((lines[i].backsector->floorheight==lines[i].backsector->ceilingheight) || + (lines[i].frontsector->floorheight==lines[i].frontsector->ceilingheight)) + ) + { + AM_drawMline(&l, mapcolor_clsd); // non-secret closed door + } //jff 1/6/98 show secret sector 2S lines + else if + ( + mapcolor_secr && //jff 2/16/98 fixed bug + ( // special was cleared after getting it + (map_secret_after && + ( + (P_WasSecret(lines[i].frontsector) + && !P_IsSecret(lines[i].frontsector)) || + (P_WasSecret(lines[i].backsector) + && !P_IsSecret(lines[i].backsector)) + ) + ) + || //jff 3/9/98 add logic to not show secret til after entered + ( // if map_secret_after is true + !map_secret_after && + (P_WasSecret(lines[i].frontsector) || + P_WasSecret(lines[i].backsector)) + ) + ) + ) + { + AM_drawMline(&l, mapcolor_secr); // line bounding secret sector + } //jff 1/6/98 end secret sector line change + else if (lines[i].backsector->floorheight != + lines[i].frontsector->floorheight) + { + AM_drawMline(&l, mapcolor_fchg); // floor level change + } + else if (lines[i].backsector->ceilingheight != + lines[i].frontsector->ceilingheight) + { + AM_drawMline(&l, mapcolor_cchg); // ceiling level change + } + else if (mapcolor_flat && ddt_cheating) + { + AM_drawMline(&l, mapcolor_flat); //2S lines that appear only in IDDT + } + } + } // now draw the lines only visible because the player has computermap + else if (plr->powers[pw_allmap]) // computermap visible lines + { + if (!(lines[i].flags & ML_DONTDRAW)) // invisible flag lines do not show + { + if + ( + mapcolor_flat + || + !lines[i].backsector + || + lines[i].backsector->floorheight + != lines[i].frontsector->floorheight + || + lines[i].backsector->ceilingheight + != lines[i].frontsector->ceilingheight + ) + AM_drawMline(&l, mapcolor_unsn); + } + } + } +} + +// +// AM_drawLineCharacter() +// +// Draws a vector graphic according to numerous parameters +// +// Passed the structure defining the vector graphic shape, the number +// of vectors in it, the scale to draw it at, the angle to draw it at, +// the color to draw it with, and the map coordinates to draw it at. +// Returns nothing +// +static void AM_drawLineCharacter +( mline_t* lineguy, + int lineguylines, + fixed_t scale, + angle_t angle, + int color, + fixed_t x, + fixed_t y ) +{ + int i; + mline_t l; + + if (automapmode & am_rotate) angle -= plr->mo->angle - ANG90; // cph + + for (i=0;imo->angle, + mapcolor_sngl, //jff color + plr->mo->x >> FRACTOMAPBITS,//e6y + plr->mo->y >> FRACTOMAPBITS//e6y + ); + else + AM_drawLineCharacter + ( + player_arrow, + NUMPLYRLINES, + 0, + plr->mo->angle, + mapcolor_sngl, //jff color + plr->mo->x >> FRACTOMAPBITS,//e6y + plr->mo->y >> FRACTOMAPBITS);//e6y + return; + } + + for (i=0;imo->x >> FRACTOMAPBITS, y = p->mo->y >> FRACTOMAPBITS;//e6y + if (automapmode & am_rotate) + AM_rotate(&x, &y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y); + + AM_drawLineCharacter (player_arrow, NUMPLYRLINES, 0, p->mo->angle, + p->powers[pw_invisibility] ? 246 /* *close* to black */ + : mapcolor_plyr[i], //jff 1/6/98 use default color + x, y); + } + } +} + +// +// AM_drawThings() +// +// Draws the things on the automap in double IDDT cheat mode +// +// Passed colors and colorrange, no longer used +// Returns nothing +// +static void AM_drawThings(void) +{ + int i; + mobj_t* t; + + // for all sectors + for (i=0;ix >> FRACTOMAPBITS, y = t->y >> FRACTOMAPBITS;//e6y + + if (automapmode & am_rotate) + AM_rotate(&x, &y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y); + + //jff 1/5/98 case over doomednum of thing being drawn + if (mapcolor_rkey || mapcolor_ykey || mapcolor_bkey) + { + switch(t->info->doomednum) + { + //jff 1/5/98 treat keys special + case 38: case 13: //jff red key + AM_drawLineCharacter + ( + cross_mark, + NUMCROSSMARKLINES, + 16<angle, + mapcolor_rkey!=-1? mapcolor_rkey : mapcolor_sprt, + x, y + ); + t = t->snext; + continue; + case 39: case 6: //jff yellow key + AM_drawLineCharacter + ( + cross_mark, + NUMCROSSMARKLINES, + 16<angle, + mapcolor_ykey!=-1? mapcolor_ykey : mapcolor_sprt, + x, y + ); + t = t->snext; + continue; + case 40: case 5: //jff blue key + AM_drawLineCharacter + ( + cross_mark, + NUMCROSSMARKLINES, + 16<angle, + mapcolor_bkey!=-1? mapcolor_bkey : mapcolor_sprt, + x, y + ); + t = t->snext; + continue; + default: + break; + } + } + //jff 1/5/98 end added code for keys + //jff previously entire code + AM_drawLineCharacter + ( + thintriangle_guy, + NUMTHINTRIANGLEGUYLINES, + 16<angle, + t->flags & MF_FRIEND && !t->player ? mapcolor_frnd : + /* cph 2006/07/30 - Show count-as-kills in red. */ + ((t->flags & (MF_COUNTKILL | MF_CORPSE)) == MF_COUNTKILL) ? mapcolor_enemy : + /* bbm 2/28/03 Show countable items in yellow. */ + t->flags & MF_COUNTITEM ? mapcolor_item : mapcolor_sprt, + x, y + ); + t = t->snext; + } + } +} + +// +// AM_drawMarks() +// +// Draw the marked locations on the automap +// +// Passed nothing, returns nothing +// +// killough 2/22/98: +// Rewrote AM_drawMarks(). Removed limit on marks. +// +static void AM_drawMarks(void) +{ + int i; + for (i=0;imo->angle, plr->mo->x, plr->mo->y); + + fx = CXMTOF(fx); fy = CYMTOF(fy); + + do + { + int d = j % 10; + if (d==1) // killough 2/22/98: less spacing for '1' + fx++; + + if (fx >= f_x && fx < f_w - w && fy >= f_y && fy < f_h - h) { + // cph - construct patch name and draw marker + char namebuf[] = { 'A', 'M', 'M', 'N', 'U', 'M', '0'+d, 0 }; + + V_DrawNamePatch(fx, fy, FB, namebuf, CR_DEFAULT, VPT_NONE); + } + fx -= w-1; // killough 2/22/98: 1 space backwards + j /= 10; + } + while (j>0); + } +} + +// +// AM_drawCrosshair() +// +// Draw the single point crosshair representing map center +// +// Passed the color to draw the pixel with +// Returns nothing +// +// CPhipps - made static inline, and use the general pixel plotter function + +inline static void AM_drawCrosshair(int color) +{ + fline_t line; + + line.a.x = (f_w/2)-1; + line.a.y = (f_h/2); + line.b.x = (f_w/2)+1; + line.b.y = (f_h/2); + V_DrawLine(&line, color); + + line.a.x = (f_w/2); + line.a.y = (f_h/2)-1; + line.b.x = (f_w/2); + line.b.y = (f_h/2)+1; + V_DrawLine(&line, color); +} + +// +// AM_Drawer() +// +// Draws the entire automap +// +// Passed nothing, returns nothing +// +void AM_Drawer (void) +{ + // CPhipps - all automap modes put into one enum + if (!(automapmode & am_active)) return; + + if (!(automapmode & am_overlay)) // cph - If not overlay mode, clear background for the automap + V_FillRect(FB, f_x, f_y, f_w, f_h, (byte)mapcolor_back); //jff 1/5/98 background default color + if (automapmode & am_grid) + AM_drawGrid(mapcolor_grid); //jff 1/7/98 grid default color + AM_drawWalls(); + AM_drawPlayers(); + if (ddt_cheating==2) + AM_drawThings(); //jff 1/5/98 default double IDDT sprite + AM_drawCrosshair(mapcolor_hair); //jff 1/7/98 default crosshair color + + AM_drawMarks(); +} diff --git a/src/am_map.h b/src/am_map.h new file mode 100644 index 0000000..850c9ce --- /dev/null +++ b/src/am_map.h @@ -0,0 +1,111 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * AutoMap module. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __AMMAP_H__ +#define __AMMAP_H__ + +#include "d_event.h" + +#define MAPBITS 12 +#define FRACTOMAPBITS (FRACBITS-MAPBITS) + +// Used by ST StatusBar stuff. +#define AM_MSGHEADER (('a'<<24)+('m'<<16)) +#define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8)) +#define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8)) + +// Called by main loop. +boolean AM_Responder (event_t* ev); + +// Called by main loop. +void AM_Ticker (void); + +// Called by main loop, +// called instead of view drawer if automap active. +void AM_Drawer (void); + +// Called to force the automap to quit +// if the level is completed while it is up. +void AM_Stop (void); + +// killough 2/22/98: for saving automap information in savegame: + +extern void AM_Start(void); + +//jff 4/16/98 make externally available + +extern void AM_clearMarks(void); + +typedef struct +{ + fixed_t x,y; +} mpoint_t; + +extern mpoint_t *markpoints; +extern int markpointnum, markpointnum_max; + +// end changes -- killough 2/22/98 + +// killough 5/2/98: moved from m_misc.c + +//jff 1/7/98 automap colors added +extern int mapcolor_back; // map background +extern int mapcolor_grid; // grid lines color +extern int mapcolor_wall; // normal 1s wall color +extern int mapcolor_fchg; // line at floor height change color +extern int mapcolor_cchg; // line at ceiling height change color +extern int mapcolor_clsd; // line at sector with floor=ceiling color +extern int mapcolor_rkey; // red key color +extern int mapcolor_bkey; // blue key color +extern int mapcolor_ykey; // yellow key color +extern int mapcolor_rdor; // red door color (diff from keys to allow option) +extern int mapcolor_bdor; // blue door color (of enabling one not other) +extern int mapcolor_ydor; // yellow door color +extern int mapcolor_tele; // teleporter line color +extern int mapcolor_secr; // secret sector boundary color +//jff 4/23/98 +extern int mapcolor_exit; // exit line +extern int mapcolor_unsn; // computer map unseen line color +extern int mapcolor_flat; // line with no floor/ceiling changes +extern int mapcolor_sprt; // general sprite color +extern int mapcolor_item; // item sprite color +extern int mapcolor_enemy; // enemy sprite color +extern int mapcolor_frnd; // friendly sprite color +extern int mapcolor_hair; // crosshair color +extern int mapcolor_sngl; // single player arrow color +extern int mapcolor_plyr[4]; // colors for players in multiplayer +extern int mapcolor_me; // consoleplayer's chosen colour +//jff 3/9/98 +extern int map_secret_after; // secrets do not appear til after bagged + +#endif diff --git a/src/d_client.c b/src/d_client.c new file mode 100644 index 0000000..dd09720 --- /dev/null +++ b/src/d_client.c @@ -0,0 +1,539 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Network client. Passes information to/from server, staying + * synchronised. + * Contains the main wait loop, waiting for network input or + * time before doing the next tic. + * Rewritten for LxDoom, but based around bits of the old code. + * + *----------------------------------------------------------------------------- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +#ifdef USE_SDL_NET + #include "SDL.h" +#endif + +#include "doomtype.h" +#include "doomstat.h" +#include "d_net.h" +#include "z_zone.h" + +#include "d_main.h" +#include "g_game.h" +#include "m_menu.h" +#include "p_checksum.h" + +#include "protocol.h" +#include "i_network.h" +#include "i_system.h" +#include "i_main.h" +#include "i_video.h" +#include "m_argv.h" +#include "r_fps.h" +#include "lprintf.h" + +static boolean server; +static int remotetic; // Tic expected from the remote +static int remotesend; // Tic expected by the remote +ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; +static ticcmd_t* localcmds; +static unsigned numqueuedpackets; +static packet_header_t** queuedpacket; +int maketic; +int ticdup = 1; +static int xtratics = 0; +int wanted_player_number; + +static boolean isExtraDDisplay = false; + +static void D_QuitNetGame (void); + +#ifndef HAVE_NET +doomcom_t* doomcom; +#endif + +#ifdef HAVE_NET +void D_InitNetGame (void) +{ + int i; + int numplayers = 1; + + i = M_CheckParm("-net"); + if (i && i < myargc-1) i++; + + if (!(netgame = server = !!i)) { + playeringame[consoleplayer = 0] = true; + // e6y + // for play, recording or playback using "single-player coop" mode. + // Equivalent to using prboom_server with -N 1 + netgame = M_CheckParm("-solo-net"); + } else { + // Get game info from server + packet_header_t *packet = Z_Malloc(1000, PU_STATIC, NULL); + struct setup_packet_s *sinfo = (void*)(packet+1); + struct { packet_header_t head; short pn; } PACKEDATTR initpacket; + + I_InitNetwork(); + udp_socket = I_Socket(0); + I_ConnectToServer(myargv[i]); + + do + { + do { + // Send init packet + initpacket.pn = doom_htons(wanted_player_number); + packet_set(&initpacket.head, PKT_INIT, 0); + I_SendPacket(&initpacket.head, sizeof(initpacket)); + I_WaitForPacket(5000); + } while (!I_GetPacket(packet, 1000)); + if (packet->type == PKT_DOWN) I_Error("Server aborted the game"); + } while (packet->type != PKT_SETUP); + + // Once we have been accepted by the server, we should tell it when we leave + atexit(D_QuitNetGame); + + // Get info from the setup packet + consoleplayer = sinfo->yourplayer; + compatibility_level = sinfo->complevel; + G_Compatibility(); + startskill = sinfo->skill; + deathmatch = sinfo->deathmatch; + startmap = sinfo->level; + startepisode = sinfo->episode; + ticdup = sinfo->ticdup; + xtratics = sinfo->extratic; + G_ReadOptions(sinfo->game_options); + + lprintf(LO_INFO, "\tjoined game as player %d/%d; %d WADs specified\n", + consoleplayer+1, numplayers = sinfo->players, sinfo->numwads); + { + char *p = sinfo->wadnames; + int i = sinfo->numwads; + + while (i--) { + D_AddFile(p, source_net); + p += strlen(p) + 1; + } + } + Z_Free(packet); + } + localcmds = netcmds[displayplayer = consoleplayer]; + for (i=0; iconsoleplayer = 0; + doomcom->numnodes = 0; doomcom->numplayers = 1; + localcmds = netcmds[consoleplayer]; + netgame = (M_CheckParm("-solo-net") != 0); + + for (i=0; inumplayers; i++) + playeringame[i] = true; + for (; iconsoleplayer; +} +#endif // HAVE_NET + +#ifdef HAVE_NET +void D_CheckNetGame(void) +{ + packet_header_t *packet = Z_Malloc(sizeof(packet_header_t)+1, PU_STATIC, NULL); + + if (server) { + lprintf(LO_INFO, "D_CheckNetGame: waiting for server to signal game start\n"); + do { + while (!I_GetPacket(packet, sizeof(packet_header_t)+1)) { + packet_set(packet, PKT_GO, 0); + *(byte*)(packet+1) = consoleplayer; + I_SendPacket(packet, sizeof(packet_header_t)+1); + I_uSleep(100000); + } + } while (packet->type != PKT_GO); + } + Z_Free(packet); +} + +boolean D_NetGetWad(const char* name) +{ +#if defined(HAVE_WAIT_H) + size_t psize = sizeof(packet_header_t) + strlen(name) + 500; + packet_header_t *packet; + boolean done = false; + + if (!server || strchr(name, '/')) return false; // If it contains path info, reject + + do { + // Send WAD request to remote + packet = Z_Malloc(psize, PU_STATIC, NULL); + packet_set(packet, PKT_WAD, 0); + *(byte*)(packet+1) = consoleplayer; + strcpy(1+(byte*)(packet+1), name); + I_SendPacket(packet, sizeof(packet_header_t) + strlen(name) + 2); + + I_uSleep(10000); + } while (!I_GetPacket(packet, psize) || (packet->type != PKT_WAD)); + Z_Free(packet); + + if (!strcasecmp((void*)(packet+1), name)) { + pid_t pid; + int rv; + byte *p = (byte*)(packet+1) + strlen(name) + 1; + + /* Automatic wad file retrieval using wget (supports http and ftp, using URLs) + * Unix systems have all these commands handy, this kind of thing is easy + * Any windo$e port will have some awkward work replacing these. + */ + /* cph - caution here. This is data from an untrusted source. + * Don't pass it via a shell. */ + if ((pid = fork()) == -1) + perror("fork"); + else if (!pid) { + /* Child chains to wget, does the download */ + execlp("wget", "wget", p, NULL); + } + /* This is the parent, i.e. main LxDoom process */ + wait(&rv); + if (!(done = !access(name, R_OK))) { + if (!strcmp(p+strlen(p)-4, ".zip")) { + p = strrchr(p, '/')+1; + if ((pid = fork()) == -1) + perror("fork"); + else if (!pid) { + /* Child executes decompressor */ + execlp("unzip", "unzip", p, name, NULL); + } + /* Parent waits for the file */ + wait(&rv); + done = !!access(name, R_OK); + } + /* Add more decompression protocols here as desired */ + } + Z_Free(buffer); + } + return done; +#else /* HAVE_WAIT_H */ + return false; +#endif +} + +void NetUpdate(void) +{ + static int lastmadetic; + if (isExtraDDisplay) + return; + if (server) { // Receive network packets + size_t recvlen; + packet_header_t *packet = Z_Malloc(10000, PU_STATIC, NULL); + while ((recvlen = I_GetPacket(packet, 10000))) { + switch(packet->type) { + case PKT_TICS: + { + byte *p = (void*)(packet+1); + int tics = *p++; + unsigned long ptic = doom_ntohl(packet->tic); + if (ptic > (unsigned)remotetic) { // Missed some + packet_set(packet, PKT_RETRANS, remotetic); + *(byte*)(packet+1) = consoleplayer; + I_SendPacket(packet, sizeof(*packet)+1); + } else { + if (ptic + tics <= (unsigned)remotetic) break; // Will not improve things + remotetic = ptic; + while (tics--) { + int players = *p++; + while (players--) { + int n = *p++; + RawToTic(&netcmds[n][remotetic%BACKUPTICS], p); + p += sizeof(ticcmd_t); + } + remotetic++; + } + } + } + break; + case PKT_RETRANS: // Resend request + remotesend = doom_ntohl(packet->tic); + break; + case PKT_DOWN: // Server downed + { + int j; + for (j=0; j 0 ? newtics : 0); + lastmadetic += newtics; + if (ffmap) newtics++; + while (newtics--) { + I_StartTic(); + if (maketic - gametic > BACKUPTICS/2) break; + G_BuildTiccmd(&localcmds[maketic%BACKUPTICS]); + maketic++; + } + if (server && maketic > remotesend) { // Send the tics to the server + int sendtics; + remotesend -= xtratics; + if (remotesend < 0) remotesend = 0; + sendtics = maketic - remotesend; + { + size_t pkt_size = sizeof(packet_header_t) + 2 + sendtics * sizeof(ticcmd_t); + packet_header_t *packet = Z_Malloc(pkt_size, PU_STATIC, NULL); + + packet_set(packet, PKT_TICC, maketic - sendtics); + *(byte*)(packet+1) = sendtics; + *(((byte*)(packet+1))+1) = consoleplayer; + { + void *tic = ((byte*)(packet+1)) +2; + while (sendtics--) { + TicToRaw(tic, &localcmds[remotesend++%BACKUPTICS]); + tic = (byte *)tic + sizeof(ticcmd_t); + } + } + I_SendPacket(packet, pkt_size); + Z_Free(packet); + } + } + } +} +#else + +void D_BuildNewTiccmds(void) +{ + static int lastmadetic; + int newtics = I_GetTime() - lastmadetic; + lastmadetic += newtics; + while (newtics--) + { + I_StartTic(); + if (maketic - gametic > BACKUPTICS/2) break; + G_BuildTiccmd(&localcmds[maketic%BACKUPTICS]); + maketic++; + } +} +#endif + +#ifdef HAVE_NET +/* cph - data passed to this must be in the Doom (little-) endian */ +void D_NetSendMisc(netmisctype_t type, size_t len, void* data) +{ + if (server) { + size_t size = sizeof(packet_header_t) + 3*sizeof(int) + len; + packet_header_t *packet = Z_Malloc(size, PU_STATIC, NULL); + int *p = (void*)(packet+1); + + packet_set(packet, PKT_EXTRA, gametic); + *p++ = LONG(type); *p++ = LONG(consoleplayer); *p++ = LONG(len); + memcpy(p, data, len); + I_SendPacket(packet, size); + + Z_Free(packet); + } +} + +static void CheckQueuedPackets(void) +{ + int i; + for (i=0; (unsigned)itic) <= gametic) + switch (queuedpacket[i]->type) { + case PKT_QUIT: // Player quit the game + { + int pn = *(byte*)(queuedpacket[i]+1); + playeringame[pn] = false; + doom_printf("Player %d left the game\n", pn); + } + break; + case PKT_EXTRA: + { + int *p = (int*)(queuedpacket[i]+1); + size_t len = LONG(*(p+2)); + switch (LONG(*p)) { + case nm_plcolour: + G_ChangedPlayerColour(LONG(*(p+1)), LONG(*(p+3))); + break; + case nm_savegamename: + if (len < SAVEDESCLEN) { + memcpy(savedescription, p+3, len); + // Force terminating 0 in case + savedescription[len] = 0; + } + break; + } + } + break; + default: // Should not be queued + break; + } + + { // Requeue remaining packets + int newnum = 0; + packet_header_t **newqueue = NULL; + + for (i=0; (unsigned)itic) > gametic) { + newqueue = Z_Realloc(newqueue, ++newnum * sizeof *newqueue, + PU_STATIC, NULL); + newqueue[newnum-1] = queuedpacket[i]; + } else Z_Free(queuedpacket[i]); + + Z_Free(queuedpacket); + numqueuedpackets = newnum; queuedpacket = newqueue; + } +} +#endif // HAVE_NET + +void TryRunTics (void) +{ + int runtics; + int entertime = I_GetTime(); + + // Wait for tics to run + while (1) { +#ifdef HAVE_NET + NetUpdate(); +#else + D_BuildNewTiccmds(); +#endif + runtics = (server ? remotetic : maketic) - gametic; + if (!runtics) { + if (!movement_smooth) { +#ifdef HAVE_NET + if (server) + I_WaitForPacket(ms_to_next_tick); + else +#endif + I_uSleep(ms_to_next_tick*1000); + } + if (I_GetTime() - entertime > 10) { +#ifdef HAVE_NET + if (server) { + char buf[sizeof(packet_header_t)+1]; + remotesend--; + packet_set((packet_header_t *)buf, PKT_RETRANS, remotetic); + buf[sizeof(buf)-1] = consoleplayer; + I_SendPacket((packet_header_t *)buf, sizeof buf); + } +#endif + M_Ticker(); return; + } + //if ((displaytime) < (tic_vars.next-SDL_GetTicks())) + { + WasRenderedInTryRunTics = true; + if (V_GetMode() == VID_MODEGL ? + movement_smooth : + movement_smooth && gamestate==wipegamestate) + { + isExtraDDisplay = true; + D_Display(); + isExtraDDisplay = false; + } + } + } else break; + } + + while (runtics--) { +#ifdef HAVE_NET + if (server) CheckQueuedPackets(); +#endif + if (advancedemo) + D_DoAdvanceDemo (); + M_Ticker (); + I_GetTime_SaveMS(); + G_Ticker (); + P_Checksum(gametic); + gametic++; +#ifdef HAVE_NET + NetUpdate(); // Keep sending our tics to avoid stalling remote nodes +#endif + } +} + +#ifdef HAVE_NET +static void D_QuitNetGame (void) +{ + byte buf[1 + sizeof(packet_header_t)]; + packet_header_t *packet = (void*)buf; + int i; + + if (!server) return; + buf[sizeof(packet_header_t)] = consoleplayer; + packet_set(packet, PKT_QUIT, gametic); + + for (i=0; i<4; i++) { + I_SendPacket(packet, 1 + sizeof(packet_header_t)); + I_uSleep(10000); + } +} +#endif diff --git a/src/d_deh.c b/src/d_deh.c new file mode 100644 index 0000000..b3790f5 --- /dev/null +++ b/src/d_deh.c @@ -0,0 +1,3090 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2004 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Dehacked file support + * New for the TeamTNT "Boom" engine + * + * Author: Ty Halderman, TeamTNT + * + *--------------------------------------------------------------------*/ + +// killough 5/2/98: fixed headers, removed rendunant external declarations: +#include "doomdef.h" +#include "doomtype.h" +#include "doomstat.h" +#include "d_deh.h" +#include "sounds.h" +#include "info.h" +#include "m_cheat.h" +#include "p_inter.h" +#include "p_enemy.h" +#include "g_game.h" +#include "d_think.h" +#include "w_wad.h" + +// CPhipps - modify to use logical output routine +#include "lprintf.h" + +#define TRUE 1 +#define FALSE 0 + +#ifndef HAVE_STRLWR +#include + +static char* strlwr(char* str) +{ + char* p; + for (p=str; *p; p++) *p = tolower(*p); + return str; +} +#endif + +// killough 10/98: new functions, to allow processing DEH files in-memory +// (e.g. from wads) + +typedef struct { + /* cph 2006/08/06 - + * if lump != NULL, lump is the start of the lump, + * inp is the current read pos. */ + const byte *inp, *lump; + long size; + /* else, !lump, and f is the file being read */ + FILE* f; +} DEHFILE; + +// killough 10/98: emulate IO whether input really comes from a file or not + +static char *dehfgets(char *buf, size_t n, DEHFILE *fp) +{ + if (!fp->lump) // If this is a real file, + return (fgets)(buf, n, fp->f); // return regular fgets + if (!n || !*fp->inp || fp->size<=0) // If no more characters + return NULL; + if (n==1) + fp->size--, *buf = *fp->inp++; + else + { // copy buffer + char *p = buf; + while (n>1 && *fp->inp && fp->size && + (n--, fp->size--, *p++ = *fp->inp++) != '\n') + ; + *p = 0; + } + return buf; // Return buffer pointer +} + +static int dehfeof(DEHFILE *fp) +{ + return !fp->lump ? feof(fp->f) : !*fp->inp || fp->size<=0; +} + +static int dehfgetc(DEHFILE *fp) +{ + return !fp->lump ? fgetc(fp->f) : fp->size > 0 ? + fp->size--, *fp->inp++ : EOF; +} + +// haleyjd 9/22/99 +int HelperThing = -1; // in P_SpawnMapThing to substitute helper thing + +// variables used in other routines +boolean deh_pars = FALSE; // in wi_stuff to allow pars in modified games + +// #include "d_deh.h" -- we don't do that here but we declare the +// variables. This externalizes everything that there is a string +// set for in the language files. See d_deh.h for detailed comments, +// original English values etc. These are set to the macro values, +// which are set by D_ENGLSH.H or D_FRENCH.H(etc). BEX files are a +// better way of changing these strings globally by language. + +// ==================================================================== +// Any of these can be changed using the bex extensions +#include "dstrings.h" // to get the initial values +/* cph - const's + * - removed redundant "can't XXX in a netgame" strings. + */ +const char *s_D_DEVSTR = D_DEVSTR; +const char *s_D_CDROM = D_CDROM; +const char *s_PRESSKEY = PRESSKEY; +const char *s_PRESSYN = PRESSYN; +const char *s_QUITMSG = QUITMSG; +const char *s_QSAVESPOT = QSAVESPOT; // PRESSKEY; +const char *s_SAVEDEAD = SAVEDEAD; // PRESSKEY; // remove duplicate y/n +const char *s_QSPROMPT = QSPROMPT; // PRESSYN; +const char *s_QLPROMPT = QLPROMPT; // PRESSYN; +const char *s_NEWGAME = NEWGAME; // PRESSKEY; +const char *s_RESTARTLEVEL= RESTARTLEVEL; // PRESSYN; +const char *s_NIGHTMARE = NIGHTMARE; // PRESSYN; +const char *s_SWSTRING = SWSTRING; // PRESSKEY; +const char *s_MSGOFF = MSGOFF; +const char *s_MSGON = MSGON; +const char *s_NETEND = NETEND; // PRESSKEY; +const char *s_ENDGAME = ENDGAME; // PRESSYN; // killough 4/4/98: end +const char *s_DOSY = DOSY; +const char *s_DETAILHI = DETAILHI; +const char *s_DETAILLO = DETAILLO; +const char *s_GAMMALVL0 = GAMMALVL0; +const char *s_GAMMALVL1 = GAMMALVL1; +const char *s_GAMMALVL2 = GAMMALVL2; +const char *s_GAMMALVL3 = GAMMALVL3; +const char *s_GAMMALVL4 = GAMMALVL4; +const char *s_EMPTYSTRING = EMPTYSTRING; +const char *s_GOTARMOR = GOTARMOR; +const char *s_GOTMEGA = GOTMEGA; +const char *s_GOTHTHBONUS = GOTHTHBONUS; +const char *s_GOTARMBONUS = GOTARMBONUS; +const char *s_GOTSTIM = GOTSTIM; +const char *s_GOTMEDINEED = GOTMEDINEED; +const char *s_GOTMEDIKIT = GOTMEDIKIT; +const char *s_GOTSUPER = GOTSUPER; +const char *s_GOTBLUECARD = GOTBLUECARD; +const char *s_GOTYELWCARD = GOTYELWCARD; +const char *s_GOTREDCARD = GOTREDCARD; +const char *s_GOTBLUESKUL = GOTBLUESKUL; +const char *s_GOTYELWSKUL = GOTYELWSKUL; +const char *s_GOTREDSKULL = GOTREDSKULL; +const char *s_GOTINVUL = GOTINVUL; +const char *s_GOTBERSERK = GOTBERSERK; +const char *s_GOTINVIS = GOTINVIS; +const char *s_GOTSUIT = GOTSUIT; +const char *s_GOTMAP = GOTMAP; +const char *s_GOTVISOR = GOTVISOR; +const char *s_GOTMSPHERE = GOTMSPHERE; +const char *s_GOTCLIP = GOTCLIP; +const char *s_GOTCLIPBOX = GOTCLIPBOX; +const char *s_GOTROCKET = GOTROCKET; +const char *s_GOTROCKBOX = GOTROCKBOX; +const char *s_GOTCELL = GOTCELL; +const char *s_GOTCELLBOX = GOTCELLBOX; +const char *s_GOTSHELLS = GOTSHELLS; +const char *s_GOTSHELLBOX = GOTSHELLBOX; +const char *s_GOTBACKPACK = GOTBACKPACK; +const char *s_GOTBFG9000 = GOTBFG9000; +const char *s_GOTCHAINGUN = GOTCHAINGUN; +const char *s_GOTCHAINSAW = GOTCHAINSAW; +const char *s_GOTLAUNCHER = GOTLAUNCHER; +const char *s_GOTPLASMA = GOTPLASMA; +const char *s_GOTSHOTGUN = GOTSHOTGUN; +const char *s_GOTSHOTGUN2 = GOTSHOTGUN2; +const char *s_PD_BLUEO = PD_BLUEO; +const char *s_PD_REDO = PD_REDO; +const char *s_PD_YELLOWO = PD_YELLOWO; +const char *s_PD_BLUEK = PD_BLUEK; +const char *s_PD_REDK = PD_REDK; +const char *s_PD_YELLOWK = PD_YELLOWK; +const char *s_PD_BLUEC = PD_BLUEC; +const char *s_PD_REDC = PD_REDC; +const char *s_PD_YELLOWC = PD_YELLOWC; +const char *s_PD_BLUES = PD_BLUES; +const char *s_PD_REDS = PD_REDS; +const char *s_PD_YELLOWS = PD_YELLOWS; +const char *s_PD_ANY = PD_ANY; +const char *s_PD_ALL3 = PD_ALL3; +const char *s_PD_ALL6 = PD_ALL6; +const char *s_GGSAVED = GGSAVED; +const char *s_HUSTR_MSGU = HUSTR_MSGU; +const char *s_HUSTR_E1M1 = HUSTR_E1M1; +const char *s_HUSTR_E1M2 = HUSTR_E1M2; +const char *s_HUSTR_E1M3 = HUSTR_E1M3; +const char *s_HUSTR_E1M4 = HUSTR_E1M4; +const char *s_HUSTR_E1M5 = HUSTR_E1M5; +const char *s_HUSTR_E1M6 = HUSTR_E1M6; +const char *s_HUSTR_E1M7 = HUSTR_E1M7; +const char *s_HUSTR_E1M8 = HUSTR_E1M8; +const char *s_HUSTR_E1M9 = HUSTR_E1M9; +const char *s_HUSTR_E2M1 = HUSTR_E2M1; +const char *s_HUSTR_E2M2 = HUSTR_E2M2; +const char *s_HUSTR_E2M3 = HUSTR_E2M3; +const char *s_HUSTR_E2M4 = HUSTR_E2M4; +const char *s_HUSTR_E2M5 = HUSTR_E2M5; +const char *s_HUSTR_E2M6 = HUSTR_E2M6; +const char *s_HUSTR_E2M7 = HUSTR_E2M7; +const char *s_HUSTR_E2M8 = HUSTR_E2M8; +const char *s_HUSTR_E2M9 = HUSTR_E2M9; +const char *s_HUSTR_E3M1 = HUSTR_E3M1; +const char *s_HUSTR_E3M2 = HUSTR_E3M2; +const char *s_HUSTR_E3M3 = HUSTR_E3M3; +const char *s_HUSTR_E3M4 = HUSTR_E3M4; +const char *s_HUSTR_E3M5 = HUSTR_E3M5; +const char *s_HUSTR_E3M6 = HUSTR_E3M6; +const char *s_HUSTR_E3M7 = HUSTR_E3M7; +const char *s_HUSTR_E3M8 = HUSTR_E3M8; +const char *s_HUSTR_E3M9 = HUSTR_E3M9; +const char *s_HUSTR_E4M1 = HUSTR_E4M1; +const char *s_HUSTR_E4M2 = HUSTR_E4M2; +const char *s_HUSTR_E4M3 = HUSTR_E4M3; +const char *s_HUSTR_E4M4 = HUSTR_E4M4; +const char *s_HUSTR_E4M5 = HUSTR_E4M5; +const char *s_HUSTR_E4M6 = HUSTR_E4M6; +const char *s_HUSTR_E4M7 = HUSTR_E4M7; +const char *s_HUSTR_E4M8 = HUSTR_E4M8; +const char *s_HUSTR_E4M9 = HUSTR_E4M9; +const char *s_HUSTR_1 = HUSTR_1; +const char *s_HUSTR_2 = HUSTR_2; +const char *s_HUSTR_3 = HUSTR_3; +const char *s_HUSTR_4 = HUSTR_4; +const char *s_HUSTR_5 = HUSTR_5; +const char *s_HUSTR_6 = HUSTR_6; +const char *s_HUSTR_7 = HUSTR_7; +const char *s_HUSTR_8 = HUSTR_8; +const char *s_HUSTR_9 = HUSTR_9; +const char *s_HUSTR_10 = HUSTR_10; +const char *s_HUSTR_11 = HUSTR_11; +const char *s_HUSTR_12 = HUSTR_12; +const char *s_HUSTR_13 = HUSTR_13; +const char *s_HUSTR_14 = HUSTR_14; +const char *s_HUSTR_15 = HUSTR_15; +const char *s_HUSTR_16 = HUSTR_16; +const char *s_HUSTR_17 = HUSTR_17; +const char *s_HUSTR_18 = HUSTR_18; +const char *s_HUSTR_19 = HUSTR_19; +const char *s_HUSTR_20 = HUSTR_20; +const char *s_HUSTR_21 = HUSTR_21; +const char *s_HUSTR_22 = HUSTR_22; +const char *s_HUSTR_23 = HUSTR_23; +const char *s_HUSTR_24 = HUSTR_24; +const char *s_HUSTR_25 = HUSTR_25; +const char *s_HUSTR_26 = HUSTR_26; +const char *s_HUSTR_27 = HUSTR_27; +const char *s_HUSTR_28 = HUSTR_28; +const char *s_HUSTR_29 = HUSTR_29; +const char *s_HUSTR_30 = HUSTR_30; +const char *s_HUSTR_31 = HUSTR_31; +const char *s_HUSTR_32 = HUSTR_32; +const char *s_PHUSTR_1 = PHUSTR_1; +const char *s_PHUSTR_2 = PHUSTR_2; +const char *s_PHUSTR_3 = PHUSTR_3; +const char *s_PHUSTR_4 = PHUSTR_4; +const char *s_PHUSTR_5 = PHUSTR_5; +const char *s_PHUSTR_6 = PHUSTR_6; +const char *s_PHUSTR_7 = PHUSTR_7; +const char *s_PHUSTR_8 = PHUSTR_8; +const char *s_PHUSTR_9 = PHUSTR_9; +const char *s_PHUSTR_10 = PHUSTR_10; +const char *s_PHUSTR_11 = PHUSTR_11; +const char *s_PHUSTR_12 = PHUSTR_12; +const char *s_PHUSTR_13 = PHUSTR_13; +const char *s_PHUSTR_14 = PHUSTR_14; +const char *s_PHUSTR_15 = PHUSTR_15; +const char *s_PHUSTR_16 = PHUSTR_16; +const char *s_PHUSTR_17 = PHUSTR_17; +const char *s_PHUSTR_18 = PHUSTR_18; +const char *s_PHUSTR_19 = PHUSTR_19; +const char *s_PHUSTR_20 = PHUSTR_20; +const char *s_PHUSTR_21 = PHUSTR_21; +const char *s_PHUSTR_22 = PHUSTR_22; +const char *s_PHUSTR_23 = PHUSTR_23; +const char *s_PHUSTR_24 = PHUSTR_24; +const char *s_PHUSTR_25 = PHUSTR_25; +const char *s_PHUSTR_26 = PHUSTR_26; +const char *s_PHUSTR_27 = PHUSTR_27; +const char *s_PHUSTR_28 = PHUSTR_28; +const char *s_PHUSTR_29 = PHUSTR_29; +const char *s_PHUSTR_30 = PHUSTR_30; +const char *s_PHUSTR_31 = PHUSTR_31; +const char *s_PHUSTR_32 = PHUSTR_32; +const char *s_THUSTR_1 = THUSTR_1; +const char *s_THUSTR_2 = THUSTR_2; +const char *s_THUSTR_3 = THUSTR_3; +const char *s_THUSTR_4 = THUSTR_4; +const char *s_THUSTR_5 = THUSTR_5; +const char *s_THUSTR_6 = THUSTR_6; +const char *s_THUSTR_7 = THUSTR_7; +const char *s_THUSTR_8 = THUSTR_8; +const char *s_THUSTR_9 = THUSTR_9; +const char *s_THUSTR_10 = THUSTR_10; +const char *s_THUSTR_11 = THUSTR_11; +const char *s_THUSTR_12 = THUSTR_12; +const char *s_THUSTR_13 = THUSTR_13; +const char *s_THUSTR_14 = THUSTR_14; +const char *s_THUSTR_15 = THUSTR_15; +const char *s_THUSTR_16 = THUSTR_16; +const char *s_THUSTR_17 = THUSTR_17; +const char *s_THUSTR_18 = THUSTR_18; +const char *s_THUSTR_19 = THUSTR_19; +const char *s_THUSTR_20 = THUSTR_20; +const char *s_THUSTR_21 = THUSTR_21; +const char *s_THUSTR_22 = THUSTR_22; +const char *s_THUSTR_23 = THUSTR_23; +const char *s_THUSTR_24 = THUSTR_24; +const char *s_THUSTR_25 = THUSTR_25; +const char *s_THUSTR_26 = THUSTR_26; +const char *s_THUSTR_27 = THUSTR_27; +const char *s_THUSTR_28 = THUSTR_28; +const char *s_THUSTR_29 = THUSTR_29; +const char *s_THUSTR_30 = THUSTR_30; +const char *s_THUSTR_31 = THUSTR_31; +const char *s_THUSTR_32 = THUSTR_32; +const char *s_HUSTR_CHATMACRO1 = HUSTR_CHATMACRO1; +const char *s_HUSTR_CHATMACRO2 = HUSTR_CHATMACRO2; +const char *s_HUSTR_CHATMACRO3 = HUSTR_CHATMACRO3; +const char *s_HUSTR_CHATMACRO4 = HUSTR_CHATMACRO4; +const char *s_HUSTR_CHATMACRO5 = HUSTR_CHATMACRO5; +const char *s_HUSTR_CHATMACRO6 = HUSTR_CHATMACRO6; +const char *s_HUSTR_CHATMACRO7 = HUSTR_CHATMACRO7; +const char *s_HUSTR_CHATMACRO8 = HUSTR_CHATMACRO8; +const char *s_HUSTR_CHATMACRO9 = HUSTR_CHATMACRO9; +const char *s_HUSTR_CHATMACRO0 = HUSTR_CHATMACRO0; +const char *s_HUSTR_TALKTOSELF1 = HUSTR_TALKTOSELF1; +const char *s_HUSTR_TALKTOSELF2 = HUSTR_TALKTOSELF2; +const char *s_HUSTR_TALKTOSELF3 = HUSTR_TALKTOSELF3; +const char *s_HUSTR_TALKTOSELF4 = HUSTR_TALKTOSELF4; +const char *s_HUSTR_TALKTOSELF5 = HUSTR_TALKTOSELF5; +const char *s_HUSTR_MESSAGESENT = HUSTR_MESSAGESENT; +const char *s_HUSTR_PLRGREEN = HUSTR_PLRGREEN; +const char *s_HUSTR_PLRINDIGO = HUSTR_PLRINDIGO; +const char *s_HUSTR_PLRBROWN = HUSTR_PLRBROWN; +const char *s_HUSTR_PLRRED = HUSTR_PLRRED; +const char *s_AMSTR_FOLLOWON = AMSTR_FOLLOWON; +const char *s_AMSTR_FOLLOWOFF = AMSTR_FOLLOWOFF; +const char *s_AMSTR_GRIDON = AMSTR_GRIDON; +const char *s_AMSTR_GRIDOFF = AMSTR_GRIDOFF; +const char *s_AMSTR_MARKEDSPOT = AMSTR_MARKEDSPOT; +const char *s_AMSTR_MARKSCLEARED = AMSTR_MARKSCLEARED; +// CPhipps - automap rotate & overlay +const char* s_AMSTR_ROTATEON = AMSTR_ROTATEON; +const char* s_AMSTR_ROTATEOFF = AMSTR_ROTATEOFF; +const char* s_AMSTR_OVERLAYON = AMSTR_OVERLAYON; +const char* s_AMSTR_OVERLAYOFF = AMSTR_OVERLAYOFF; +const char *s_STSTR_MUS = STSTR_MUS; +const char *s_STSTR_NOMUS = STSTR_NOMUS; +const char *s_STSTR_DQDON = STSTR_DQDON; +const char *s_STSTR_DQDOFF = STSTR_DQDOFF; +const char *s_STSTR_KFAADDED = STSTR_KFAADDED; +const char *s_STSTR_FAADDED = STSTR_FAADDED; +const char *s_STSTR_NCON = STSTR_NCON; +const char *s_STSTR_NCOFF = STSTR_NCOFF; +const char *s_STSTR_BEHOLD = STSTR_BEHOLD; +const char *s_STSTR_BEHOLDX = STSTR_BEHOLDX; +const char *s_STSTR_CHOPPERS = STSTR_CHOPPERS; +const char *s_STSTR_CLEV = STSTR_CLEV; +const char *s_STSTR_COMPON = STSTR_COMPON; +const char *s_STSTR_COMPOFF = STSTR_COMPOFF; +const char *s_E1TEXT = E1TEXT; +const char *s_E2TEXT = E2TEXT; +const char *s_E3TEXT = E3TEXT; +const char *s_E4TEXT = E4TEXT; +const char *s_C1TEXT = C1TEXT; +const char *s_C2TEXT = C2TEXT; +const char *s_C3TEXT = C3TEXT; +const char *s_C4TEXT = C4TEXT; +const char *s_C5TEXT = C5TEXT; +const char *s_C6TEXT = C6TEXT; +const char *s_P1TEXT = P1TEXT; +const char *s_P2TEXT = P2TEXT; +const char *s_P3TEXT = P3TEXT; +const char *s_P4TEXT = P4TEXT; +const char *s_P5TEXT = P5TEXT; +const char *s_P6TEXT = P6TEXT; +const char *s_T1TEXT = T1TEXT; +const char *s_T2TEXT = T2TEXT; +const char *s_T3TEXT = T3TEXT; +const char *s_T4TEXT = T4TEXT; +const char *s_T5TEXT = T5TEXT; +const char *s_T6TEXT = T6TEXT; +const char *s_CC_ZOMBIE = CC_ZOMBIE; +const char *s_CC_SHOTGUN = CC_SHOTGUN; +const char *s_CC_HEAVY = CC_HEAVY; +const char *s_CC_IMP = CC_IMP; +const char *s_CC_DEMON = CC_DEMON; +const char *s_CC_LOST = CC_LOST; +const char *s_CC_CACO = CC_CACO; +const char *s_CC_HELL = CC_HELL; +const char *s_CC_BARON = CC_BARON; +const char *s_CC_ARACH = CC_ARACH; +const char *s_CC_PAIN = CC_PAIN; +const char *s_CC_REVEN = CC_REVEN; +const char *s_CC_MANCU = CC_MANCU; +const char *s_CC_ARCH = CC_ARCH; +const char *s_CC_SPIDER = CC_SPIDER; +const char *s_CC_CYBER = CC_CYBER; +const char *s_CC_HERO = CC_HERO; +// Ty 03/30/98 - new substitutions for background textures +// during int screens +const char *bgflatE1 = "FLOOR4_8"; // end of DOOM Episode 1 +const char *bgflatE2 = "SFLR6_1"; // end of DOOM Episode 2 +const char *bgflatE3 = "MFLR8_4"; // end of DOOM Episode 3 +const char *bgflatE4 = "MFLR8_3"; // end of DOOM Episode 4 +const char *bgflat06 = "SLIME16"; // DOOM2 after MAP06 +const char *bgflat11 = "RROCK14"; // DOOM2 after MAP11 +const char *bgflat20 = "RROCK07"; // DOOM2 after MAP20 +const char *bgflat30 = "RROCK17"; // DOOM2 after MAP30 +const char *bgflat15 = "RROCK13"; // DOOM2 going MAP15 to MAP31 +const char *bgflat31 = "RROCK19"; // DOOM2 going MAP31 to MAP32 +const char *bgcastcall = "BOSSBACK"; // Panel behind cast call + +const char *startup1 = ""; // blank lines are default and are not printed +const char *startup2 = ""; +const char *startup3 = ""; +const char *startup4 = ""; +const char *startup5 = ""; + +/* Ty 05/03/98 - externalized + * cph - updated for prboom */ +const char *savegamename = "prbmsav"; + +// end d_deh.h variable declarations +// ==================================================================== + +// Do this for a lookup--the pointer (loaded above) is cross-referenced +// to a string key that is the same as the define above. We will use +// strdups to set these new values that we read from the file, orphaning +// the original value set above. + +// CPhipps - make strings pointed to const +typedef struct { + const char **ppstr; // doubly indirect pointer to string + const char *lookup; // pointer to lookup string name +} deh_strs; + +/* CPhipps - const, static + * - removed redundant "Can't XXX in a netgame" strings + */ +static const deh_strs deh_strlookup[] = { + {&s_D_DEVSTR,"D_DEVSTR"}, + {&s_D_CDROM,"D_CDROM"}, + {&s_PRESSKEY,"PRESSKEY"}, + {&s_PRESSYN,"PRESSYN"}, + {&s_QUITMSG,"QUITMSG"}, + {&s_QSAVESPOT,"QSAVESPOT"}, + {&s_SAVEDEAD,"SAVEDEAD"}, + /* cph - disabled to prevent format string attacks in WAD files + {&s_QSPROMPT,"QSPROMPT"}, + {&s_QLPROMPT,"QLPROMPT"},*/ + {&s_NEWGAME,"NEWGAME"}, + {&s_RESTARTLEVEL,"RESTARTLEVEL"}, + {&s_NIGHTMARE,"NIGHTMARE"}, + {&s_SWSTRING,"SWSTRING"}, + {&s_MSGOFF,"MSGOFF"}, + {&s_MSGON,"MSGON"}, + {&s_NETEND,"NETEND"}, + {&s_ENDGAME,"ENDGAME"}, + {&s_DOSY,"DOSY"}, + {&s_DETAILHI,"DETAILHI"}, + {&s_DETAILLO,"DETAILLO"}, + {&s_GAMMALVL0,"GAMMALVL0"}, + {&s_GAMMALVL1,"GAMMALVL1"}, + {&s_GAMMALVL2,"GAMMALVL2"}, + {&s_GAMMALVL3,"GAMMALVL3"}, + {&s_GAMMALVL4,"GAMMALVL4"}, + {&s_EMPTYSTRING,"EMPTYSTRING"}, + {&s_GOTARMOR,"GOTARMOR"}, + {&s_GOTMEGA,"GOTMEGA"}, + {&s_GOTHTHBONUS,"GOTHTHBONUS"}, + {&s_GOTARMBONUS,"GOTARMBONUS"}, + {&s_GOTSTIM,"GOTSTIM"}, + {&s_GOTMEDINEED,"GOTMEDINEED"}, + {&s_GOTMEDIKIT,"GOTMEDIKIT"}, + {&s_GOTSUPER,"GOTSUPER"}, + {&s_GOTBLUECARD,"GOTBLUECARD"}, + {&s_GOTYELWCARD,"GOTYELWCARD"}, + {&s_GOTREDCARD,"GOTREDCARD"}, + {&s_GOTBLUESKUL,"GOTBLUESKUL"}, + {&s_GOTYELWSKUL,"GOTYELWSKUL"}, + {&s_GOTREDSKULL,"GOTREDSKULL"}, + {&s_GOTINVUL,"GOTINVUL"}, + {&s_GOTBERSERK,"GOTBERSERK"}, + {&s_GOTINVIS,"GOTINVIS"}, + {&s_GOTSUIT,"GOTSUIT"}, + {&s_GOTMAP,"GOTMAP"}, + {&s_GOTVISOR,"GOTVISOR"}, + {&s_GOTMSPHERE,"GOTMSPHERE"}, + {&s_GOTCLIP,"GOTCLIP"}, + {&s_GOTCLIPBOX,"GOTCLIPBOX"}, + {&s_GOTROCKET,"GOTROCKET"}, + {&s_GOTROCKBOX,"GOTROCKBOX"}, + {&s_GOTCELL,"GOTCELL"}, + {&s_GOTCELLBOX,"GOTCELLBOX"}, + {&s_GOTSHELLS,"GOTSHELLS"}, + {&s_GOTSHELLBOX,"GOTSHELLBOX"}, + {&s_GOTBACKPACK,"GOTBACKPACK"}, + {&s_GOTBFG9000,"GOTBFG9000"}, + {&s_GOTCHAINGUN,"GOTCHAINGUN"}, + {&s_GOTCHAINSAW,"GOTCHAINSAW"}, + {&s_GOTLAUNCHER,"GOTLAUNCHER"}, + {&s_GOTPLASMA,"GOTPLASMA"}, + {&s_GOTSHOTGUN,"GOTSHOTGUN"}, + {&s_GOTSHOTGUN2,"GOTSHOTGUN2"}, + {&s_PD_BLUEO,"PD_BLUEO"}, + {&s_PD_REDO,"PD_REDO"}, + {&s_PD_YELLOWO,"PD_YELLOWO"}, + {&s_PD_BLUEK,"PD_BLUEK"}, + {&s_PD_REDK,"PD_REDK"}, + {&s_PD_YELLOWK,"PD_YELLOWK"}, + {&s_PD_BLUEC,"PD_BLUEC"}, + {&s_PD_REDC,"PD_REDC"}, + {&s_PD_YELLOWC,"PD_YELLOWC"}, + {&s_PD_BLUES,"PD_BLUES"}, + {&s_PD_REDS,"PD_REDS"}, + {&s_PD_YELLOWS,"PD_YELLOWS"}, + {&s_PD_ANY,"PD_ANY"}, + {&s_PD_ALL3,"PD_ALL3"}, + {&s_PD_ALL6,"PD_ALL6"}, + {&s_GGSAVED,"GGSAVED"}, + {&s_HUSTR_MSGU,"HUSTR_MSGU"}, + {&s_HUSTR_E1M1,"HUSTR_E1M1"}, + {&s_HUSTR_E1M2,"HUSTR_E1M2"}, + {&s_HUSTR_E1M3,"HUSTR_E1M3"}, + {&s_HUSTR_E1M4,"HUSTR_E1M4"}, + {&s_HUSTR_E1M5,"HUSTR_E1M5"}, + {&s_HUSTR_E1M6,"HUSTR_E1M6"}, + {&s_HUSTR_E1M7,"HUSTR_E1M7"}, + {&s_HUSTR_E1M8,"HUSTR_E1M8"}, + {&s_HUSTR_E1M9,"HUSTR_E1M9"}, + {&s_HUSTR_E2M1,"HUSTR_E2M1"}, + {&s_HUSTR_E2M2,"HUSTR_E2M2"}, + {&s_HUSTR_E2M3,"HUSTR_E2M3"}, + {&s_HUSTR_E2M4,"HUSTR_E2M4"}, + {&s_HUSTR_E2M5,"HUSTR_E2M5"}, + {&s_HUSTR_E2M6,"HUSTR_E2M6"}, + {&s_HUSTR_E2M7,"HUSTR_E2M7"}, + {&s_HUSTR_E2M8,"HUSTR_E2M8"}, + {&s_HUSTR_E2M9,"HUSTR_E2M9"}, + {&s_HUSTR_E3M1,"HUSTR_E3M1"}, + {&s_HUSTR_E3M2,"HUSTR_E3M2"}, + {&s_HUSTR_E3M3,"HUSTR_E3M3"}, + {&s_HUSTR_E3M4,"HUSTR_E3M4"}, + {&s_HUSTR_E3M5,"HUSTR_E3M5"}, + {&s_HUSTR_E3M6,"HUSTR_E3M6"}, + {&s_HUSTR_E3M7,"HUSTR_E3M7"}, + {&s_HUSTR_E3M8,"HUSTR_E3M8"}, + {&s_HUSTR_E3M9,"HUSTR_E3M9"}, + {&s_HUSTR_E4M1,"HUSTR_E4M1"}, + {&s_HUSTR_E4M2,"HUSTR_E4M2"}, + {&s_HUSTR_E4M3,"HUSTR_E4M3"}, + {&s_HUSTR_E4M4,"HUSTR_E4M4"}, + {&s_HUSTR_E4M5,"HUSTR_E4M5"}, + {&s_HUSTR_E4M6,"HUSTR_E4M6"}, + {&s_HUSTR_E4M7,"HUSTR_E4M7"}, + {&s_HUSTR_E4M8,"HUSTR_E4M8"}, + {&s_HUSTR_E4M9,"HUSTR_E4M9"}, + {&s_HUSTR_1,"HUSTR_1"}, + {&s_HUSTR_2,"HUSTR_2"}, + {&s_HUSTR_3,"HUSTR_3"}, + {&s_HUSTR_4,"HUSTR_4"}, + {&s_HUSTR_5,"HUSTR_5"}, + {&s_HUSTR_6,"HUSTR_6"}, + {&s_HUSTR_7,"HUSTR_7"}, + {&s_HUSTR_8,"HUSTR_8"}, + {&s_HUSTR_9,"HUSTR_9"}, + {&s_HUSTR_10,"HUSTR_10"}, + {&s_HUSTR_11,"HUSTR_11"}, + {&s_HUSTR_12,"HUSTR_12"}, + {&s_HUSTR_13,"HUSTR_13"}, + {&s_HUSTR_14,"HUSTR_14"}, + {&s_HUSTR_15,"HUSTR_15"}, + {&s_HUSTR_16,"HUSTR_16"}, + {&s_HUSTR_17,"HUSTR_17"}, + {&s_HUSTR_18,"HUSTR_18"}, + {&s_HUSTR_19,"HUSTR_19"}, + {&s_HUSTR_20,"HUSTR_20"}, + {&s_HUSTR_21,"HUSTR_21"}, + {&s_HUSTR_22,"HUSTR_22"}, + {&s_HUSTR_23,"HUSTR_23"}, + {&s_HUSTR_24,"HUSTR_24"}, + {&s_HUSTR_25,"HUSTR_25"}, + {&s_HUSTR_26,"HUSTR_26"}, + {&s_HUSTR_27,"HUSTR_27"}, + {&s_HUSTR_28,"HUSTR_28"}, + {&s_HUSTR_29,"HUSTR_29"}, + {&s_HUSTR_30,"HUSTR_30"}, + {&s_HUSTR_31,"HUSTR_31"}, + {&s_HUSTR_32,"HUSTR_32"}, + {&s_PHUSTR_1,"PHUSTR_1"}, + {&s_PHUSTR_2,"PHUSTR_2"}, + {&s_PHUSTR_3,"PHUSTR_3"}, + {&s_PHUSTR_4,"PHUSTR_4"}, + {&s_PHUSTR_5,"PHUSTR_5"}, + {&s_PHUSTR_6,"PHUSTR_6"}, + {&s_PHUSTR_7,"PHUSTR_7"}, + {&s_PHUSTR_8,"PHUSTR_8"}, + {&s_PHUSTR_9,"PHUSTR_9"}, + {&s_PHUSTR_10,"PHUSTR_10"}, + {&s_PHUSTR_11,"PHUSTR_11"}, + {&s_PHUSTR_12,"PHUSTR_12"}, + {&s_PHUSTR_13,"PHUSTR_13"}, + {&s_PHUSTR_14,"PHUSTR_14"}, + {&s_PHUSTR_15,"PHUSTR_15"}, + {&s_PHUSTR_16,"PHUSTR_16"}, + {&s_PHUSTR_17,"PHUSTR_17"}, + {&s_PHUSTR_18,"PHUSTR_18"}, + {&s_PHUSTR_19,"PHUSTR_19"}, + {&s_PHUSTR_20,"PHUSTR_20"}, + {&s_PHUSTR_21,"PHUSTR_21"}, + {&s_PHUSTR_22,"PHUSTR_22"}, + {&s_PHUSTR_23,"PHUSTR_23"}, + {&s_PHUSTR_24,"PHUSTR_24"}, + {&s_PHUSTR_25,"PHUSTR_25"}, + {&s_PHUSTR_26,"PHUSTR_26"}, + {&s_PHUSTR_27,"PHUSTR_27"}, + {&s_PHUSTR_28,"PHUSTR_28"}, + {&s_PHUSTR_29,"PHUSTR_29"}, + {&s_PHUSTR_30,"PHUSTR_30"}, + {&s_PHUSTR_31,"PHUSTR_31"}, + {&s_PHUSTR_32,"PHUSTR_32"}, + {&s_THUSTR_1,"THUSTR_1"}, + {&s_THUSTR_2,"THUSTR_2"}, + {&s_THUSTR_3,"THUSTR_3"}, + {&s_THUSTR_4,"THUSTR_4"}, + {&s_THUSTR_5,"THUSTR_5"}, + {&s_THUSTR_6,"THUSTR_6"}, + {&s_THUSTR_7,"THUSTR_7"}, + {&s_THUSTR_8,"THUSTR_8"}, + {&s_THUSTR_9,"THUSTR_9"}, + {&s_THUSTR_10,"THUSTR_10"}, + {&s_THUSTR_11,"THUSTR_11"}, + {&s_THUSTR_12,"THUSTR_12"}, + {&s_THUSTR_13,"THUSTR_13"}, + {&s_THUSTR_14,"THUSTR_14"}, + {&s_THUSTR_15,"THUSTR_15"}, + {&s_THUSTR_16,"THUSTR_16"}, + {&s_THUSTR_17,"THUSTR_17"}, + {&s_THUSTR_18,"THUSTR_18"}, + {&s_THUSTR_19,"THUSTR_19"}, + {&s_THUSTR_20,"THUSTR_20"}, + {&s_THUSTR_21,"THUSTR_21"}, + {&s_THUSTR_22,"THUSTR_22"}, + {&s_THUSTR_23,"THUSTR_23"}, + {&s_THUSTR_24,"THUSTR_24"}, + {&s_THUSTR_25,"THUSTR_25"}, + {&s_THUSTR_26,"THUSTR_26"}, + {&s_THUSTR_27,"THUSTR_27"}, + {&s_THUSTR_28,"THUSTR_28"}, + {&s_THUSTR_29,"THUSTR_29"}, + {&s_THUSTR_30,"THUSTR_30"}, + {&s_THUSTR_31,"THUSTR_31"}, + {&s_THUSTR_32,"THUSTR_32"}, + {&s_HUSTR_CHATMACRO1,"HUSTR_CHATMACRO1"}, + {&s_HUSTR_CHATMACRO2,"HUSTR_CHATMACRO2"}, + {&s_HUSTR_CHATMACRO3,"HUSTR_CHATMACRO3"}, + {&s_HUSTR_CHATMACRO4,"HUSTR_CHATMACRO4"}, + {&s_HUSTR_CHATMACRO5,"HUSTR_CHATMACRO5"}, + {&s_HUSTR_CHATMACRO6,"HUSTR_CHATMACRO6"}, + {&s_HUSTR_CHATMACRO7,"HUSTR_CHATMACRO7"}, + {&s_HUSTR_CHATMACRO8,"HUSTR_CHATMACRO8"}, + {&s_HUSTR_CHATMACRO9,"HUSTR_CHATMACRO9"}, + {&s_HUSTR_CHATMACRO0,"HUSTR_CHATMACRO0"}, + {&s_HUSTR_TALKTOSELF1,"HUSTR_TALKTOSELF1"}, + {&s_HUSTR_TALKTOSELF2,"HUSTR_TALKTOSELF2"}, + {&s_HUSTR_TALKTOSELF3,"HUSTR_TALKTOSELF3"}, + {&s_HUSTR_TALKTOSELF4,"HUSTR_TALKTOSELF4"}, + {&s_HUSTR_TALKTOSELF5,"HUSTR_TALKTOSELF5"}, + {&s_HUSTR_MESSAGESENT,"HUSTR_MESSAGESENT"}, + {&s_HUSTR_PLRGREEN,"HUSTR_PLRGREEN"}, + {&s_HUSTR_PLRINDIGO,"HUSTR_PLRINDIGO"}, + {&s_HUSTR_PLRBROWN,"HUSTR_PLRBROWN"}, + {&s_HUSTR_PLRRED,"HUSTR_PLRRED"}, + //{c_HUSTR_KEYGREEN,"HUSTR_KEYGREEN"}, + //{c_HUSTR_KEYINDIGO,"HUSTR_KEYINDIGO"}, + //{c_HUSTR_KEYBROWN,"HUSTR_KEYBROWN"}, + //{c_HUSTR_KEYRED,"HUSTR_KEYRED"}, + {&s_AMSTR_FOLLOWON,"AMSTR_FOLLOWON"}, + {&s_AMSTR_FOLLOWOFF,"AMSTR_FOLLOWOFF"}, + {&s_AMSTR_GRIDON,"AMSTR_GRIDON"}, + {&s_AMSTR_GRIDOFF,"AMSTR_GRIDOFF"}, + {&s_AMSTR_MARKEDSPOT,"AMSTR_MARKEDSPOT"}, + {&s_AMSTR_MARKSCLEARED,"AMSTR_MARKSCLEARED"}, + {&s_STSTR_MUS,"STSTR_MUS"}, + {&s_STSTR_NOMUS,"STSTR_NOMUS"}, + {&s_STSTR_DQDON,"STSTR_DQDON"}, + {&s_STSTR_DQDOFF,"STSTR_DQDOFF"}, + {&s_STSTR_KFAADDED,"STSTR_KFAADDED"}, + {&s_STSTR_FAADDED,"STSTR_FAADDED"}, + {&s_STSTR_NCON,"STSTR_NCON"}, + {&s_STSTR_NCOFF,"STSTR_NCOFF"}, + {&s_STSTR_BEHOLD,"STSTR_BEHOLD"}, + {&s_STSTR_BEHOLDX,"STSTR_BEHOLDX"}, + {&s_STSTR_CHOPPERS,"STSTR_CHOPPERS"}, + {&s_STSTR_CLEV,"STSTR_CLEV"}, + {&s_STSTR_COMPON,"STSTR_COMPON"}, + {&s_STSTR_COMPOFF,"STSTR_COMPOFF"}, + {&s_E1TEXT,"E1TEXT"}, + {&s_E2TEXT,"E2TEXT"}, + {&s_E3TEXT,"E3TEXT"}, + {&s_E4TEXT,"E4TEXT"}, + {&s_C1TEXT,"C1TEXT"}, + {&s_C2TEXT,"C2TEXT"}, + {&s_C3TEXT,"C3TEXT"}, + {&s_C4TEXT,"C4TEXT"}, + {&s_C5TEXT,"C5TEXT"}, + {&s_C6TEXT,"C6TEXT"}, + {&s_P1TEXT,"P1TEXT"}, + {&s_P2TEXT,"P2TEXT"}, + {&s_P3TEXT,"P3TEXT"}, + {&s_P4TEXT,"P4TEXT"}, + {&s_P5TEXT,"P5TEXT"}, + {&s_P6TEXT,"P6TEXT"}, + {&s_T1TEXT,"T1TEXT"}, + {&s_T2TEXT,"T2TEXT"}, + {&s_T3TEXT,"T3TEXT"}, + {&s_T4TEXT,"T4TEXT"}, + {&s_T5TEXT,"T5TEXT"}, + {&s_T6TEXT,"T6TEXT"}, + {&s_CC_ZOMBIE,"CC_ZOMBIE"}, + {&s_CC_SHOTGUN,"CC_SHOTGUN"}, + {&s_CC_HEAVY,"CC_HEAVY"}, + {&s_CC_IMP,"CC_IMP"}, + {&s_CC_DEMON,"CC_DEMON"}, + {&s_CC_LOST,"CC_LOST"}, + {&s_CC_CACO,"CC_CACO"}, + {&s_CC_HELL,"CC_HELL"}, + {&s_CC_BARON,"CC_BARON"}, + {&s_CC_ARACH,"CC_ARACH"}, + {&s_CC_PAIN,"CC_PAIN"}, + {&s_CC_REVEN,"CC_REVEN"}, + {&s_CC_MANCU,"CC_MANCU"}, + {&s_CC_ARCH,"CC_ARCH"}, + {&s_CC_SPIDER,"CC_SPIDER"}, + {&s_CC_CYBER,"CC_CYBER"}, + {&s_CC_HERO,"CC_HERO"}, + {&bgflatE1,"BGFLATE1"}, + {&bgflatE2,"BGFLATE2"}, + {&bgflatE3,"BGFLATE3"}, + {&bgflatE4,"BGFLATE4"}, + {&bgflat06,"BGFLAT06"}, + {&bgflat11,"BGFLAT11"}, + {&bgflat20,"BGFLAT20"}, + {&bgflat30,"BGFLAT30"}, + {&bgflat15,"BGFLAT15"}, + {&bgflat31,"BGFLAT31"}, + {&bgcastcall,"BGCASTCALL"}, + // Ty 04/08/98 - added 5 general purpose startup announcement + // strings for hacker use. See m_menu.c + {&startup1,"STARTUP1"}, + {&startup2,"STARTUP2"}, + {&startup3,"STARTUP3"}, + {&startup4,"STARTUP4"}, + {&startup5,"STARTUP5"}, + {&savegamename,"SAVEGAMENAME"}, // Ty 05/03/98 +}; + +static int deh_numstrlookup = +sizeof(deh_strlookup)/sizeof(deh_strlookup[0]); + +const char *deh_newlevel = "NEWLEVEL"; // CPhipps - const + +// DOOM shareware/registered/retail (Ultimate) names. +// CPhipps - const**const +const char **const mapnames[] = +{ + &s_HUSTR_E1M1, + &s_HUSTR_E1M2, + &s_HUSTR_E1M3, + &s_HUSTR_E1M4, + &s_HUSTR_E1M5, + &s_HUSTR_E1M6, + &s_HUSTR_E1M7, + &s_HUSTR_E1M8, + &s_HUSTR_E1M9, + + &s_HUSTR_E2M1, + &s_HUSTR_E2M2, + &s_HUSTR_E2M3, + &s_HUSTR_E2M4, + &s_HUSTR_E2M5, + &s_HUSTR_E2M6, + &s_HUSTR_E2M7, + &s_HUSTR_E2M8, + &s_HUSTR_E2M9, + + &s_HUSTR_E3M1, + &s_HUSTR_E3M2, + &s_HUSTR_E3M3, + &s_HUSTR_E3M4, + &s_HUSTR_E3M5, + &s_HUSTR_E3M6, + &s_HUSTR_E3M7, + &s_HUSTR_E3M8, + &s_HUSTR_E3M9, + + &s_HUSTR_E4M1, + &s_HUSTR_E4M2, + &s_HUSTR_E4M3, + &s_HUSTR_E4M4, + &s_HUSTR_E4M5, + &s_HUSTR_E4M6, + &s_HUSTR_E4M7, + &s_HUSTR_E4M8, + &s_HUSTR_E4M9, + + &deh_newlevel, // spares? Unused. + &deh_newlevel, + &deh_newlevel, + &deh_newlevel, + &deh_newlevel, + &deh_newlevel, + &deh_newlevel, + &deh_newlevel, + &deh_newlevel +}; + +// CPhipps - const**const +const char **const mapnames2[] = // DOOM 2 map names. +{ + &s_HUSTR_1, + &s_HUSTR_2, + &s_HUSTR_3, + &s_HUSTR_4, + &s_HUSTR_5, + &s_HUSTR_6, + &s_HUSTR_7, + &s_HUSTR_8, + &s_HUSTR_9, + &s_HUSTR_10, + &s_HUSTR_11, + + &s_HUSTR_12, + &s_HUSTR_13, + &s_HUSTR_14, + &s_HUSTR_15, + &s_HUSTR_16, + &s_HUSTR_17, + &s_HUSTR_18, + &s_HUSTR_19, + &s_HUSTR_20, + + &s_HUSTR_21, + &s_HUSTR_22, + &s_HUSTR_23, + &s_HUSTR_24, + &s_HUSTR_25, + &s_HUSTR_26, + &s_HUSTR_27, + &s_HUSTR_28, + &s_HUSTR_29, + &s_HUSTR_30, + &s_HUSTR_31, + &s_HUSTR_32, +}; + +// CPhipps - const**const +const char **const mapnamesp[] = // Plutonia WAD map names. +{ + &s_PHUSTR_1, + &s_PHUSTR_2, + &s_PHUSTR_3, + &s_PHUSTR_4, + &s_PHUSTR_5, + &s_PHUSTR_6, + &s_PHUSTR_7, + &s_PHUSTR_8, + &s_PHUSTR_9, + &s_PHUSTR_10, + &s_PHUSTR_11, + + &s_PHUSTR_12, + &s_PHUSTR_13, + &s_PHUSTR_14, + &s_PHUSTR_15, + &s_PHUSTR_16, + &s_PHUSTR_17, + &s_PHUSTR_18, + &s_PHUSTR_19, + &s_PHUSTR_20, + + &s_PHUSTR_21, + &s_PHUSTR_22, + &s_PHUSTR_23, + &s_PHUSTR_24, + &s_PHUSTR_25, + &s_PHUSTR_26, + &s_PHUSTR_27, + &s_PHUSTR_28, + &s_PHUSTR_29, + &s_PHUSTR_30, + &s_PHUSTR_31, + &s_PHUSTR_32, +}; + +// CPhipps - const**const +const char **const mapnamest[] = // TNT WAD map names. +{ + &s_THUSTR_1, + &s_THUSTR_2, + &s_THUSTR_3, + &s_THUSTR_4, + &s_THUSTR_5, + &s_THUSTR_6, + &s_THUSTR_7, + &s_THUSTR_8, + &s_THUSTR_9, + &s_THUSTR_10, + &s_THUSTR_11, + + &s_THUSTR_12, + &s_THUSTR_13, + &s_THUSTR_14, + &s_THUSTR_15, + &s_THUSTR_16, + &s_THUSTR_17, + &s_THUSTR_18, + &s_THUSTR_19, + &s_THUSTR_20, + + &s_THUSTR_21, + &s_THUSTR_22, + &s_THUSTR_23, + &s_THUSTR_24, + &s_THUSTR_25, + &s_THUSTR_26, + &s_THUSTR_27, + &s_THUSTR_28, + &s_THUSTR_29, + &s_THUSTR_30, + &s_THUSTR_31, + &s_THUSTR_32, +}; + +// Function prototypes +void lfstrip(char *); // strip the \r and/or \n off of a line +void rstrip(char *); // strip trailing whitespace +char * ptr_lstrip(char *); // point past leading whitespace +boolean deh_GetData(char *, char *, uint_64_t *, char **, FILE *); +boolean deh_procStringSub(char *, char *, char *, FILE *); +char * dehReformatStr(char *); + +// Prototypes for block processing functions +// Pointers to these functions are used as the blocks are encountered. + +static void deh_procThing(DEHFILE *fpin, FILE* fpout, char *line); +static void deh_procFrame(DEHFILE *, FILE*, char *); +static void deh_procPointer(DEHFILE *, FILE*, char *); +static void deh_procSounds(DEHFILE *, FILE*, char *); +static void deh_procAmmo(DEHFILE *, FILE*, char *); +static void deh_procWeapon(DEHFILE *, FILE*, char *); +static void deh_procSprite(DEHFILE *, FILE*, char *); +static void deh_procCheat(DEHFILE *, FILE*, char *); +static void deh_procMisc(DEHFILE *, FILE*, char *); +static void deh_procText(DEHFILE *, FILE*, char *); +static void deh_procPars(DEHFILE *, FILE*, char *); +static void deh_procStrings(DEHFILE *, FILE*, char *); +static void deh_procError(DEHFILE *, FILE*, char *); +static void deh_procBexCodePointers(DEHFILE *, FILE*, char *); +static void deh_procHelperThing(DEHFILE *, FILE *, char *); // haleyjd 9/22/99 +// haleyjd: handlers to fully deprecate the DeHackEd text section +static void deh_procBexSounds(DEHFILE *, FILE *, char *); +static void deh_procBexMusic(DEHFILE *, FILE *, char *); +static void deh_procBexSprites(DEHFILE *, FILE *, char *); + +// Structure deh_block is used to hold the block names that can +// be encountered, and the routines to use to decipher them + +typedef struct +{ + const char *key; // a mnemonic block code name // CPhipps - const* + void (*const fptr)(DEHFILE *, FILE*, char *); // handler +} deh_block; + +#define DEH_BUFFERMAX 1024 // input buffer area size, hardcodedfor now +// killough 8/9/98: make DEH_BLOCKMAX self-adjusting +#define DEH_BLOCKMAX (sizeof deh_blocks/sizeof*deh_blocks) // size of array +#define DEH_MAXKEYLEN 32 // as much of any key as we'll look at +#define DEH_MOBJINFOMAX 24 // number of ints in the mobjinfo_t structure (!) + +// Put all the block header values, and the function to be called when that +// one is encountered, in this array: +static const deh_block deh_blocks[] = { // CPhipps - static const + /* 0 */ {"Thing",deh_procThing}, + /* 1 */ {"Frame",deh_procFrame}, + /* 2 */ {"Pointer",deh_procPointer}, + /* 3 */ {"Sound",deh_procSounds}, // Ty 03/16/98 corrected from "Sounds" + /* 4 */ {"Ammo",deh_procAmmo}, + /* 5 */ {"Weapon",deh_procWeapon}, + /* 6 */ {"Sprite",deh_procSprite}, + /* 7 */ {"Cheat",deh_procCheat}, + /* 8 */ {"Misc",deh_procMisc}, + /* 9 */ {"Text",deh_procText}, // -- end of standard "deh" entries, + + // begin BOOM Extensions (BEX) + + /* 10 */ {"[STRINGS]",deh_procStrings}, // new string changes + /* 11 */ {"[PARS]",deh_procPars}, // alternative block marker + /* 12 */ {"[CODEPTR]",deh_procBexCodePointers}, // bex codepointers by mnemonic + /* 13 */ {"[HELPER]", deh_procHelperThing}, // helper thing substitution haleyjd 9/22/99 + /* 14 */ {"[SPRITES]", deh_procBexSprites}, // bex style sprites + /* 15 */ {"[SOUNDS]", deh_procBexSounds}, // bex style sounds + /* 16 */ {"[MUSIC]", deh_procBexMusic}, // bex style music + /* 17 */ {"", deh_procError} // dummy to handle anything else +}; + +// flag to skip included deh-style text, used with INCLUDE NOTEXT directive +static boolean includenotext = false; + +// MOBJINFO - Dehacked block name = "Thing" +// Usage: Thing nn (name) +// These are for mobjinfo_t types. Each is an integer +// within the structure, so we can use index of the string in this +// array to offset by sizeof(int) into the mobjinfo_t array at [nn] +// * things are base zero but dehacked considers them to start at #1. *** +// CPhipps - static const + +static const char *deh_mobjinfo[DEH_MOBJINFOMAX] = +{ + "ID #", // .doomednum + "Initial frame", // .spawnstate + "Hit points", // .spawnhealth + "First moving frame", // .seestate + "Alert sound", // .seesound + "Reaction time", // .reactiontime + "Attack sound", // .attacksound + "Injury frame", // .painstate + "Pain chance", // .painchance + "Pain sound", // .painsound + "Close attack frame", // .meleestate + "Far attack frame", // .missilestate + "Death frame", // .deathstate + "Exploding frame", // .xdeathstate + "Death sound", // .deathsound + "Speed", // .speed + "Width", // .radius + "Height", // .height + "Mass", // .mass + "Missile damage", // .damage + "Action sound", // .activesound + "Bits", // .flags + "Bits2", // .flags + "Respawn frame" // .raisestate +}; + +// Strings that are used to indicate flags ("Bits" in mobjinfo) +// This is an array of bit masks that are related to p_mobj.h +// values, using the smae names without the MF_ in front. +// Ty 08/27/98 new code +// +// killough 10/98: +// +// Convert array to struct to allow multiple values, make array size variable + +#define DEH_MOBJFLAGMAX (sizeof deh_mobjflags/sizeof*deh_mobjflags) + +struct deh_mobjflags_s { + const char *name; // CPhipps - const* + uint_64_t value; +}; + +// CPhipps - static const +static const struct deh_mobjflags_s deh_mobjflags[] = { + {"SPECIAL", MF_SPECIAL}, // call P_Specialthing when touched + {"SOLID", MF_SOLID}, // block movement + {"SHOOTABLE", MF_SHOOTABLE}, // can be hit + {"NOSECTOR", MF_NOSECTOR}, // invisible but touchable + {"NOBLOCKMAP", MF_NOBLOCKMAP}, // inert but displayable + {"AMBUSH", MF_AMBUSH}, // deaf monster + {"JUSTHIT", MF_JUSTHIT}, // will try to attack right back + {"JUSTATTACKED", MF_JUSTATTACKED}, // take at least 1 step before attacking + {"SPAWNCEILING", MF_SPAWNCEILING}, // initially hang from ceiling + {"NOGRAVITY", MF_NOGRAVITY}, // don't apply gravity during play + {"DROPOFF", MF_DROPOFF}, // can jump from high places + {"PICKUP", MF_PICKUP}, // will pick up items + {"NOCLIP", MF_NOCLIP}, // goes through walls + {"SLIDE", MF_SLIDE}, // keep info about sliding along walls + {"FLOAT", MF_FLOAT}, // allow movement to any height + {"TELEPORT", MF_TELEPORT}, // don't cross lines or look at heights + {"MISSILE", MF_MISSILE}, // don't hit same species, explode on block + {"DROPPED", MF_DROPPED}, // dropped, not spawned (like ammo clip) + {"SHADOW", MF_SHADOW}, // use fuzzy draw like spectres + {"NOBLOOD", MF_NOBLOOD}, // puffs instead of blood when shot + {"CORPSE", MF_CORPSE}, // so it will slide down steps when dead + {"INFLOAT", MF_INFLOAT}, // float but not to target height + {"COUNTKILL", MF_COUNTKILL}, // count toward the kills total + {"COUNTITEM", MF_COUNTITEM}, // count toward the items total + {"SKULLFLY", MF_SKULLFLY}, // special handling for flying skulls + {"NOTDMATCH", MF_NOTDMATCH}, // do not spawn in deathmatch + + // killough 10/98: TRANSLATION consists of 2 bits, not 1: + + {"TRANSLATION", MF_TRANSLATION1}, // for Boom bug-compatibility + {"TRANSLATION1", MF_TRANSLATION1}, // use translation table for color (players) + {"TRANSLATION2", MF_TRANSLATION2}, // use translation table for color (players) + {"UNUSED1", MF_TRANSLATION2}, // unused bit # 1 -- For Boom bug-compatibility + {"UNUSED2", MF_UNUSED2}, // unused bit # 2 -- For Boom compatibility + {"UNUSED3", MF_UNUSED3}, // unused bit # 3 -- For Boom compatibility + {"UNUSED4", MF_TRANSLUCENT}, // unused bit # 4 -- For Boom compatibility + {"TRANSLUCENT", MF_TRANSLUCENT}, // apply translucency to sprite (BOOM) + {"TOUCHY", MF_TOUCHY}, // dies on contact with solid objects (MBF) + {"BOUNCES", MF_BOUNCES}, // bounces off floors, ceilings and maybe walls (MBF) + {"FRIEND", MF_FRIEND}, // a friend of the player(s) (MBF) +}; + +// STATE - Dehacked block name = "Frame" and "Pointer" +// Usage: Frame nn +// Usage: Pointer nn (Frame nn) +// These are indexed separately, for lookup to the actual +// function pointers. Here we'll take whatever Dehacked gives +// us and go from there. The (Frame nn) after the pointer is the +// real place to put this value. The "Pointer" value is an xref +// that Dehacked uses and is useless to us. +// * states are base zero and have a dummy #0 (TROO) + +static const char *deh_state[] = // CPhipps - static const* +{ + "Sprite number", // .sprite (spritenum_t) // an enum + "Sprite subnumber", // .frame (long) + "Duration", // .tics (long) + "Next frame", // .nextstate (statenum_t) + // This is set in a separate "Pointer" block from Dehacked + "Codep Frame", // pointer to first use of action (actionf_t) + "Unknown 1", // .misc1 (long) + "Unknown 2" // .misc2 (long) +}; + +// SFXINFO_STRUCT - Dehacked block name = "Sounds" +// Sound effects, typically not changed (redirected, and new sfx put +// into the pwad, but not changed here. Can you tell that Gregdidn't +// know what they were for, mostly? Can you tell that I don't either? +// Mostly I just put these into the same slots as they are in the struct. +// This may not be supported in our -deh option if it doesn't make sense by then. + +// * sounds are base zero but have a dummy #0 + +static const char *deh_sfxinfo[] = // CPhipps - static const* +{ + "Offset", // pointer to a name string, changed in text + "Zero/One", // .singularity (int, one at a time flag) + "Value", // .priority + "Zero 1", // .link (sfxinfo_t*) referenced sound if linked + "Zero 2", // .pitch + "Zero 3", // .volume + "Zero 4", // .data (SAMPLE*) sound data + "Neg. One 1", // .usefulness + "Neg. One 2" // .lumpnum +}; + +// MUSICINFO is not supported in Dehacked. Ignored here. +// * music entries are base zero but have a dummy #0 + +// SPRITE - Dehacked block name = "Sprite" +// Usage = Sprite nn +// Sprite redirection by offset into the text area - unsupported by BOOM +// * sprites are base zero and dehacked uses it that way. + +// static const char *deh_sprite[] = // CPhipps - static const* +// { +// "Offset" // supposed to be the offset into the text section +// }; + +// AMMO - Dehacked block name = "Ammo" +// usage = Ammo n (name) +// Ammo information for the few types of ammo + +static const char *deh_ammo[] = // CPhipps - static const* +{ + "Max ammo", // maxammo[] + "Per ammo" // clipammo[] +}; + +// WEAPONS - Dehacked block name = "Weapon" +// Usage: Weapon nn (name) +// Basically a list of frames and what kind of ammo (see above)it uses. + +static const char *deh_weapon[] = // CPhipps - static const* +{ + "Ammo type", // .ammo + "Deselect frame", // .upstate + "Select frame", // .downstate + "Bobbing frame", // .readystate + "Shooting frame", // .atkstate + "Firing frame" // .flashstate +}; + +// CHEATS - Dehacked block name = "Cheat" +// Usage: Cheat 0 +// Always uses a zero in the dehacked file, for consistency. No meaning. +// These are just plain funky terms compared with id's +// +// killough 4/18/98: integrated into main cheat table now (see st_stuff.c) + +// MISC - Dehacked block name = "Misc" +// Usage: Misc 0 +// Always uses a zero in the dehacked file, for consistency. No meaning. + +static const char *deh_misc[] = // CPhipps - static const* +{ + "Initial Health", // initial_health + "Initial Bullets", // initial_bullets + "Max Health", // maxhealth + "Max Armor", // max_armor + "Green Armor Class", // green_armor_class + "Blue Armor Class", // blue_armor_class + "Max Soulsphere", // max_soul + "Soulsphere Health", // soul_health + "Megasphere Health", // mega_health + "God Mode Health", // god_health + "IDFA Armor", // idfa_armor + "IDFA Armor Class", // idfa_armor_class + "IDKFA Armor", // idkfa_armor + "IDKFA Armor Class", // idkfa_armor_class + "BFG Cells/Shot", // BFGCELLS + "Monsters Infight" // Unknown--not a specific number it seems, but + // the logic has to be here somewhere or + // it'd happen always +}; + +// TEXT - Dehacked block name = "Text" +// Usage: Text fromlen tolen +// Dehacked allows a bit of adjustment to the length (why?) + +// BEX extension [CODEPTR] +// Usage: Start block, then each line is: +// FRAME nnn = PointerMnemonic + +typedef struct { + actionf_t cptr; // actual pointer to the subroutine + const char *lookup; // mnemonic lookup string to be specified in BEX + // CPhipps - const* +} deh_bexptr; + +static const deh_bexptr deh_bexptrs[] = // CPhipps - static const +{ + {A_Light0, "A_Light0"}, + {A_WeaponReady, "A_WeaponReady"}, + {A_Lower, "A_Lower"}, + {A_Raise, "A_Raise"}, + {A_Punch, "A_Punch"}, + {A_ReFire, "A_ReFire"}, + {A_FirePistol, "A_FirePistol"}, + {A_Light1, "A_Light1"}, + {A_FireShotgun, "A_FireShotgun"}, + {A_Light2, "A_Light2"}, + {A_FireShotgun2, "A_FireShotgun2"}, + {A_CheckReload, "A_CheckReload"}, + {A_OpenShotgun2, "A_OpenShotgun2"}, + {A_LoadShotgun2, "A_LoadShotgun2"}, + {A_CloseShotgun2, "A_CloseShotgun2"}, + {A_FireCGun, "A_FireCGun"}, + {A_GunFlash, "A_GunFlash"}, + {A_FireMissile, "A_FireMissile"}, + {A_Saw, "A_Saw"}, + {A_FirePlasma, "A_FirePlasma"}, + {A_BFGsound, "A_BFGsound"}, + {A_FireBFG, "A_FireBFG"}, + {A_BFGSpray, "A_BFGSpray"}, + {A_Explode, "A_Explode"}, + {A_Pain, "A_Pain"}, + {A_PlayerScream, "A_PlayerScream"}, + {A_Fall, "A_Fall"}, + {A_XScream, "A_XScream"}, + {A_Look, "A_Look"}, + {A_Chase, "A_Chase"}, + {A_FaceTarget, "A_FaceTarget"}, + {A_PosAttack, "A_PosAttack"}, + {A_Scream, "A_Scream"}, + {A_SPosAttack, "A_SPosAttack"}, + {A_VileChase, "A_VileChase"}, + {A_VileStart, "A_VileStart"}, + {A_VileTarget, "A_VileTarget"}, + {A_VileAttack, "A_VileAttack"}, + {A_StartFire, "A_StartFire"}, + {A_Fire, "A_Fire"}, + {A_FireCrackle, "A_FireCrackle"}, + {A_Tracer, "A_Tracer"}, + {A_SkelWhoosh, "A_SkelWhoosh"}, + {A_SkelFist, "A_SkelFist"}, + {A_SkelMissile, "A_SkelMissile"}, + {A_FatRaise, "A_FatRaise"}, + {A_FatAttack1, "A_FatAttack1"}, + {A_FatAttack2, "A_FatAttack2"}, + {A_FatAttack3, "A_FatAttack3"}, + {A_BossDeath, "A_BossDeath"}, + {A_CPosAttack, "A_CPosAttack"}, + {A_CPosRefire, "A_CPosRefire"}, + {A_TroopAttack, "A_TroopAttack"}, + {A_SargAttack, "A_SargAttack"}, + {A_HeadAttack, "A_HeadAttack"}, + {A_BruisAttack, "A_BruisAttack"}, + {A_SkullAttack, "A_SkullAttack"}, + {A_Metal, "A_Metal"}, + {A_SpidRefire, "A_SpidRefire"}, + {A_BabyMetal, "A_BabyMetal"}, + {A_BspiAttack, "A_BspiAttack"}, + {A_Hoof, "A_Hoof"}, + {A_CyberAttack, "A_CyberAttack"}, + {A_PainAttack, "A_PainAttack"}, + {A_PainDie, "A_PainDie"}, + {A_KeenDie, "A_KeenDie"}, + {A_BrainPain, "A_BrainPain"}, + {A_BrainScream, "A_BrainScream"}, + {A_BrainDie, "A_BrainDie"}, + {A_BrainAwake, "A_BrainAwake"}, + {A_BrainSpit, "A_BrainSpit"}, + {A_SpawnSound, "A_SpawnSound"}, + {A_SpawnFly, "A_SpawnFly"}, + {A_BrainExplode, "A_BrainExplode"}, + {A_Detonate, "A_Detonate"}, // killough 8/9/98 + {A_Mushroom, "A_Mushroom"}, // killough 10/98 + {A_Die, "A_Die"}, // killough 11/98 + {A_Spawn, "A_Spawn"}, // killough 11/98 + {A_Turn, "A_Turn"}, // killough 11/98 + {A_Face, "A_Face"}, // killough 11/98 + {A_Scratch, "A_Scratch"}, // killough 11/98 + {A_PlaySound, "A_PlaySound"}, // killough 11/98 + {A_RandomJump, "A_RandomJump"}, // killough 11/98 + {A_LineEffect, "A_LineEffect"}, // killough 11/98 + + // This NULL entry must be the last in the list + {NULL, "A_NULL"}, // Ty 05/16/98 +}; + +// to hold startup code pointers from INFO.C +// CPhipps - static +static actionf_t deh_codeptr[NUMSTATES]; + +// haleyjd: support for BEX SPRITES, SOUNDS, and MUSIC +char *deh_spritenames[NUMSPRITES + 1]; +char *deh_musicnames[NUMMUSIC + 1]; +char *deh_soundnames[NUMSFX + 1]; + +void D_BuildBEXTables(void) +{ + int i; + + // moved from ProcessDehFile, then we don't need the static int i + for (i = 0; i < NUMSTATES; i++) // remember what they start as for deh xref + deh_codeptr[i] = states[i].action; + + for(i = 0; i < NUMSPRITES; i++) + deh_spritenames[i] = strdup(sprnames[i]); + deh_spritenames[NUMSPRITES] = NULL; + + for(i = 1; i < NUMMUSIC; i++) + deh_musicnames[i] = strdup(S_music[i].name); + deh_musicnames[0] = deh_musicnames[NUMMUSIC] = NULL; + + for(i = 1; i < NUMSFX; i++) + deh_soundnames[i] = strdup(S_sfx[i].name); + deh_soundnames[0] = deh_soundnames[NUMSFX] = NULL; +} + +// ==================================================================== +// ProcessDehFile +// Purpose: Read and process a DEH or BEX file +// Args: filename -- name of the DEH/BEX file +// outfilename -- output file (DEHOUT.TXT), appended to here +// Returns: void +// +// killough 10/98: +// substantially modified to allow input from wad lumps instead of .deh files. + +void ProcessDehFile(const char *filename, const char *outfilename, int lumpnum) +{ + static FILE *fileout; // In case -dehout was used + DEHFILE infile, *filein = &infile; // killough 10/98 + char inbuffer[DEH_BUFFERMAX]; // Place to put the primary infostring + + // Open output file if we're writing output + if (outfilename && *outfilename && !fileout) + { + static boolean firstfile = true; // to allow append to output log + if (!strcmp(outfilename, "-")) + fileout = stdout; + else + if (!(fileout=fopen(outfilename, firstfile ? "wt" : "at"))) + { + lprintf(LO_WARN, "Could not open -dehout file %s\n... using stdout.\n", + outfilename); + fileout = stdout; + } + firstfile = false; + } + + // killough 10/98: allow DEH files to come from wad lumps + + if (filename) + { + if (!(infile.f = fopen(filename,"rt"))) + { + lprintf(LO_WARN, "-deh file %s not found\n",filename); + return; // should be checked up front anyway + } + infile.lump = NULL; + } + else // DEH file comes from lump indicated by third argument + { + infile.size = W_LumpLength(lumpnum); + infile.inp = infile.lump = W_CacheLumpNum(lumpnum); + filename = "(WAD)"; + } + + lprintf(LO_INFO, "Loading DEH file %s\n",filename); + if (fileout) fprintf(fileout,"\nLoading DEH file %s\n\n",filename); + + // move deh_codeptr initialisation to D_BuildBEXTables + + // loop until end of file + + while (dehfgets(inbuffer,sizeof(inbuffer),filein)) + { + unsigned i; + + lfstrip(inbuffer); + if (fileout) fprintf(fileout,"Line='%s'\n",inbuffer); + if (!*inbuffer || *inbuffer == '#' || *inbuffer == ' ') + continue; /* Blank line or comment line */ + + // -- If DEH_BLOCKMAX is set right, the processing is independently + // -- handled based on data in the deh_blocks[] structure array + + // killough 10/98: INCLUDE code rewritten to allow arbitrary nesting, + // and to greatly simplify code, fix memory leaks, other bugs + + if (!strnicmp(inbuffer,"INCLUDE",7)) // include a file + { + // preserve state while including a file + // killough 10/98: moved to here + + char *nextfile; + boolean oldnotext = includenotext; // killough 10/98 + + // killough 10/98: exclude if inside wads (only to discourage + // the practice, since the code could otherwise handle it) + + if (infile.lump) + { + if (fileout) + fprintf(fileout, + "No files may be included from wads: %s\n",inbuffer); + continue; + } + + // check for no-text directive, used when including a DEH + // file but using the BEX format to handle strings + + if (!strnicmp(nextfile = ptr_lstrip(inbuffer+7),"NOTEXT",6)) + includenotext = true, nextfile = ptr_lstrip(nextfile+6); + + if (fileout) + fprintf(fileout,"Branching to include file %s...\n", nextfile); + + // killough 10/98: + // Second argument must be NULL to prevent closing fileout too soon + + ProcessDehFile(nextfile,NULL,0); // do the included file + + includenotext = oldnotext; + if (fileout) fprintf(fileout,"...continuing with %s\n",filename); + continue; + } + + for (i=0; i= NUMSTATES) + { + if (fpout) fprintf(fpout,"Bad pointer number %d of %d\n", + indexnum, NUMSTATES); + return; // killough 10/98: fix SegViol + } + strcpy(key,"A_"); // reusing the key area to prefix the mnemonic + strcat(key,ptr_lstrip(mnemonic)); + + found = FALSE; + i= -1; // incremented to start at zero at the top of the loop + do // Ty 05/16/98 - fix loop logic to look for null ending entry + { + ++i; + if (!stricmp(key,deh_bexptrs[i].lookup)) + { // Ty 06/01/98 - add to states[].action for new djgcc version + states[indexnum].action = deh_bexptrs[i].cptr; // assign + if (fpout) fprintf(fpout, + " - applied %s from codeptr[%d] to states[%d]\n", + deh_bexptrs[i].lookup,i,indexnum); + found = TRUE; + } + } while (!found && (deh_bexptrs[i].cptr != NULL)); + + if (!found) + if (fpout) fprintf(fpout, + "Invalid frame pointer mnemonic '%s' at %d\n", + mnemonic, indexnum); + } + return; +} + +//--------------------------------------------------------------------------- +// To be on the safe, compatible side, we manually convert DEH bitflags +// to prboom types - POPE +//--------------------------------------------------------------------------- +static uint_64_t getConvertedDEHBits(uint_64_t bits) { + static const uint_64_t bitMap[32] = { + /* cf linuxdoom-1.10 p_mobj.h */ + MF_SPECIAL, // 0 Can be picked up - When touched the thing can be picked up. + MF_SOLID, // 1 Obstacle - The thing is solid and will not let you (or others) pass through it + MF_SHOOTABLE, // 2 Shootable - Can be shot. + MF_NOSECTOR, // 3 Total Invisibility - Invisible, but can be touched + MF_NOBLOCKMAP, // 4 Don't use the blocklinks (inert but displayable) + MF_AMBUSH, // 5 Semi deaf - The thing is a deaf monster + MF_JUSTHIT, // 6 In pain - Will try to attack right back after being hit + MF_JUSTATTACKED, // 7 Steps before attack - Will take at least one step before attacking + MF_SPAWNCEILING, // 8 Hangs from ceiling - When the level starts, this thing will be at ceiling height. + MF_NOGRAVITY, // 9 No gravity - Gravity does not affect this thing + MF_DROPOFF, // 10 Travels over cliffs - Monsters normally do not walk off ledges/steps they could not walk up. With this set they can walk off any height of cliff. Usually only used for flying monsters. + MF_PICKUP, // 11 Pick up items - The thing can pick up gettable items. + MF_NOCLIP, // 12 No clipping - Thing can walk through walls. + MF_SLIDE, // 13 Slides along walls - Keep info about sliding along walls (don't really know much about this one). + MF_FLOAT, // 14 Floating - Thing can move to any height + MF_TELEPORT, // 15 Semi no clipping - Don't cross lines or look at teleport heights. (don't really know much about this one either). + MF_MISSILE, // 16 Projectiles - Behaves like a projectile, explodes when hitting something that blocks movement + MF_DROPPED, // 17 Disappearing weapon - Dropped, not spawned (like an ammo clip) I have not had much success in using this one. + MF_SHADOW, // 18 Partial invisibility - Drawn like a spectre. + MF_NOBLOOD, // 19 Puffs (vs. bleeds) - If hit will spawn bullet puffs instead of blood splats. + MF_CORPSE, // 20 Sliding helpless - Will slide down steps when dead. + MF_INFLOAT, // 21 No auto levelling - float but not to target height (?) + MF_COUNTKILL, // 22 Affects kill % - counted as a killable enemy and affects percentage kills on level summary. + MF_COUNTITEM, // 23 Affects item % - affects percentage items gathered on level summary. + MF_SKULLFLY, // 24 Running - special handling for flying skulls. + MF_NOTDMATCH, // 25 Not in deathmatch - do not spawn in deathmatch (like keys) + MF_TRANSLATION1, // 26 Color 1 (grey / red) + MF_TRANSLATION2, // 27 Color 2 (brown / red) + // Convert bit 28 to MF_TOUCHY, not (MF_TRANSLATION1|MF_TRANSLATION2) + // fixes bug #1576151 (part 1) + MF_TOUCHY, // 28 - explodes on contact (MBF) + MF_BOUNCES, // 29 - bounces off walls and floors (MBF) + MF_FRIEND, // 30 - friendly monster helps players (MBF) + MF_TRANSLUCENT // e6y: Translucency via dehacked/bex doesn't work without it + }; + int i; + uint_64_t shiftBits = bits; + uint_64_t convertedBits = 0; + for (i=0; i<32; i++) { + if (shiftBits & 0x1) convertedBits |= bitMap[i]; + shiftBits >>= 1; + } + return convertedBits; +} + +//--------------------------------------------------------------------------- +// See usage below for an explanation of this function's existence - POPE +//--------------------------------------------------------------------------- +static void setMobjInfoValue(int mobjInfoIndex, int keyIndex, uint_64_t value) { + mobjinfo_t *mi; + if (mobjInfoIndex >= NUMMOBJTYPES || mobjInfoIndex < 0) return; + mi = &mobjinfo[mobjInfoIndex]; + switch (keyIndex) { + case 0: mi->doomednum = (int)value; return; + case 1: mi->spawnstate = (int)value; return; + case 2: mi->spawnhealth = (int)value; return; + case 3: mi->seestate = (int)value; return; + case 4: mi->seesound = (int)value; return; + case 5: mi->reactiontime = (int)value; return; + case 6: mi->attacksound = (int)value; return; + case 7: mi->painstate = (int)value; return; + case 8: mi->painchance = (int)value; return; + case 9: mi->painsound = (int)value; return; + case 10: mi->meleestate = (int)value; return; + case 11: mi->missilestate = (int)value; return; + case 12: mi->deathstate = (int)value; return; + case 13: mi->xdeathstate = (int)value; return; + case 14: mi->deathsound = (int)value; return; + case 15: mi->speed = (int)value; return; + case 16: mi->radius = (int)value; return; + case 17: mi->height = (int)value; return; + case 18: mi->mass = (int)value; return; + case 19: mi->damage = (int)value; return; + case 20: mi->activesound = (int)value; return; + case 21: mi->flags = value; return; + case 22: return; // "Bits2", unused + case 23: mi->raisestate = (int)value; return; + default: return; + } +} + +// ==================================================================== +// deh_procThing +// Purpose: Handle DEH Thing block +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +// Ty 8/27/98 - revised to also allow mnemonics for +// bit masks for monster attributes +// + +static void deh_procThing(DEHFILE *fpin, FILE* fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + int indexnum; + int ix; + char *strval; + + strncpy(inbuffer,line,DEH_BUFFERMAX); + if (fpout) fprintf(fpout,"Thing line: '%s'\n",inbuffer); + + // killough 8/98: allow hex numbers in input: + ix = sscanf(inbuffer,"%s %i",key, &indexnum); + if (fpout) fprintf(fpout,"count=%d, Thing %d\n",ix, indexnum); + + // Note that the mobjinfo[] array is base zero, but object numbers + // in the dehacked file start with one. Grumble. + --indexnum; + + // now process the stuff + // Note that for Things we can look up the key and use its offset + // in the array of key strings as an int offset in the structure + + // get a line until a blank or end of file--it's not + // blank now because it has our incoming key in it + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero + // No more desync on HACX demos. + int bGetData; + + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); // toss the end of line + + // killough 11/98: really bail out on blank lines (break != continue) + if (!*inbuffer) break; // bail out with blank line between sections + + // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero + // No more desync on HACX demos. + bGetData = deh_GetData(inbuffer,key,&value,&strval,fpout); + if (!bGetData) + // Old code: if (!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + for (ix=0; ix>32) & 0xffffffff, + (unsigned long)deh_mobjflags[iy].value & 0xffffffff, strval + ); + } + value |= deh_mobjflags[iy].value; + break; + } + if (iy >= DEH_MOBJFLAGMAX && fpout) { + fprintf(fpout, "Could not find bit mnemonic %s\n", strval); + } + } + + // Don't worry about conversion -- simply print values + if (fpout) { + fprintf(fpout, + "Bits = 0x%08lX%08lX\n", + (unsigned long)(value>>32) & 0xffffffff, + (unsigned long)value & 0xffffffff + ); + } + mobjinfo[indexnum].flags = value; // e6y + } + } + if (fpout) { + fprintf(fpout, + "Assigned 0x%08lx%08lx to %s(%d) at index %d\n", + (unsigned long)(value>>32) & 0xffffffff, + (unsigned long)value & 0xffffffff, key, indexnum, ix + ); + } + } + } + return; +} + +// ==================================================================== +// deh_procFrame +// Purpose: Handle DEH Frame block +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procFrame(DEHFILE *fpin, FILE* fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + int indexnum; + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + // killough 8/98: allow hex numbers in input: + sscanf(inbuffer,"%s %i",key, &indexnum); + if (fpout) fprintf(fpout,"Processing Frame at index %d: %s\n",indexnum,key); + if (indexnum < 0 || indexnum >= NUMSTATES) + if (fpout) fprintf(fpout,"Bad frame number %d of %d\n",indexnum, NUMSTATES); + + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + if (!strcasecmp(key,deh_state[0])) // Sprite number + { + if (fpout) fprintf(fpout," - sprite = %lld\n",value); + states[indexnum].sprite = (spritenum_t)value; + } + else + if (!strcasecmp(key,deh_state[1])) // Sprite subnumber + { + if (fpout) fprintf(fpout," - frame = %lld\n",value); + states[indexnum].frame = (long)value; // long + } + else + if (!strcasecmp(key,deh_state[2])) // Duration + { + if (fpout) fprintf(fpout," - tics = %lld\n",value); + states[indexnum].tics = (long)value; // long + } + else + if (!strcasecmp(key,deh_state[3])) // Next frame + { + if (fpout) fprintf(fpout," - nextstate = %lld\n",value); + states[indexnum].nextstate = (statenum_t)value; + } + else + if (!strcasecmp(key,deh_state[4])) // Codep frame (not set in Frame deh block) + { + if (fpout) fprintf(fpout," - codep, should not be set in Frame section!\n"); + /* nop */ ; + } + else + if (!strcasecmp(key,deh_state[5])) // Unknown 1 + { + if (fpout) fprintf(fpout," - misc1 = %lld\n",value); + states[indexnum].misc1 = (long)value; // long + } + else + if (!strcasecmp(key,deh_state[6])) // Unknown 2 + { + if (fpout) fprintf(fpout," - misc2 = %lld\n",value); + states[indexnum].misc2 = (long)value; // long + } + else + if (fpout) fprintf(fpout,"Invalid frame string index for '%s'\n",key); + } + return; +} + +// ==================================================================== +// deh_procPointer +// Purpose: Handle DEH Code pointer block, can use BEX [CODEPTR] instead +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procPointer(DEHFILE *fpin, FILE* fpout, char *line) // done +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + int indexnum; + int i; // looper + + strncpy(inbuffer,line,DEH_BUFFERMAX); + // NOTE: different format from normal + + // killough 8/98: allow hex numbers in input, fix error case: + if (sscanf(inbuffer,"%*s %*i (%s %i)",key, &indexnum) != 2) + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + return; + } + + if (fpout) fprintf(fpout,"Processing Pointer at index %d: %s\n",indexnum, key); + if (indexnum < 0 || indexnum >= NUMSTATES) + { + if (fpout) + fprintf(fpout,"Bad pointer number %d of %d\n",indexnum, NUMSTATES); + return; + } + + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + + if (value < 0 || value >= NUMSTATES) + { + if (fpout) + fprintf(fpout,"Bad pointer number %lld of %d\n",value, NUMSTATES); + return; + } + + if (!strcasecmp(key,deh_state[4])) // Codep frame (not set in Frame deh block) + { + states[indexnum].action = deh_codeptr[value]; + if (fpout) fprintf(fpout," - applied from codeptr[%lld] to states[%d]\n", + value,indexnum); + // Write BEX-oriented line to match: + // for (i=0;i FRAME %d = %s\n", + indexnum, &deh_bexptrs[i].lookup[2]); + break; + } + if (deh_bexptrs[i].cptr == NULL) // stop at null entry + break; + } + } + else + if (fpout) fprintf(fpout,"Invalid frame pointer index for '%s' at %lld\n", + key, value); + } + return; +} + +// ==================================================================== +// deh_procSounds +// Purpose: Handle DEH Sounds block +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procSounds(DEHFILE *fpin, FILE* fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + int indexnum; + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + // killough 8/98: allow hex numbers in input: + sscanf(inbuffer,"%s %i",key, &indexnum); + if (fpout) fprintf(fpout,"Processing Sounds at index %d: %s\n", + indexnum, key); + if (indexnum < 0 || indexnum >= NUMSFX) + if (fpout) fprintf(fpout,"Bad sound number %d of %d\n", + indexnum, NUMSFX); + + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + if (!strcasecmp(key,deh_sfxinfo[0])) // Offset + /* nop */ ; // we don't know what this is, I don't think + else + if (!strcasecmp(key,deh_sfxinfo[1])) // Zero/One + S_sfx[indexnum].singularity = (int)value; + else + if (!strcasecmp(key,deh_sfxinfo[2])) // Value + S_sfx[indexnum].priority = (int)value; + else + if (!strcasecmp(key,deh_sfxinfo[3])) // Zero 1 + S_sfx[indexnum].link = (sfxinfo_t *)value; + else + if (!strcasecmp(key,deh_sfxinfo[4])) // Zero 2 + S_sfx[indexnum].pitch = (int)value; + else + if (!strcasecmp(key,deh_sfxinfo[5])) // Zero 3 + S_sfx[indexnum].volume = (int)value; + else + if (!strcasecmp(key,deh_sfxinfo[6])) // Zero 4 + S_sfx[indexnum].data = (void *) value; // killough 5/3/98: changed cast + else + if (!strcasecmp(key,deh_sfxinfo[7])) // Neg. One 1 + S_sfx[indexnum].usefulness = (int)value; + else + if (!strcasecmp(key,deh_sfxinfo[8])) // Neg. One 2 + S_sfx[indexnum].lumpnum = (int)value; + else + if (fpout) fprintf(fpout, + "Invalid sound string index for '%s'\n",key); + } + return; +} + +// ==================================================================== +// deh_procAmmo +// Purpose: Handle DEH Ammo block +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procAmmo(DEHFILE *fpin, FILE* fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + int indexnum; + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + // killough 8/98: allow hex numbers in input: + sscanf(inbuffer,"%s %i",key, &indexnum); + if (fpout) fprintf(fpout,"Processing Ammo at index %d: %s\n", + indexnum, key); + if (indexnum < 0 || indexnum >= NUMAMMO) + if (fpout) fprintf(fpout,"Bad ammo number %d of %d\n", + indexnum,NUMAMMO); + + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + if (!strcasecmp(key,deh_ammo[0])) // Max ammo + maxammo[indexnum] = (int)value; + else + if (!strcasecmp(key,deh_ammo[1])) // Per ammo + clipammo[indexnum] = (int)value; + else + if (fpout) fprintf(fpout,"Invalid ammo string index for '%s'\n",key); + } + return; +} + +// ==================================================================== +// deh_procWeapon +// Purpose: Handle DEH Weapon block +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procWeapon(DEHFILE *fpin, FILE* fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + int indexnum; + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + // killough 8/98: allow hex numbers in input: + sscanf(inbuffer,"%s %i",key, &indexnum); + if (fpout) fprintf(fpout,"Processing Weapon at index %d: %s\n", + indexnum, key); + if (indexnum < 0 || indexnum >= NUMWEAPONS) + if (fpout) fprintf(fpout,"Bad weapon number %d of %d\n", + indexnum, NUMAMMO); + + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + if (!strcasecmp(key,deh_weapon[0])) // Ammo type + weaponinfo[indexnum].ammo = (ammotype_t)value; + else + if (!strcasecmp(key,deh_weapon[1])) // Deselect frame + weaponinfo[indexnum].upstate = (int)value; + else + if (!strcasecmp(key,deh_weapon[2])) // Select frame + weaponinfo[indexnum].downstate = (int)value; + else + if (!strcasecmp(key,deh_weapon[3])) // Bobbing frame + weaponinfo[indexnum].readystate = (int)value; + else + if (!strcasecmp(key,deh_weapon[4])) // Shooting frame + weaponinfo[indexnum].atkstate = (int)value; + else + if (!strcasecmp(key,deh_weapon[5])) // Firing frame + weaponinfo[indexnum].flashstate = (int)value; + else + if (fpout) fprintf(fpout,"Invalid weapon string index for '%s'\n",key); + } + return; +} + +// ==================================================================== +// deh_procSprite +// Purpose: Dummy - we do not support the DEH Sprite block +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procSprite(DEHFILE *fpin, FILE* fpout, char *line) // Not supported +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + int indexnum; + + // Too little is known about what this is supposed to do, and + // there are better ways of handling sprite renaming. Not supported. + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + // killough 8/98: allow hex numbers in input: + sscanf(inbuffer,"%s %i",key, &indexnum); + if (fpout) fprintf(fpout, + "Ignoring Sprite offset change at index %d: %s\n",indexnum, key); + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + // ignore line + if (fpout) fprintf(fpout,"- %s\n",inbuffer); + } + return; +} + +// ==================================================================== +// deh_procPars +// Purpose: Handle BEX extension for PAR times +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procPars(DEHFILE *fpin, FILE* fpout, char *line) // extension +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + int indexnum; + int episode, level, partime, oldpar; + + // new item, par times + // usage: After [PARS] Par 0 section identifier, use one or more of these + // lines: + // par 3 5 120 + // par 14 230 + // The first would make the par for E3M5 be 120 seconds, and the + // second one makes the par for MAP14 be 230 seconds. The number + // of parameters on the line determines which group of par values + // is being changed. Error checking is done based on current fixed + // array sizes of[4][10] and [32] + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + // killough 8/98: allow hex numbers in input: + sscanf(inbuffer,"%s %i",key, &indexnum); + if (fpout) fprintf(fpout, + "Processing Par value at index %d: %s\n",indexnum, key); + // indexnum is a dummy entry + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(strlwr(inbuffer)); // lowercase it + if (!*inbuffer) break; // killough 11/98 + if (3 != sscanf(inbuffer,"par %i %i %i",&episode, &level, &partime)) + { // not 3 + if (2 != sscanf(inbuffer,"par %i %i",&level, &partime)) + { // not 2 + if (fpout) fprintf(fpout,"Invalid par time setting string: %s\n",inbuffer); + } + else + { // is 2 + // Ty 07/11/98 - wrong range check, not zero-based + if (level < 1 || level > 32) // base 0 array (but 1-based parm) + { + if (fpout) fprintf(fpout,"Invalid MAPnn value MAP%d\n",level); + } + else + { + oldpar = cpars[level-1]; + if (fpout) fprintf(fpout,"Changed par time for MAP%02d from %d to %d\n",level,oldpar,partime); + cpars[level-1] = partime; + deh_pars = TRUE; + } + } + } + else + { // is 3 + // note that though it's a [4][10] array, the "left" and "top" aren't used, + // effectively making it a base 1 array. + // Ty 07/11/98 - level was being checked against max 3 - dumb error + // Note that episode 4 does not have par times per original design + // in Ultimate DOOM so that is not supported here. + if (episode < 1 || episode > 3 || level < 1 || level > 9) + { + if (fpout) fprintf(fpout, + "Invalid ExMx values E%dM%d\n",episode, level); + } + else + { + oldpar = pars[episode][level]; + pars[episode][level] = partime; + if (fpout) fprintf(fpout, + "Changed par time for E%dM%d from %d to %d\n", + episode,level,oldpar,partime); + deh_pars = TRUE; + } + } + } + return; +} + +// ==================================================================== +// deh_procCheat +// Purpose: Handle DEH Cheat block +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procCheat(DEHFILE *fpin, FILE* fpout, char *line) // done +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + char ch = 0; // CPhipps - `writable' null string to initialise... + char *strval = &ch; // pointer to the value area + int ix, iy; // array indices + char *p; // utility pointer + + if (fpout) fprintf(fpout,"Processing Cheat: %s\n",line); + + strncpy(inbuffer,line,DEH_BUFFERMAX); + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + if (!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + // Otherwise we got a (perhaps valid) cheat name, + // so look up the key in the array + + // killough 4/18/98: use main cheat code table in st_stuff.c now + for (ix=0; cheat[ix].cheat; ix++) + if (cheat[ix].deh_cheat) // killough 4/18/98: skip non-deh + { + if (!stricmp(key,cheat[ix].deh_cheat)) // found the cheat, ignored case + { + // replace it but don't overflow it. Use current length as limit. + // Ty 03/13/98 - add 0xff code + // Deal with the fact that the cheats in deh files are extended + // with character 0xFF to the original cheat length, which we don't do. + for (iy=0; strval[iy]; iy++) + strval[iy] = (strval[iy]==(char)0xff) ? '\0' : strval[iy]; + + iy = ix; // killough 4/18/98 + + // Ty 03/14/98 - skip leading spaces + p = strval; + while (*p == ' ') ++p; + // Ty 03/16/98 - change to use a strdup and orphan the original + // Also has the advantage of allowing length changes. + // strncpy(cheat[iy].cheat,p,strlen(cheat[iy].cheat)); +#if 0 + { // killough 9/12/98: disable cheats which are prefixes of this one + int i; + for (i=0; cheat[i].cheat; i++) + if (cheat[i].when & not_deh && + !strncasecmp(cheat[i].cheat, + cheat[iy].cheat, + strlen(cheat[i].cheat)) && i != iy) + cheat[i].deh_modified = true; + } +#endif + cheat[iy].cheat = strdup(p); + if (fpout) fprintf(fpout, + "Assigned new cheat '%s' to cheat '%s'at index %d\n", + p, cheat[ix].deh_cheat, iy); // killough 4/18/98 + } + } + if (fpout) fprintf(fpout,"- %s\n",inbuffer); + } + return; +} + +// ==================================================================== +// deh_procMisc +// Purpose: Handle DEH Misc block +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procMisc(DEHFILE *fpin, FILE* fpout, char *line) // done +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + + strncpy(inbuffer,line,DEH_BUFFERMAX); + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + // Otherwise it's ok + if (fpout) fprintf(fpout,"Processing Misc item '%s'\n", key); + + if (!strcasecmp(key,deh_misc[0])) // Initial Health + initial_health = (int)value; + else + if (!strcasecmp(key,deh_misc[1])) // Initial Bullets + initial_bullets = (int)value; + else + if (!strcasecmp(key,deh_misc[2])) // Max Health + maxhealth = (int)value; + else + if (!strcasecmp(key,deh_misc[3])) // Max Armor + max_armor = (int)value; + else + if (!strcasecmp(key,deh_misc[4])) // Green Armor Class + green_armor_class = (int)value; + else + if (!strcasecmp(key,deh_misc[5])) // Blue Armor Class + blue_armor_class = (int)value; + else + if (!strcasecmp(key,deh_misc[6])) // Max Soulsphere + max_soul = (int)value; + else + if (!strcasecmp(key,deh_misc[7])) // Soulsphere Health + soul_health = (int)value; + else + if (!strcasecmp(key,deh_misc[8])) // Megasphere Health + mega_health = (int)value; + else + if (!strcasecmp(key,deh_misc[9])) // God Mode Health + god_health = (int)value; + else + if (!strcasecmp(key,deh_misc[10])) // IDFA Armor + idfa_armor = (int)value; + else + if (!strcasecmp(key,deh_misc[11])) // IDFA Armor Class + idfa_armor_class = (int)value; + else + if (!strcasecmp(key,deh_misc[12])) // IDKFA Armor + idkfa_armor = (int)value; + else + if (!strcasecmp(key,deh_misc[13])) // IDKFA Armor Class + idkfa_armor_class = (int)value; + else + if (!strcasecmp(key,deh_misc[14])) // BFG Cells/Shot + bfgcells = (int)value; + else + if (!strcasecmp(key,deh_misc[15])) { // Monsters Infight + // e6y: Dehacked support - monsters infight + if (value == 202) monsters_infight = 0; + else if (value == 221) monsters_infight = 1; + else if (fpout) fprintf(fpout, + "Invalid value for 'Monsters Infight': %i", (int)value); + + /* No such switch in DOOM - nop */ //e6y ; + } else + if (fpout) fprintf(fpout, + "Invalid misc item string index for '%s'\n",key); + } + return; +} + +// ==================================================================== +// deh_procText +// Purpose: Handle DEH Text block +// Notes: We look things up in the current information and if found +// we replace it. At the same time we write the new and +// improved BEX syntax to the log file for future use. +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procText(DEHFILE *fpin, FILE* fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX*2]; // can't use line -- double size buffer too. + int i; // loop variable + int fromlen, tolen; // as specified on the text block line + int usedlen; // shorter of fromlen and tolen if not matched + boolean found = FALSE; // to allow early exit once found + char* line2 = NULL; // duplicate line for rerouting + + // Ty 04/11/98 - Included file may have NOTEXT skip flag set + if (includenotext) // flag to skip included deh-style text + { + if (fpout) fprintf(fpout, + "Skipped text block because of notext directive\n"); + strcpy(inbuffer,line); + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + dehfgets(inbuffer, sizeof(inbuffer), fpin); // skip block + // Ty 05/17/98 - don't care if this fails + return; // ************** Early return + } + + // killough 8/98: allow hex numbers in input: + sscanf(line,"%s %i %i",key,&fromlen,&tolen); + if (fpout) fprintf(fpout, + "Processing Text (key=%s, from=%d, to=%d)\n", + key, fromlen, tolen); + + // killough 10/98: fix incorrect usage of feof + { + int c, totlen = 0; + while (totlen < fromlen + tolen && (c = dehfgetc(fpin)) != EOF) + if (c != '\r') + inbuffer[totlen++] = c; + inbuffer[totlen]='\0'; + } + + // if the from and to are 4, this may be a sprite rename. Check it + // against the array and process it as such if it matches. Remember + // that the original names are (and should remain) uppercase. + // Future: this will be from a separate [SPRITES] block. + if (fromlen==4 && tolen==4) + { + i=0; + while (sprnames[i]) // null terminated list in info.c //jff 3/19/98 + { //check pointer + if (!strnicmp(sprnames[i],inbuffer,fromlen)) //not first char + { + if (fpout) fprintf(fpout, + "Changing name of sprite at index %d from %s to %*s\n", + i,sprnames[i],tolen,&inbuffer[fromlen]); + // Ty 03/18/98 - not using strdup because length is fixed + + // killough 10/98: but it's an array of pointers, so we must + // use strdup unless we redeclare sprnames and change all else + { + // CPhipps - fix constness problem + char *s; + sprnames[i] = s = strdup(sprnames[i]); + + strncpy(s,&inbuffer[fromlen],tolen); + } + found = TRUE; + break; // only one will match--quit early + } + ++i; // next array element + } + } + else + if (fromlen < 7 && tolen < 7) // lengths of music and sfx are 6 or shorter + { + usedlen = (fromlen < tolen) ? fromlen : tolen; + if (fromlen != tolen) + if (fpout) fprintf(fpout, + "Warning: Mismatched lengths from=%d, to=%d, used %d\n", + fromlen, tolen, usedlen); + // Try sound effects entries - see sounds.c + for (i=1; i 12) ? "..." : "",fromlen,tolen); + if ((size_t)fromlen <= strlen(inbuffer)) + { + line2 = strdup(&inbuffer[fromlen]); + inbuffer[fromlen] = '\0'; + } + + deh_procStringSub(NULL, inbuffer, line2, fpout); + } + free(line2); // may be NULL, ignored by free() + return; +} + +static void deh_procError(DEHFILE *fpin, FILE* fpout, char *line) +{ + char inbuffer[DEH_BUFFERMAX]; + + strncpy(inbuffer,line,DEH_BUFFERMAX); + if (fpout) fprintf(fpout,"Unmatched Block: '%s'\n",inbuffer); + return; +} + +// ==================================================================== +// deh_procStrings +// Purpose: Handle BEX [STRINGS] extension +// Args: fpin -- input file stream +// fpout -- output file stream (DEHOUT.TXT) +// line -- current line in file to process +// Returns: void +// +static void deh_procStrings(DEHFILE *fpin, FILE* fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + char *strval; // holds the string value of the line + static int maxstrlen = 128; // maximum string length, bumped 128 at + // a time as needed + // holds the final result of the string after concatenation + static char *holdstring = NULL; + boolean found = false; // looking for string continuation + + if (fpout) fprintf(fpout,"Processing extended string substitution\n"); + + if (!holdstring) holdstring = malloc(maxstrlen*sizeof(*holdstring)); + + *holdstring = '\0'; // empty string to start with + strncpy(inbuffer,line,DEH_BUFFERMAX); + // Ty 04/24/98 - have to allow inbuffer to start with a blank for + // the continuations of C1TEXT etc. + while (!dehfeof(fpin) && *inbuffer) /* && (*inbuffer != ' ') */ + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + if (*inbuffer == '#') continue; // skip comment lines + lfstrip(inbuffer); + if (!*inbuffer) break; // killough 11/98 + if (!*holdstring) // first one--get the key + { + if (!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + } + while (strlen(holdstring) + strlen(inbuffer) > (size_t)maxstrlen) // Ty03/29/98 - fix stupid error + { + // killough 11/98: allocate enough the first time + maxstrlen += strlen(holdstring) + strlen(inbuffer) - maxstrlen; + if (fpout) fprintf(fpout, + "* increased buffer from to %d for buffer size %d\n", + maxstrlen,(int)strlen(inbuffer)); + holdstring = realloc(holdstring,maxstrlen*sizeof(*holdstring)); + } + // concatenate the whole buffer if continuation or the value iffirst + strcat(holdstring,ptr_lstrip(((*holdstring) ? inbuffer : strval))); + rstrip(holdstring); + // delete any trailing blanks past the backslash + // note that blanks before the backslash will be concatenated + // but ones at the beginning of the next line will not, allowing + // indentation in the file to read well without affecting the + // string itself. + if (holdstring[strlen(holdstring)-1] == '\\') + { + holdstring[strlen(holdstring)-1] = '\0'; + continue; // ready to concatenate + } + if (*holdstring) // didn't have a backslash, trap above would catch that + { + // go process the current string + found = deh_procStringSub(key, NULL, holdstring, fpout); // supply keyand not search string + + if (!found) + if (fpout) fprintf(fpout, + "Invalid string key '%s', substitution skipped.\n",key); + + *holdstring = '\0'; // empty string for the next one + } + } + return; +} + +// ==================================================================== +// deh_procStringSub +// Purpose: Common string parsing and handling routine for DEH and BEX +// Args: key -- place to put the mnemonic for the string if found +// lookfor -- original value string to look for +// newstring -- string to put in its place if found +// fpout -- file stream pointer for log file (DEHOUT.TXT) +// Returns: boolean: True if string found, false if not +// +boolean deh_procStringSub(char *key, char *lookfor, char *newstring, FILE *fpout) +{ + boolean found; // loop exit flag + int i; // looper + + found = false; + for (i=0;i '%s'\n",key,newstring); + + if (!key) + if (fpout) fprintf(fpout, + "Assigned '%.12s%s' to'%.12s%s' at key %s\n", + lookfor, (strlen(lookfor) > 12) ? "..." : "", + newstring, (strlen(newstring) > 12) ? "..." :"", + deh_strlookup[i].lookup); + + if (!key) // must have passed an old style string so showBEX + if (fpout) fprintf(fpout, + "*BEX FORMAT:\n%s = %s\n*END BEX\n", + deh_strlookup[i].lookup, + dehReformatStr(newstring)); + + break; + } + } + if (!found) + if (fpout) fprintf(fpout, + "Could not find '%.12s'\n",key ? key: lookfor); + + return found; +} + +//======================================================================== +// haleyjd 9/22/99 +// +// deh_procHelperThing +// +// Allows handy substitution of any thing for helper dogs. DEH patches +// are being made frequently for this purpose and it requires a complete +// rewiring of the DOG thing. I feel this is a waste of effort, and so +// have added this new [HELPER] BEX block + +static void deh_procHelperThing(DEHFILE *fpin, FILE *fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + + strncpy(inbuffer,line,DEH_BUFFERMAX); + while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; + lfstrip(inbuffer); + if (!*inbuffer) break; + if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok + { + if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + // Otherwise it's ok + if (fpout) + { + fprintf(fpout,"Processing Helper Thing item '%s'\n", key); + fprintf(fpout,"value is %i", (int)value); + } + if (!strncasecmp(key, "type", 4)) + HelperThing = (int)value; + } + return; +} + +// +// deh_procBexSprites +// +// Supports sprite name substitutions without requiring use +// of the DeHackEd Text block +// +static void deh_procBexSprites(DEHFILE *fpin, FILE *fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + char *strval; // holds the string value of the line + char candidate[5]; + int rover; + + if(fpout) + fprintf(fpout,"Processing sprite name substitution\n"); + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + while(!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if(!dehfgets(inbuffer, sizeof(inbuffer), fpin)) + break; + if(*inbuffer == '#') + continue; // skip comment lines + lfstrip(inbuffer); + if(!*inbuffer) + break; // killough 11/98 + if(!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok + { + if(fpout) + fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + // do it + memset(candidate, 0, sizeof(candidate)); + strncpy(candidate, ptr_lstrip(strval), 4); + if(strlen(candidate) != 4) + { + if(fpout) + fprintf(fpout, "Bad length for sprite name '%s'\n", + candidate); + continue; + } + + rover = 0; + while(deh_spritenames[rover]) + { + if(!strncasecmp(deh_spritenames[rover], key, 4)) + { + if(fpout) + fprintf(fpout, "Substituting '%s' for sprite '%s'\n", + candidate, deh_spritenames[rover]); + + sprnames[rover] = strdup(candidate); + break; + } + rover++; + } + } +} + +// ditto for sound names +static void deh_procBexSounds(DEHFILE *fpin, FILE *fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + char *strval; // holds the string value of the line + char candidate[7]; + int rover, len; + + if(fpout) + fprintf(fpout,"Processing sound name substitution\n"); + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + while(!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if(!dehfgets(inbuffer, sizeof(inbuffer), fpin)) + break; + if(*inbuffer == '#') + continue; // skip comment lines + lfstrip(inbuffer); + if(!*inbuffer) + break; // killough 11/98 + if(!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok + { + if(fpout) + fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + // do it + memset(candidate, 0, 7); + strncpy(candidate, ptr_lstrip(strval), 6); + len = strlen(candidate); + if(len < 1 || len > 6) + { + if(fpout) + fprintf(fpout, "Bad length for sound name '%s'\n", + candidate); + continue; + } + + rover = 1; + while(deh_soundnames[rover]) + { + if(!strncasecmp(deh_soundnames[rover], key, 6)) + { + if(fpout) + fprintf(fpout, "Substituting '%s' for sound '%s'\n", + candidate, deh_soundnames[rover]); + + S_sfx[rover].name = strdup(candidate); + break; + } + rover++; + } + } +} + +// ditto for music names +static void deh_procBexMusic(DEHFILE *fpin, FILE *fpout, char *line) +{ + char key[DEH_MAXKEYLEN]; + char inbuffer[DEH_BUFFERMAX]; + uint_64_t value; // All deh values are ints or longs + char *strval; // holds the string value of the line + char candidate[7]; + int rover, len; + + if(fpout) + fprintf(fpout,"Processing music name substitution\n"); + + strncpy(inbuffer,line,DEH_BUFFERMAX); + + while(!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) + { + if(!dehfgets(inbuffer, sizeof(inbuffer), fpin)) + break; + if(*inbuffer == '#') + continue; // skip comment lines + lfstrip(inbuffer); + if(!*inbuffer) + break; // killough 11/98 + if(!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok + { + if(fpout) + fprintf(fpout,"Bad data pair in '%s'\n",inbuffer); + continue; + } + // do it + memset(candidate, 0, 7); + strncpy(candidate, ptr_lstrip(strval), 6); + len = strlen(candidate); + if(len < 1 || len > 6) + { + if(fpout) + fprintf(fpout, "Bad length for music name '%s'\n", + candidate); + continue; + } + + rover = 1; + while(deh_musicnames[rover]) + { + if(!strncasecmp(deh_musicnames[rover], key, 6)) + { + if(fpout) + fprintf(fpout, "Substituting '%s' for music '%s'\n", + candidate, deh_musicnames[rover]); + + S_music[rover].name = strdup(candidate); + break; + } + rover++; + } + } +} + +// ==================================================================== +// General utility function(s) +// ==================================================================== + +// ==================================================================== +// dehReformatStr +// Purpose: Convert a string into a continuous string with embedded +// linefeeds for "\n" sequences in the source string +// Args: string -- the string to convert +// Returns: the converted string (converted in a static buffer) +// +char *dehReformatStr(char *string) +{ + static char buff[DEH_BUFFERMAX]; // only processing the changed string, + // don't need double buffer + char *s, *t; + + s = string; // source + t = buff; // target + // let's play... + + while (*s) + { + if (*s == '\n') + ++s, *t++ = '\\', *t++ = 'n', *t++ = '\\', *t++='\n'; + else + *t++ = *s++; + } + *t = '\0'; + return buff; +} + +// ==================================================================== +// lfstrip +// Purpose: Strips CR/LF off the end of a string +// Args: s -- the string to work on +// Returns: void -- the string is modified in place +// +// killough 10/98: only strip at end of line, not entire string + +void lfstrip(char *s) // strip the \r and/or \n off of a line +{ + char *p = s+strlen(s); + while (p > s && (*--p=='\r' || *p=='\n')) + *p = 0; +} + +// ==================================================================== +// rstrip +// Purpose: Strips trailing blanks off a string +// Args: s -- the string to work on +// Returns: void -- the string is modified in place +// +void rstrip(char *s) // strip trailing whitespace +{ + char *p = s+strlen(s); // killough 4/4/98: same here + while (p > s && isspace(*--p)) // break on first non-whitespace + *p='\0'; +} + +// ==================================================================== +// ptr_lstrip +// Purpose: Points past leading whitespace in a string +// Args: s -- the string to work on +// Returns: char * pointing to the first nonblank character in the +// string. The original string is not changed. +// +char *ptr_lstrip(char *p) // point past leading whitespace +{ + while (isspace(*p)) + p++; + return p; +} + +// e6y: Correction of wrong processing of Bits parameter if its value is equal to zero +// No more desync on HACX demos. +// FIXME!!! (lame) +static boolean StrToInt(char *s, long *l) +{ + return ( + (sscanf(s, " 0x%lx", l) == 1) || + (sscanf(s, " 0X%lx", l) == 1) || + (sscanf(s, " 0%lo", l) == 1) || + (sscanf(s, " %ld", l) == 1) + ); +} + +// ==================================================================== +// deh_GetData +// Purpose: Get a key and data pair from a passed string +// Args: s -- the string to be examined +// k -- a place to put the key +// l -- pointer to a long integer to store the number +// strval -- a pointer to the place in s where the number +// value comes from. Pass NULL to not use this. +// fpout -- stream pointer to output log (DEHOUT.TXT) +// Notes: Expects a key phrase, optional space, equal sign, +// optional space and a value, mostly an int but treated +// as a long just in case. The passed pointer to hold +// the key must be DEH_MAXKEYLEN in size. + +boolean deh_GetData(char *s, char *k, uint_64_t *l, char **strval, FILE *fpout) +{ + char *t; // current char + long val; // to hold value of pair + char buffer[DEH_MAXKEYLEN]; // to hold key in progress + // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero + // No more desync on HACX demos. + boolean okrc = 1; // assume good unless we have problems + int i; // iterator + + *buffer = '\0'; + val = 0; // defaults in case not otherwise set + for (i=0, t=s; *t && i < DEH_MAXKEYLEN; t++, i++) + { + if (*t == '=') break; + buffer[i] = *t; // copy it + } + buffer[--i] = '\0'; // terminate the key before the '=' + if (!*t) // end of string with no equal sign + { + okrc = FALSE; + } + else + { + if (!*++t) + { + val = 0; // in case "thiskey =" with no value + okrc = FALSE; + } + // we've incremented t + // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero + // No more desync on HACX demos. + // Old code: e6y val = strtol(t,NULL,0); // killough 8/9/98: allow hex or octal input + if (!StrToInt(t,&val)) + { + val = 0; + okrc = 2; + } + } + + // go put the results in the passed pointers + *l = val; // may be a faked zero + + // if spaces between key and equal sign, strip them + strcpy(k,ptr_lstrip(buffer)); // could be a zero-length string + + if (strval != NULL) // pass NULL if you don't want this back + *strval = t; // pointer, has to be somewhere in s, + // even if pointing at the zero byte. + + return(okrc); +} diff --git a/src/d_deh.h b/src/d_deh.h new file mode 100644 index 0000000..02cdffa --- /dev/null +++ b/src/d_deh.h @@ -0,0 +1,1118 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2006 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Dehacked file support + * New for the TeamTNT "Boom" engine + * + * Author: Ty Halderman, TeamTNT + * + * Description: This file translates the #defined string constants + * to named variables to externalize them for deh/bex changes. + * Should be able to compile with D_FRENCH (for example) and still + * work (untested). + * + */ + +#ifndef __D_DEH__ +#define __D_DEH__ + +void ProcessDehFile(const char *filename, const char *outfilename, int lumpnum); + +// +// Ty 03/22/98 - note that we are keeping the english versions and +// comments in this file +// New string names all start with an extra s_ to avoid conflicts, +// but are otherwise identical to the original including uppercase. +// This is partly to keep the changes simple and partly for easier +// identification of the locations in which they're used. +// +// Printed strings for translation +// + +// +// D_Main.C +// +//#define D_DEVSTR "Development mode ON.\n" +extern const char *s_D_DEVSTR; // = D_DEVSTR; +//#define D_CDROM "CD-ROM Version: default.cfg from c:\\doomdata\n" +extern const char *s_D_CDROM; // = D_CDROM; + +// +// M_Menu.C +// +//#define PRESSKEY "press a key." +extern const char *s_PRESSKEY; // = PRESSKEY; +//#define PRESSYN "press y or n." +extern const char *s_PRESSYN; // = PRESSYN; +//#define QUITMSG "are you sure you want to\nquit this great game?" +extern const char *s_QUITMSG; // = QUITMSG; +//#define LOADNET "you can't do load while in a net game!\n\n"PRESSKEY +extern const char *s_LOADNET; // = LOADNET; +//#define QLOADNET "you can't quickload during a netgame!\n\n"PRESSKEY +extern const char *s_QLOADNET; // = QLOADNET; +//#define QSAVESPOT "you haven't picked a quicksave slot yet!\n\n"PRESSKEY +extern const char *s_QSAVESPOT; // = QSAVESPOT; +//#define SAVEDEAD "you can't save if you aren't playing!\n\n"PRESSKEY +extern const char *s_SAVEDEAD; // = SAVEDEAD; +//#define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n"PRESSYN +extern const char *s_QSPROMPT; // = QSPROMPT; +//#define QLPROMPT "do you want to quickload the game named\n\n'%s'?\n\n"PRESSYN +extern const char *s_QLPROMPT; // = QLPROMPT; + +/* +#define NEWGAME \ +"you can't start a new game\n"\ +"while in a network game.\n\n"PRESSKEY +*/ +extern const char *s_NEWGAME; // = NEWGAME; + +// CPhipps - message given when asked if to restart the level +extern const char *s_RESTARTLEVEL; + +/* +#define NIGHTMARE \ +"are you sure? this skill level\n"\ +"isn't even remotely fair.\n\n"PRESSYN +*/ +extern const char *s_NIGHTMARE; // = NIGHTMARE; + +/* +#define SWSTRING \ +"this is the shareware version of doom.\n\n"\ +"you need to order the entire trilogy.\n\n"PRESSKEY +*/ +extern const char *s_SWSTRING; // = SWSTRING; + +//#define MSGOFF "Messages OFF" +extern const char *s_MSGOFF; // = MSGOFF; +//#define MSGON "Messages ON" +extern const char *s_MSGON; // = MSGON; +//#define NETEND "you can't end a netgame!\n\n"PRESSKEY +extern const char *s_NETEND; // = NETEND; +//#define ENDGAME "are you sure you want to end the game?\n\n"PRESSYN +extern const char *s_ENDGAME; // = ENDGAME; + +//#define DOSY "(press y to quit)" +extern const char *s_DOSY; // = DOSY; + +//#define DETAILHI "High detail" +extern const char *s_DETAILHI; // = DETAILHI; +//#define DETAILLO "Low detail" +extern const char *s_DETAILLO; // = DETAILLO; +//#define GAMMALVL0 "Gamma correction OFF" +extern const char *s_GAMMALVL0; // = GAMMALVL0; +//#define GAMMALVL1 "Gamma correction level 1" +extern const char *s_GAMMALVL1; // = GAMMALVL1; +//#define GAMMALVL2 "Gamma correction level 2" +extern const char *s_GAMMALVL2; // = GAMMALVL2; +//#define GAMMALVL3 "Gamma correction level 3" +extern const char *s_GAMMALVL3; // = GAMMALVL3; +//#define GAMMALVL4 "Gamma correction level 4" +extern const char *s_GAMMALVL4; // = GAMMALVL4; +//#define EMPTYSTRING "empty slot" +extern const char *s_EMPTYSTRING; // = EMPTYSTRING; + +// +// P_inter.C +// +//#define GOTARMOR "Picked up the armor." +extern const char *s_GOTARMOR; // = GOTARMOR; +//#define GOTMEGA "Picked up the MegaArmor!" +extern const char *s_GOTMEGA; // = GOTMEGA; +//#define GOTHTHBONUS "Picked up a health bonus." +extern const char *s_GOTHTHBONUS; // = GOTHTHBONUS; +//#define GOTARMBONUS "Picked up an armor bonus." +extern const char *s_GOTARMBONUS; // = GOTARMBONUS; +//#define GOTSTIM "Picked up a stimpack." +extern const char *s_GOTSTIM; // = GOTSTIM; +//#define GOTMEDINEED "Picked up a medikit that you REALLY need!" +extern const char *s_GOTMEDINEED; // = GOTMEDINEED; +//#define GOTMEDIKIT "Picked up a medikit." +extern const char *s_GOTMEDIKIT; // = GOTMEDIKIT; +//#define GOTSUPER "Supercharge!" +extern const char *s_GOTSUPER; // = GOTSUPER; + +//#define GOTBLUECARD "Picked up a blue keycard." +extern const char *s_GOTBLUECARD; // = GOTBLUECARD; +//#define GOTYELWCARD "Picked up a yellow keycard." +extern const char *s_GOTYELWCARD; // = GOTYELWCARD; +//#define GOTREDCARD "Picked up a red keycard." +extern const char *s_GOTREDCARD; // = GOTREDCARD; +//#define GOTBLUESKUL "Picked up a blue skull key." +extern const char *s_GOTBLUESKUL; // = GOTBLUESKUL; +//#define GOTYELWSKUL "Picked up a yellow skull key." +extern const char *s_GOTYELWSKUL; // = GOTYELWSKUL; +//#define GOTREDSKULL "Picked up a red skull key." +extern const char *s_GOTREDSKULL; // = GOTREDSKULL; + +//#define GOTINVUL "Invulnerability!" +extern const char *s_GOTINVUL; // = GOTINVUL; +//#define GOTBERSERK "Berserk!" +extern const char *s_GOTBERSERK; // = GOTBERSERK; +//#define GOTINVIS "Partial Invisibility" +extern const char *s_GOTINVIS; // = GOTINVIS; +//#define GOTSUIT "Radiation Shielding Suit" +extern const char *s_GOTSUIT; // = GOTSUIT; +//#define GOTMAP "Computer Area Map" +extern const char *s_GOTMAP; // = GOTMAP; +//#define GOTVISOR "Light Amplification Visor" +extern const char *s_GOTVISOR; // = GOTVISOR; +//#define GOTMSPHERE "MegaSphere!" +extern const char *s_GOTMSPHERE; // = GOTMSPHERE; + +//#define GOTCLIP "Picked up a clip." +extern const char *s_GOTCLIP; // = GOTCLIP; +//#define GOTCLIPBOX "Picked up a box of bullets." +extern const char *s_GOTCLIPBOX; // = GOTCLIPBOX; +//#define GOTROCKET "Picked up a rocket." +extern const char *s_GOTROCKET; // = GOTROCKET; +//#define GOTROCKBOX "Picked up a box of rockets." +extern const char *s_GOTROCKBOX; // = GOTROCKBOX; +//#define GOTCELL "Picked up an energy cell." +extern const char *s_GOTCELL; // = GOTCELL; +//#define GOTCELLBOX "Picked up an energy cell pack." +extern const char *s_GOTCELLBOX; // = GOTCELLBOX; +//#define GOTSHELLS "Picked up 4 shotgun shells." +extern const char *s_GOTSHELLS; // = GOTSHELLS; +//#define GOTSHELLBOX "Picked up a box of shotgun shells." +extern const char *s_GOTSHELLBOX; // = GOTSHELLBOX; +//#define GOTBACKPACK "Picked up a backpack full of ammo!" +extern const char *s_GOTBACKPACK; // = GOTBACKPACK; + +//#define GOTBFG9000 "You got the BFG9000! Oh, yes." +extern const char *s_GOTBFG9000; // = GOTBFG9000; +//#define GOTCHAINGUN "You got the chaingun!" +extern const char *s_GOTCHAINGUN; // = GOTCHAINGUN; +//#define GOTCHAINSAW "A chainsaw! Find some meat!" +extern const char *s_GOTCHAINSAW; // = GOTCHAINSAW; +//#define GOTLAUNCHER "You got the rocket launcher!" +extern const char *s_GOTLAUNCHER; // = GOTLAUNCHER; +//#define GOTPLASMA "You got the plasma gun!" +extern const char *s_GOTPLASMA; // = GOTPLASMA; +//#define GOTSHOTGUN "You got the shotgun!" +extern const char *s_GOTSHOTGUN; // = GOTSHOTGUN; +//#define GOTSHOTGUN2 "You got the super shotgun!" +extern const char *s_GOTSHOTGUN2; // = GOTSHOTGUN2; + +// +// P_Doors.C +// +//#define PD_BLUEO "You need a blue key to activate this object" +extern const char *s_PD_BLUEO; // = PD_BLUEO; +//#define PD_REDO "You need a red key to activate this object" +extern const char *s_PD_REDO; // = PD_REDO; +//#define PD_YELLOWO "You need a yellow key to activate this object" +extern const char *s_PD_YELLOWO; // = PD_YELLOWO; +//#define PD_BLUEK "You need a blue key to open this door" +extern const char *s_PD_BLUEK; // = PD_BLUEK; +//#define PD_REDK "You need a red key to open this door" +extern const char *s_PD_REDK; // = PD_REDK; +//#define PD_YELLOWK "You need a yellow key to open this door" +extern const char *s_PD_YELLOWK; // = PD_YELLOWK; +//jff 02/05/98 Create messages specific to card and skull keys +//#define PD_BLUEC "You need a blue card to open this door" +extern const char *s_PD_BLUEC; // = PD_BLUEC; +//#define PD_REDC "You need a red card to open this door" +extern const char *s_PD_REDC; // = PD_REDC; +//#define PD_YELLOWC "You need a yellow card to open this door" +extern const char *s_PD_YELLOWC; // = PD_YELLOWC; +//#define PD_BLUES "You need a blue skull to open this door" +extern const char *s_PD_BLUES; // = PD_BLUES; +//#define PD_REDS "You need a red skull to open this door" +extern const char *s_PD_REDS; // = PD_REDS; +//#define PD_YELLOWS "You need a yellow skull to open this door" +extern const char *s_PD_YELLOWS; // = PD_YELLOWS; +//#define PD_ANY "Any key will open this door" +extern const char *s_PD_ANY; // = PD_ANY; +//#define PD_ALL3 "You need all three keys to open this door" +extern const char *s_PD_ALL3; // = PD_ALL3; +//#define PD_ALL6 "You need all six keys to open this door" +extern const char *s_PD_ALL6; // = PD_ALL6; + +// +// G_game.C +// +//#define GGSAVED "game saved." +extern const char *s_GGSAVED; // = GGSAVED; + +// +// HU_stuff.C +// +//#define HUSTR_MSGU "[Message unsent]" +extern const char *s_HUSTR_MSGU; // = HUSTR_MSGU; + +//#define HUSTR_E1M1 "E1M1: Hangar" +extern const char *s_HUSTR_E1M1; // = HUSTR_E1M1; +//#define HUSTR_E1M2 "E1M2: Nuclear Plant" +extern const char *s_HUSTR_E1M2; // = HUSTR_E1M2; +//#define HUSTR_E1M3 "E1M3: Toxin Refinery" +extern const char *s_HUSTR_E1M3; // = HUSTR_E1M3; +//#define HUSTR_E1M4 "E1M4: Command Control" +extern const char *s_HUSTR_E1M4; // = HUSTR_E1M4; +//#define HUSTR_E1M5 "E1M5: Phobos Lab" +extern const char *s_HUSTR_E1M5; // = HUSTR_E1M5; +//#define HUSTR_E1M6 "E1M6: Central Processing" +extern const char *s_HUSTR_E1M6; // = HUSTR_E1M6; +//#define HUSTR_E1M7 "E1M7: Computer Station" +extern const char *s_HUSTR_E1M7; // = HUSTR_E1M7; +//#define HUSTR_E1M8 "E1M8: Phobos Anomaly" +extern const char *s_HUSTR_E1M8; // = HUSTR_E1M8; +//#define HUSTR_E1M9 "E1M9: Military Base" +extern const char *s_HUSTR_E1M9; // = HUSTR_E1M9; + +//#define HUSTR_E2M1 "E2M1: Deimos Anomaly" +extern const char *s_HUSTR_E2M1; // = HUSTR_E2M1; +//#define HUSTR_E2M2 "E2M2: Containment Area" +extern const char *s_HUSTR_E2M2; // = HUSTR_E2M2; +//#define HUSTR_E2M3 "E2M3: Refinery" +extern const char *s_HUSTR_E2M3; // = HUSTR_E2M3; +//#define HUSTR_E2M4 "E2M4: Deimos Lab" +extern const char *s_HUSTR_E2M4; // = HUSTR_E2M4; +//#define HUSTR_E2M5 "E2M5: Command Center" +extern const char *s_HUSTR_E2M5; // = HUSTR_E2M5; +//#define HUSTR_E2M6 "E2M6: Halls of the Damned" +extern const char *s_HUSTR_E2M6; // = HUSTR_E2M6; +//#define HUSTR_E2M7 "E2M7: Spawning Vats" +extern const char *s_HUSTR_E2M7; // = HUSTR_E2M7; +//#define HUSTR_E2M8 "E2M8: Tower of Babel" +extern const char *s_HUSTR_E2M8; // = HUSTR_E2M8; +//#define HUSTR_E2M9 "E2M9: Fortress of Mystery" +extern const char *s_HUSTR_E2M9; // = HUSTR_E2M9; + +//#define HUSTR_E3M1 "E3M1: Hell Keep" +extern const char *s_HUSTR_E3M1; // = HUSTR_E3M1; +//#define HUSTR_E3M2 "E3M2: Slough of Despair" +extern const char *s_HUSTR_E3M2; // = HUSTR_E3M2; +//#define HUSTR_E3M3 "E3M3: Pandemonium" +extern const char *s_HUSTR_E3M3; // = HUSTR_E3M3; +//#define HUSTR_E3M4 "E3M4: House of Pain" +extern const char *s_HUSTR_E3M4; // = HUSTR_E3M4; +//#define HUSTR_E3M5 "E3M5: Unholy Cathedral" +extern const char *s_HUSTR_E3M5; // = HUSTR_E3M5; +//#define HUSTR_E3M6 "E3M6: Mt. Erebus" +extern const char *s_HUSTR_E3M6; // = HUSTR_E3M6; +//#define HUSTR_E3M7 "E3M7: Limbo" +extern const char *s_HUSTR_E3M7; // = HUSTR_E3M7; +//#define HUSTR_E3M8 "E3M8: Dis" +extern const char *s_HUSTR_E3M8; // = HUSTR_E3M8; +//#define HUSTR_E3M9 "E3M9: Warrens" +extern const char *s_HUSTR_E3M9; // = HUSTR_E3M9; + +//#define HUSTR_E4M1 "E4M1: Hell Beneath" +extern const char *s_HUSTR_E4M1; // = HUSTR_E4M1; +//#define HUSTR_E4M2 "E4M2: Perfect Hatred" +extern const char *s_HUSTR_E4M2; // = HUSTR_E4M2; +//#define HUSTR_E4M3 "E4M3: Sever The Wicked" +extern const char *s_HUSTR_E4M3; // = HUSTR_E4M3; +//#define HUSTR_E4M4 "E4M4: Unruly Evil" +extern const char *s_HUSTR_E4M4; // = HUSTR_E4M4; +//#define HUSTR_E4M5 "E4M5: They Will Repent" +extern const char *s_HUSTR_E4M5; // = HUSTR_E4M5; +//#define HUSTR_E4M6 "E4M6: Against Thee Wickedly" +extern const char *s_HUSTR_E4M6; // = HUSTR_E4M6; +//#define HUSTR_E4M7 "E4M7: And Hell Followed" +extern const char *s_HUSTR_E4M7; // = HUSTR_E4M7; +//#define HUSTR_E4M8 "E4M8: Unto The Cruel" +extern const char *s_HUSTR_E4M8; // = HUSTR_E4M8; +//#define HUSTR_E4M9 "E4M9: Fear" +extern const char *s_HUSTR_E4M9; // = HUSTR_E4M9; + +//#define HUSTR_1 "level 1: entryway" +extern const char *s_HUSTR_1; // = HUSTR_1; +//#define HUSTR_2 "level 2: underhalls" +extern const char *s_HUSTR_2; // = HUSTR_2; +//#define HUSTR_3 "level 3: the gantlet" +extern const char *s_HUSTR_3; // = HUSTR_3; +//#define HUSTR_4 "level 4: the focus" +extern const char *s_HUSTR_4; // = HUSTR_4; +//#define HUSTR_5 "level 5: the waste tunnels" +extern const char *s_HUSTR_5; // = HUSTR_5; +//#define HUSTR_6 "level 6: the crusher" +extern const char *s_HUSTR_6; // = HUSTR_6; +//#define HUSTR_7 "level 7: dead simple" +extern const char *s_HUSTR_7; // = HUSTR_7; +//#define HUSTR_8 "level 8: tricks and traps" +extern const char *s_HUSTR_8; // = HUSTR_8; +//#define HUSTR_9 "level 9: the pit" +extern const char *s_HUSTR_9; // = HUSTR_9; +//#define HUSTR_10 "level 10: refueling base" +extern const char *s_HUSTR_10; // = HUSTR_10; +//#define HUSTR_11 "level 11: 'o' of destruction!" +extern const char *s_HUSTR_11; // = HUSTR_11; + +//#define HUSTR_12 "level 12: the factory" +extern const char *s_HUSTR_12; // = HUSTR_12; +//#define HUSTR_13 "level 13: downtown" +extern const char *s_HUSTR_13; // = HUSTR_13; +//#define HUSTR_14 "level 14: the inmost dens" +extern const char *s_HUSTR_14; // = HUSTR_14; +//#define HUSTR_15 "level 15: industrial zone" +extern const char *s_HUSTR_15; // = HUSTR_15; +//#define HUSTR_16 "level 16: suburbs" +extern const char *s_HUSTR_16; // = HUSTR_16; +//#define HUSTR_17 "level 17: tenements" +extern const char *s_HUSTR_17; // = HUSTR_17; +//#define HUSTR_18 "level 18: the courtyard" +extern const char *s_HUSTR_18; // = HUSTR_18; +//#define HUSTR_19 "level 19: the citadel" +extern const char *s_HUSTR_19; // = HUSTR_19; +//#define HUSTR_20 "level 20: gotcha!" +extern const char *s_HUSTR_20; // = HUSTR_20; + +//#define HUSTR_21 "level 21: nirvana" +extern const char *s_HUSTR_21; // = HUSTR_21; +//#define HUSTR_22 "level 22: the catacombs" +extern const char *s_HUSTR_22; // = HUSTR_22; +//#define HUSTR_23 "level 23: barrels o' fun" +extern const char *s_HUSTR_23; // = HUSTR_23; +//#define HUSTR_24 "level 24: the chasm" +extern const char *s_HUSTR_24; // = HUSTR_24; +//#define HUSTR_25 "level 25: bloodfalls" +extern const char *s_HUSTR_25; // = HUSTR_25; +//#define HUSTR_26 "level 26: the abandoned mines" +extern const char *s_HUSTR_26; // = HUSTR_26; +//#define HUSTR_27 "level 27: monster condo" +extern const char *s_HUSTR_27; // = HUSTR_27; +//#define HUSTR_28 "level 28: the spirit world" +extern const char *s_HUSTR_28; // = HUSTR_28; +//#define HUSTR_29 "level 29: the living end" +extern const char *s_HUSTR_29; // = HUSTR_29; +//#define HUSTR_30 "level 30: icon of sin" +extern const char *s_HUSTR_30; // = HUSTR_30; + +//#define HUSTR_31 "level 31: wolfenstein" +extern const char *s_HUSTR_31; // = HUSTR_31; +//#define HUSTR_32 "level 32: grosse" +extern const char *s_HUSTR_32; // = HUSTR_32; + +//#define PHUSTR_1 "level 1: congo" +extern const char *s_PHUSTR_1; // = PHUSTR_1; +//#define PHUSTR_2 "level 2: well of souls" +extern const char *s_PHUSTR_2; // = PHUSTR_2; +//#define PHUSTR_3 "level 3: aztec" +extern const char *s_PHUSTR_3; // = PHUSTR_3; +//#define PHUSTR_4 "level 4: caged" +extern const char *s_PHUSTR_4; // = PHUSTR_4; +//#define PHUSTR_5 "level 5: ghost town" +extern const char *s_PHUSTR_5; // = PHUSTR_5; +//#define PHUSTR_6 "level 6: baron's lair" +extern const char *s_PHUSTR_6; // = PHUSTR_6; +//#define PHUSTR_7 "level 7: caughtyard" +extern const char *s_PHUSTR_7; // = PHUSTR_7; +//#define PHUSTR_8 "level 8: realm" +extern const char *s_PHUSTR_8; // = PHUSTR_8; +//#define PHUSTR_9 "level 9: abattoire" +extern const char *s_PHUSTR_9; // = PHUSTR_9; +//#define PHUSTR_10 "level 10: onslaught" +extern const char *s_PHUSTR_10; // = PHUSTR_10; +//#define PHUSTR_11 "level 11: hunted" +extern const char *s_PHUSTR_11; // = PHUSTR_11; + +//#define PHUSTR_12 "level 12: speed" +extern const char *s_PHUSTR_12; // = PHUSTR_12; +//#define PHUSTR_13 "level 13: the crypt" +extern const char *s_PHUSTR_13; // = PHUSTR_13; +//#define PHUSTR_14 "level 14: genesis" +extern const char *s_PHUSTR_14; // = PHUSTR_14; +//#define PHUSTR_15 "level 15: the twilight" +extern const char *s_PHUSTR_15; // = PHUSTR_15; +//#define PHUSTR_16 "level 16: the omen" +extern const char *s_PHUSTR_16; // = PHUSTR_16; +//#define PHUSTR_17 "level 17: compound" +extern const char *s_PHUSTR_17; // = PHUSTR_17; +//#define PHUSTR_18 "level 18: neurosphere" +extern const char *s_PHUSTR_18; // = PHUSTR_18; +//#define PHUSTR_19 "level 19: nme" +extern const char *s_PHUSTR_19; // = PHUSTR_19; +//#define PHUSTR_20 "level 20: the death domain" +extern const char *s_PHUSTR_20; // = PHUSTR_20; + +//#define PHUSTR_21 "level 21: slayer" +extern const char *s_PHUSTR_21; // = PHUSTR_21; +//#define PHUSTR_22 "level 22: impossible mission" +extern const char *s_PHUSTR_22; // = PHUSTR_22; +//#define PHUSTR_23 "level 23: tombstone" +extern const char *s_PHUSTR_23; // = PHUSTR_23; +//#define PHUSTR_24 "level 24: the final frontier" +extern const char *s_PHUSTR_24; // = PHUSTR_24; +//#define PHUSTR_25 "level 25: the temple of darkness" +extern const char *s_PHUSTR_25; // = PHUSTR_25; +//#define PHUSTR_26 "level 26: bunker" +extern const char *s_PHUSTR_26; // = PHUSTR_26; +//#define PHUSTR_27 "level 27: anti-christ" +extern const char *s_PHUSTR_27; // = PHUSTR_27; +//#define PHUSTR_28 "level 28: the sewers" +extern const char *s_PHUSTR_28; // = PHUSTR_28; +//#define PHUSTR_29 "level 29: odyssey of noises" +extern const char *s_PHUSTR_29; // = PHUSTR_29; +//#define PHUSTR_30 "level 30: the gateway of hell" +extern const char *s_PHUSTR_30; // = PHUSTR_30; + +//#define PHUSTR_31 "level 31: cyberden" +extern const char *s_PHUSTR_31; // = PHUSTR_31; +//#define PHUSTR_32 "level 32: go 2 it" +extern const char *s_PHUSTR_32; // = PHUSTR_32; + +//#define THUSTR_1 "level 1: system control" +extern const char *s_THUSTR_1; // = THUSTR_1; +//#define THUSTR_2 "level 2: human bbq" +extern const char *s_THUSTR_2; // = THUSTR_2; +//#define THUSTR_3 "level 3: power control" +extern const char *s_THUSTR_3; // = THUSTR_3; +//#define THUSTR_4 "level 4: wormhole" +extern const char *s_THUSTR_4; // = THUSTR_4; +//#define THUSTR_5 "level 5: hanger" +extern const char *s_THUSTR_5; // = THUSTR_5; +//#define THUSTR_6 "level 6: open season" +extern const char *s_THUSTR_6; // = THUSTR_6; +//#define THUSTR_7 "level 7: prison" +extern const char *s_THUSTR_7; // = THUSTR_7; +//#define THUSTR_8 "level 8: metal" +extern const char *s_THUSTR_8; // = THUSTR_8; +//#define THUSTR_9 "level 9: stronghold" +extern const char *s_THUSTR_9; // = THUSTR_9; +//#define THUSTR_10 "level 10: redemption" +extern const char *s_THUSTR_10; // = THUSTR_10; +//#define THUSTR_11 "level 11: storage facility" +extern const char *s_THUSTR_11; // = THUSTR_11; + +//#define THUSTR_12 "level 12: crater" +extern const char *s_THUSTR_12; // = THUSTR_12; +//#define THUSTR_13 "level 13: nukage processing" +extern const char *s_THUSTR_13; // = THUSTR_13; +//#define THUSTR_14 "level 14: steel works" +extern const char *s_THUSTR_14; // = THUSTR_14; +//#define THUSTR_15 "level 15: dead zone" +extern const char *s_THUSTR_15; // = THUSTR_15; +//#define THUSTR_16 "level 16: deepest reaches" +extern const char *s_THUSTR_16; // = THUSTR_16; +//#define THUSTR_17 "level 17: processing area" +extern const char *s_THUSTR_17; // = THUSTR_17; +//#define THUSTR_18 "level 18: mill" +extern const char *s_THUSTR_18; // = THUSTR_18; +//#define THUSTR_19 "level 19: shipping/respawning" +extern const char *s_THUSTR_19; // = THUSTR_19; +//#define THUSTR_20 "level 20: central processing" +extern const char *s_THUSTR_20; // = THUSTR_20; + +//#define THUSTR_21 "level 21: administration center" +extern const char *s_THUSTR_21; // = THUSTR_21; +//#define THUSTR_22 "level 22: habitat" +extern const char *s_THUSTR_22; // = THUSTR_22; +//#define THUSTR_23 "level 23: lunar mining project" +extern const char *s_THUSTR_23; // = THUSTR_23; +//#define THUSTR_24 "level 24: quarry" +extern const char *s_THUSTR_24; // = THUSTR_24; +//#define THUSTR_25 "level 25: baron's den" +extern const char *s_THUSTR_25; // = THUSTR_25; +//#define THUSTR_26 "level 26: ballistyx" +extern const char *s_THUSTR_26; // = THUSTR_26; +//#define THUSTR_27 "level 27: mount pain" +extern const char *s_THUSTR_27; // = THUSTR_27; +//#define THUSTR_28 "level 28: heck" +extern const char *s_THUSTR_28; // = THUSTR_28; +//#define THUSTR_29 "level 29: river styx" +extern const char *s_THUSTR_29; // = THUSTR_29; +//#define THUSTR_30 "level 30: last call" +extern const char *s_THUSTR_30; // = THUSTR_30; + +//#define THUSTR_31 "level 31: pharaoh" +extern const char *s_THUSTR_31; // = THUSTR_31; +//#define THUSTR_32 "level 32: caribbean" +extern const char *s_THUSTR_32; // = THUSTR_32; + +//#define HUSTR_CHATMACRO1 "I'm ready to kick butt!" +extern const char *s_HUSTR_CHATMACRO1; // = HUSTR_CHATMACRO1; +//#define HUSTR_CHATMACRO2 "I'm OK." +extern const char *s_HUSTR_CHATMACRO2; // = HUSTR_CHATMACRO2; +//#define HUSTR_CHATMACRO3 "I'm not looking too good!" +extern const char *s_HUSTR_CHATMACRO3; // = HUSTR_CHATMACRO3; +//#define HUSTR_CHATMACRO4 "Help!" +extern const char *s_HUSTR_CHATMACRO4; // = HUSTR_CHATMACRO4; +//#define HUSTR_CHATMACRO5 "You suck!" +extern const char *s_HUSTR_CHATMACRO5; // = HUSTR_CHATMACRO5; +//#define HUSTR_CHATMACRO6 "Next time, scumbag..." +extern const char *s_HUSTR_CHATMACRO6; // = HUSTR_CHATMACRO6; +//#define HUSTR_CHATMACRO7 "Come here!" +extern const char *s_HUSTR_CHATMACRO7; // = HUSTR_CHATMACRO7; +//#define HUSTR_CHATMACRO8 "I'll take care of it." +extern const char *s_HUSTR_CHATMACRO8; // = HUSTR_CHATMACRO8; +//#define HUSTR_CHATMACRO9 "Yes" +extern const char *s_HUSTR_CHATMACRO9; // = HUSTR_CHATMACRO9; +//#define HUSTR_CHATMACRO0 "No" +extern const char *s_HUSTR_CHATMACRO0; // = HUSTR_CHATMACRO0; + +//#define HUSTR_TALKTOSELF1 "You mumble to yourself" +extern const char *s_HUSTR_TALKTOSELF1; // = HUSTR_TALKTOSELF1; +//#define HUSTR_TALKTOSELF2 "Who's there?" +extern const char *s_HUSTR_TALKTOSELF2; // = HUSTR_TALKTOSELF2; +//#define HUSTR_TALKTOSELF3 "You scare yourself" +extern const char *s_HUSTR_TALKTOSELF3; // = HUSTR_TALKTOSELF3; +//#define HUSTR_TALKTOSELF4 "You start to rave" +extern const char *s_HUSTR_TALKTOSELF4; // = HUSTR_TALKTOSELF4; +//#define HUSTR_TALKTOSELF5 "You've lost it..." +extern const char *s_HUSTR_TALKTOSELF5; // = HUSTR_TALKTOSELF5; + +//#define HUSTR_MESSAGESENT "[Message Sent]" +extern const char *s_HUSTR_MESSAGESENT; // = HUSTR_MESSAGESENT; + +// The following should NOT be changed unless it seems +// just AWFULLY necessary + +//#define HUSTR_PLRGREEN "Green: " +extern const char *s_HUSTR_PLRGREEN; // = HUSTR_PLRGREEN; +//#define HUSTR_PLRINDIGO "Indigo: " +extern const char *s_HUSTR_PLRINDIGO; // = HUSTR_PLRINDIGO; +//#define HUSTR_PLRBROWN "Brown: " +extern const char *s_HUSTR_PLRBROWN; // = HUSTR_PLRBROWN; +//#define HUSTR_PLRRED "Red: " +extern const char *s_HUSTR_PLRRED; // = HUSTR_PLRRED; + +// +// AM_map.C +// + +//#define AMSTR_FOLLOWON "Follow Mode ON" +extern const char* s_AMSTR_FOLLOWON; // = AMSTR_FOLLOWON; +//#define AMSTR_FOLLOWOFF "Follow Mode OFF" +extern const char* s_AMSTR_FOLLOWOFF; // = AMSTR_FOLLOWOFF; + +//#define AMSTR_GRIDON "Grid ON" +extern const char* s_AMSTR_GRIDON; // = AMSTR_GRIDON; +//#define AMSTR_GRIDOFF "Grid OFF" +extern const char* s_AMSTR_GRIDOFF; // = AMSTR_GRIDOFF; + +//#define AMSTR_MARKEDSPOT "Marked Spot" +extern const char* s_AMSTR_MARKEDSPOT; // = AMSTR_MARKEDSPOT; +//#define AMSTR_MARKSCLEARED "All Marks Cleared" +extern const char* s_AMSTR_MARKSCLEARED; // = AMSTR_MARKSCLEARED; + +// CPhipps - automap rotate & overlay +extern const char* s_AMSTR_ROTATEON; +extern const char* s_AMSTR_ROTATEOFF; +extern const char* s_AMSTR_OVERLAYON; +extern const char* s_AMSTR_OVERLAYOFF; + +// +// ST_stuff.C +// + +//#define STSTR_MUS "Music Change" +extern const char* s_STSTR_MUS; // = STSTR_MUS; +//#define STSTR_NOMUS "IMPOSSIBLE SELECTION" +extern const char* s_STSTR_NOMUS; // = STSTR_NOMUS; +//#define STSTR_DQDON "Degreelessness Mode On" +extern const char* s_STSTR_DQDON; // = STSTR_DQDON; +//#define STSTR_DQDOFF "Degreelessness Mode Off" +extern const char* s_STSTR_DQDOFF; // = STSTR_DQDOFF; + +//#define STSTR_KFAADDED "Very Happy Ammo Added" +extern const char* s_STSTR_KFAADDED; // = STSTR_KFAADDED; +//#define STSTR_FAADDED "Ammo (no keys) Added" +extern const char* s_STSTR_FAADDED; // = STSTR_FAADDED; + +//#define STSTR_NCON "No Clipping Mode ON" +extern const char* s_STSTR_NCON; // = STSTR_NCON; +//#define STSTR_NCOFF "No Clipping Mode OFF" +extern const char* s_STSTR_NCOFF; // = STSTR_NCOFF; + +//#define STSTR_BEHOLD "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp" +extern const char* s_STSTR_BEHOLD; // = STSTR_BEHOLD; +//#define STSTR_BEHOLDX "Power-up Toggled" +extern const char* s_STSTR_BEHOLDX; // = STSTR_BEHOLDX; + +//#define STSTR_CHOPPERS "... doesn't suck - GM" +extern const char* s_STSTR_CHOPPERS; // = STSTR_CHOPPERS; +//#define STSTR_CLEV "Changing Level..." +extern const char* s_STSTR_CLEV; // = STSTR_CLEV; + +// +// F_Finale.C +// +/* +#define E1TEXT \ +"Once you beat the big badasses and\n"\ +"clean out the moon base you're supposed\n"\ +"to win, aren't you? Aren't you? Where's\n"\ +"your fat reward and ticket home? What\n"\ +"the hell is this? It's not supposed to\n"\ +"end this way!\n"\ +"\n" \ +"It stinks like rotten meat, but looks\n"\ +"like the lost Deimos base. Looks like\n"\ +"you're stuck on The Shores of Hell.\n"\ +"The only way out is through.\n"\ +"\n"\ +"To continue the DOOM experience, play\n"\ +"The Shores of Hell and its amazing\n"\ +"sequel, Inferno!\n" +*/ +extern const char* s_E1TEXT; // = E1TEXT; + + +/* +#define E2TEXT \ +"You've done it! The hideous cyber-\n"\ +"demon lord that ruled the lost Deimos\n"\ +"moon base has been slain and you\n"\ +"are triumphant! But ... where are\n"\ +"you? You clamber to the edge of the\n"\ +"moon and look down to see the awful\n"\ +"truth.\n" \ +"\n"\ +"Deimos floats above Hell itself!\n"\ +"You've never heard of anyone escaping\n"\ +"from Hell, but you'll make the bastards\n"\ +"sorry they ever heard of you! Quickly,\n"\ +"you rappel down to the surface of\n"\ +"Hell.\n"\ +"\n" \ +"Now, it's on to the final chapter of\n"\ +"DOOM! -- Inferno." +*/ +extern const char* s_E2TEXT; // = E2TEXT; + + +/* +#define E3TEXT \ +"The loathsome spiderdemon that\n"\ +"masterminded the invasion of the moon\n"\ +"bases and caused so much death has had\n"\ +"its ass kicked for all time.\n"\ +"\n"\ +"A hidden doorway opens and you enter.\n"\ +"You've proven too tough for Hell to\n"\ +"contain, and now Hell at last plays\n"\ +"fair -- for you emerge from the door\n"\ +"to see the green fields of Earth!\n"\ +"Home at last.\n" \ +"\n"\ +"You wonder what's been happening on\n"\ +"Earth while you were battling evil\n"\ +"unleashed. It's good that no Hell-\n"\ +"spawn could have come through that\n"\ +"door with you ..." +*/ +extern const char* s_E3TEXT; // = E3TEXT; + + +/* +#define E4TEXT \ +"the spider mastermind must have sent forth\n"\ +"its legions of hellspawn before your\n"\ +"final confrontation with that terrible\n"\ +"beast from hell. but you stepped forward\n"\ +"and brought forth eternal damnation and\n"\ +"suffering upon the horde as a true hero\n"\ +"would in the face of something so evil.\n"\ +"\n"\ +"besides, someone was gonna pay for what\n"\ +"happened to daisy, your pet rabbit.\n"\ +"\n"\ +"but now, you see spread before you more\n"\ +"potential pain and gibbitude as a nation\n"\ +"of demons run amok among our cities.\n"\ +"\n"\ +"next stop, hell on earth!" +*/ +extern const char* s_E4TEXT; // = E4TEXT; + + +// after level 6, put this: + +/* +#define C1TEXT \ +"YOU HAVE ENTERED DEEPLY INTO THE INFESTED\n" \ +"STARPORT. BUT SOMETHING IS WRONG. THE\n" \ +"MONSTERS HAVE BROUGHT THEIR OWN REALITY\n" \ +"WITH THEM, AND THE STARPORT'S TECHNOLOGY\n" \ +"IS BEING SUBVERTED BY THEIR PRESENCE.\n" \ +"\n"\ +"AHEAD, YOU SEE AN OUTPOST OF HELL, A\n" \ +"FORTIFIED ZONE. IF YOU CAN GET PAST IT,\n" \ +"YOU CAN PENETRATE INTO THE HAUNTED HEART\n" \ +"OF THE STARBASE AND FIND THE CONTROLLING\n" \ +"SWITCH WHICH HOLDS EARTH'S POPULATION\n" \ +"HOSTAGE." +*/ +extern const char* s_C1TEXT; // = C1TEXT; + +// After level 11, put this: + +/* +#define C2TEXT \ +"YOU HAVE WON! YOUR VICTORY HAS ENABLED\n" \ +"HUMANKIND TO EVACUATE EARTH AND ESCAPE\n"\ +"THE NIGHTMARE. NOW YOU ARE THE ONLY\n"\ +"HUMAN LEFT ON THE FACE OF THE PLANET.\n"\ +"CANNIBAL MUTATIONS, CARNIVOROUS ALIENS,\n"\ +"AND EVIL SPIRITS ARE YOUR ONLY NEIGHBORS.\n"\ +"YOU SIT BACK AND WAIT FOR DEATH, CONTENT\n"\ +"THAT YOU HAVE SAVED YOUR SPECIES.\n"\ +"\n"\ +"BUT THEN, EARTH CONTROL BEAMS DOWN A\n"\ +"MESSAGE FROM SPACE: \"SENSORS HAVE LOCATED\n"\ +"THE SOURCE OF THE ALIEN INVASION. IF YOU\n"\ +"GO THERE, YOU MAY BE ABLE TO BLOCK THEIR\n"\ +"ENTRY. THE ALIEN BASE IS IN THE HEART OF\n"\ +"YOUR OWN HOME CITY, NOT FAR FROM THE\n"\ +"STARPORT.\" SLOWLY AND PAINFULLY YOU GET\n"\ +"UP AND RETURN TO THE FRAY." +*/ +extern const char* s_C2TEXT; // = C2TEXT; + + +// After level 20, put this: + +/* +#define C3TEXT \ +"YOU ARE AT THE CORRUPT HEART OF THE CITY,\n"\ +"SURROUNDED BY THE CORPSES OF YOUR ENEMIES.\n"\ +"YOU SEE NO WAY TO DESTROY THE CREATURES'\n"\ +"ENTRYWAY ON THIS SIDE, SO YOU CLENCH YOUR\n"\ +"TEETH AND PLUNGE THROUGH IT.\n"\ +"\n"\ +"THERE MUST BE A WAY TO CLOSE IT ON THE\n"\ +"OTHER SIDE. WHAT DO YOU CARE IF YOU'VE\n"\ +"GOT TO GO THROUGH HELL TO GET TO IT?" +*/ +extern const char* s_C3TEXT; // = C3TEXT; + + +// After level 29, put this: + +/* +#define C4TEXT \ +"THE HORRENDOUS VISAGE OF THE BIGGEST\n"\ +"DEMON YOU'VE EVER SEEN CRUMBLES BEFORE\n"\ +"YOU, AFTER YOU PUMP YOUR ROCKETS INTO\n"\ +"HIS EXPOSED BRAIN. THE MONSTER SHRIVELS\n"\ +"UP AND DIES, ITS THRASHING LIMBS\n"\ +"DEVASTATING UNTOLD MILES OF HELL'S\n"\ +"SURFACE.\n"\ +"\n"\ +"YOU'VE DONE IT. THE INVASION IS OVER.\n"\ +"EARTH IS SAVED. HELL IS A WRECK. YOU\n"\ +"WONDER WHERE BAD FOLKS WILL GO WHEN THEY\n"\ +"DIE, NOW. WIPING THE SWEAT FROM YOUR\n"\ +"FOREHEAD YOU BEGIN THE LONG TREK BACK\n"\ +"HOME. REBUILDING EARTH OUGHT TO BE A\n"\ +"LOT MORE FUN THAN RUINING IT WAS.\n" +*/ +extern const char* s_C4TEXT; // = C4TEXT; + + + +// Before level 31, put this: + +/* +#define C5TEXT \ +"CONGRATULATIONS, YOU'VE FOUND THE SECRET\n"\ +"LEVEL! LOOKS LIKE IT'S BEEN BUILT BY\n"\ +"HUMANS, RATHER THAN DEMONS. YOU WONDER\n"\ +"WHO THE INMATES OF THIS CORNER OF HELL\n"\ +"WILL BE." +*/ +extern const char* s_C5TEXT; // = C5TEXT; + + +// Before level 32, put this: + +/* +#define C6TEXT \ +"CONGRATULATIONS, YOU'VE FOUND THE\n"\ +"SUPER SECRET LEVEL! YOU'D BETTER\n"\ +"BLAZE THROUGH THIS ONE!\n" +*/ +extern const char* s_C6TEXT; // = C6TEXT; + + +// after map 06 + +/* +#define P1TEXT \ +"You gloat over the steaming carcass of the\n"\ +"Guardian. With its death, you've wrested\n"\ +"the Accelerator from the stinking claws\n"\ +"of Hell. You relax and glance around the\n"\ +"room. Damn! There was supposed to be at\n"\ +"least one working prototype, but you can't\n"\ +"see it. The demons must have taken it.\n"\ +"\n"\ +"You must find the prototype, or all your\n"\ +"struggles will have been wasted. Keep\n"\ +"moving, keep fighting, keep killing.\n"\ +"Oh yes, keep living, too." +*/ +extern const char* s_P1TEXT; // = P1TEXT; + + +// after map 11 + +/* +#define P2TEXT \ +"Even the deadly Arch-Vile labyrinth could\n"\ +"not stop you, and you've gotten to the\n"\ +"prototype Accelerator which is soon\n"\ +"efficiently and permanently deactivated.\n"\ +"\n"\ +"You're good at that kind of thing." +*/ +extern const char* s_P2TEXT; // = P2TEXT; + + +// after map 20 + +/* +#define P3TEXT \ +"You've bashed and battered your way into\n"\ +"the heart of the devil-hive. Time for a\n"\ +"Search-and-Destroy mission, aimed at the\n"\ +"Gatekeeper, whose foul offspring is\n"\ +"cascading to Earth. Yeah, he's bad. But\n"\ +"you know who's worse!\n"\ +"\n"\ +"Grinning evilly, you check your gear, and\n"\ +"get ready to give the bastard a little Hell\n"\ +"of your own making!" +*/ +extern const char* s_P3TEXT; // = P3TEXT; + +// after map 30 + +/* +#define P4TEXT \ +"The Gatekeeper's evil face is splattered\n"\ +"all over the place. As its tattered corpse\n"\ +"collapses, an inverted Gate forms and\n"\ +"sucks down the shards of the last\n"\ +"prototype Accelerator, not to mention the\n"\ +"few remaining demons. You're done. Hell\n"\ +"has gone back to pounding bad dead folks \n"\ +"instead of good live ones. Remember to\n"\ +"tell your grandkids to put a rocket\n"\ +"launcher in your coffin. If you go to Hell\n"\ +"when you die, you'll need it for some\n"\ +"final cleaning-up ..." +*/ +extern const char* s_P4TEXT; // = P4TEXT; + +// before map 31 + +/* +#define P5TEXT \ +"You've found the second-hardest level we\n"\ +"got. Hope you have a saved game a level or\n"\ +"two previous. If not, be prepared to die\n"\ +"aplenty. For master marines only." +*/ +extern const char* s_P5TEXT; // = P5TEXT; + +// before map 32 + +/* +#define P6TEXT \ +"Betcha wondered just what WAS the hardest\n"\ +"level we had ready for ya? Now you know.\n"\ +"No one gets out alive." +*/ +extern const char* s_P6TEXT; // = P6TEXT; + + +/* +#define T1TEXT \ +"You've fought your way out of the infested\n"\ +"experimental labs. It seems that UAC has\n"\ +"once again gulped it down. With their\n"\ +"high turnover, it must be hard for poor\n"\ +"old UAC to buy corporate health insurance\n"\ +"nowadays..\n"\ +"\n"\ +"Ahead lies the military complex, now\n"\ +"swarming with diseased horrors hot to get\n"\ +"their teeth into you. With luck, the\n"\ +"complex still has some warlike ordnance\n"\ +"laying around." +*/ +extern const char* s_T1TEXT; // = T1TEXT; + + +/* +#define T2TEXT \ +"You hear the grinding of heavy machinery\n"\ +"ahead. You sure hope they're not stamping\n"\ +"out new hellspawn, but you're ready to\n"\ +"ream out a whole herd if you have to.\n"\ +"They might be planning a blood feast, but\n"\ +"you feel about as mean as two thousand\n"\ +"maniacs packed into one mad killer.\n"\ +"\n"\ +"You don't plan to go down easy." +*/ +extern const char* s_T2TEXT; // = T2TEXT; + + +/* +#define T3TEXT \ +"The vista opening ahead looks real damn\n"\ +"familiar. Smells familiar, too -- like\n"\ +"fried excrement. You didn't like this\n"\ +"place before, and you sure as hell ain't\n"\ +"planning to like it now. The more you\n"\ +"brood on it, the madder you get.\n"\ +"Hefting your gun, an evil grin trickles\n"\ +"onto your face. Time to take some names." +*/ +extern const char* s_T3TEXT; // = T3TEXT; + +/* +#define T4TEXT \ +"Suddenly, all is silent, from one horizon\n"\ +"to the other. The agonizing echo of Hell\n"\ +"fades away, the nightmare sky turns to\n"\ +"blue, the heaps of monster corpses start \n"\ +"to evaporate along with the evil stench \n"\ +"that filled the air. Jeeze, maybe you've\n"\ +"done it. Have you really won?\n"\ +"\n"\ +"Something rumbles in the distance.\n"\ +"A blue light begins to glow inside the\n"\ +"ruined skull of the demon-spitter." +*/ +extern const char* s_T4TEXT; // = T4TEXT; + + +/* +#define T5TEXT \ +"What now? Looks totally different. Kind\n"\ +"of like King Tut's condo. Well,\n"\ +"whatever's here can't be any worse\n"\ +"than usual. Can it? Or maybe it's best\n"\ +"to let sleeping gods lie.." +*/ +extern const char* s_T5TEXT; // = T5TEXT; + + +/* +#define T6TEXT \ +"Time for a vacation. You've burst the\n"\ +"bowels of hell and by golly you're ready\n"\ +"for a break. You mutter to yourself,\n"\ +"Maybe someone else can kick Hell's ass\n"\ +"next time around. Ahead lies a quiet town,\n"\ +"with peaceful flowing water, quaint\n"\ +"buildings, and presumably no Hellspawn.\n"\ +"\n"\ +"As you step off the transport, you hear\n"\ +"the stomp of a cyberdemon's iron shoe." +*/ +extern const char* s_T6TEXT; // = T6TEXT; + +// +// Character cast strings F_FINALE.C +// +//#define CC_ZOMBIE "ZOMBIEMAN" +extern const char* s_CC_ZOMBIE; // = CC_ZOMBIE; +//#define CC_SHOTGUN "SHOTGUN GUY" +extern const char* s_CC_SHOTGUN; // = CC_SHOTGUN; +//#define CC_HEAVY "HEAVY WEAPON DUDE" +extern const char* s_CC_HEAVY; // = CC_HEAVY; +//#define CC_IMP "IMP" +extern const char* s_CC_IMP; // = CC_IMP; +//#define CC_DEMON "DEMON" +extern const char* s_CC_DEMON; // = CC_DEMON; +//#define CC_LOST "LOST SOUL" +extern const char* s_CC_LOST; // = CC_LOST; +//#define CC_CACO "CACODEMON" +extern const char* s_CC_CACO; // = CC_CACO; +//#define CC_HELL "HELL KNIGHT" +extern const char* s_CC_HELL; // = CC_HELL; +//#define CC_BARON "BARON OF HELL" +extern const char* s_CC_BARON; // = CC_BARON; +//#define CC_ARACH "ARACHNOTRON" +extern const char* s_CC_ARACH; // = CC_ARACH; +//#define CC_PAIN "PAIN ELEMENTAL" +extern const char* s_CC_PAIN; // = CC_PAIN; +//#define CC_REVEN "REVENANT" +extern const char* s_CC_REVEN; // = CC_REVEN; +//#define CC_MANCU "MANCUBUS" +extern const char* s_CC_MANCU; // = CC_MANCU; +//#define CC_ARCH "ARCH-VILE" +extern const char* s_CC_ARCH; // = CC_ARCH; +//#define CC_SPIDER "THE SPIDER MASTERMIND" +extern const char* s_CC_SPIDER; // = CC_SPIDER; +//#define CC_CYBER "THE CYBERDEMON" +extern const char* s_CC_CYBER; // = CC_CYBER; +//#define CC_HERO "OUR HERO" +extern const char* s_CC_HERO; // = CC_HERO; + +// Ty 03/30/98 - new substitutions for background textures during int screens +// char* bgflatE1 = "FLOOR4_8"; +extern const char* bgflatE1; +// char* bgflatE2 = "SFLR6_1"; +extern const char* bgflatE2; +// char* bgflatE3 = "MFLR8_4"; +extern const char* bgflatE3; +// char* bgflatE4 = "MFLR8_3"; +extern const char* bgflatE4; + +// char* bgflat06 = "SLIME16"; +extern const char* bgflat06; +// char* bgflat11 = "RROCK14"; +extern const char* bgflat11; +// char* bgflat20 = "RROCK07"; +extern const char* bgflat20; +// char* bgflat30 = "RROCK17"; +extern const char* bgflat30; +// char* bgflat15 = "RROCK13"; +extern const char* bgflat15; +// char* bgflat31 = "RROCK19"; +extern const char* bgflat31; + +// char* bgcastcall = "BOSSBACK"; // panel behind cast call +extern const char* bgcastcall; + +// ignored if blank, general purpose startup announcements +// char* startup1 = ""; +extern const char* startup1; +// char* startup2 = ""; +extern const char* startup2; +// char* startup3 = ""; +extern const char* startup3; +// char* startup4 = ""; +extern const char* startup4; +// char* startup5 = ""; +extern const char* startup5; + +// from g_game.c, prefix for savegame name like "boomsav" +extern const char* savegamename; + +void D_BuildBEXTables(void); + +#endif diff --git a/src/d_englsh.h b/src/d_englsh.h new file mode 100644 index 0000000..86e7416 --- /dev/null +++ b/src/d_englsh.h @@ -0,0 +1,707 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Printed strings for translation. + * English language support (default). + * See dstrings.h for suggestions about foreign language BEX support + * + *-----------------------------------------------------------------------------*/ + +#ifndef __D_ENGLSH__ +#define __D_ENGLSH__ + +/* d_main.c */ +#define D_DEVSTR "Development mode ON.\n" +#define D_CDROM "CD-ROM Version: default.cfg from c:\\doomdata\n" + +/* m_menu.c */ +#define PRESSKEY "press a key." +#define PRESSYN "press y or n." +#define QUITMSG "are you sure you want to\nquit this great game?" +#define LOADNET "you can't do load while in a net game!\n\n"PRESSKEY +#define QLOADNET "you can't quickload during a netgame!\n\n"PRESSKEY +#define QSAVESPOT "you haven't picked a quicksave slot yet!\n\n"PRESSKEY +#define SAVEDEAD "you can't save if you aren't playing!\n\n"PRESSKEY +#define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n"PRESSYN +#define QLPROMPT "do you want to quickload the game named\n\n'%s'?\n\n"PRESSYN + +#define NEWGAME \ + "you can't start a new game\n"\ + "while in a network game.\n\n"PRESSKEY + +#define NIGHTMARE \ + "are you sure? this skill level\n"\ + "isn't even remotely fair.\n\n"PRESSYN + +#define SWSTRING \ + "this is the shareware version of doom.\n\n"\ + "you need to order the entire trilogy.\n\n"PRESSKEY + +#define MSGOFF "Messages OFF" +#define MSGON "Messages ON" +#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 RESTARTLEVEL "restart the level?\n\n"PRESSYN + +#define DOSY "(press y to quit)" + +#define DETAILHI "High detail" +#define DETAILLO "Low detail" +#define GAMMALVL0 "Gamma correction OFF" +#define GAMMALVL1 "Gamma correction level 1" +#define GAMMALVL2 "Gamma correction level 2" +#define GAMMALVL3 "Gamma correction level 3" +#define GAMMALVL4 "Gamma correction level 4" +#define EMPTYSTRING "empty slot" + +/* p_inter.c */ +#define GOTARMOR "Picked up the armor." +#define GOTMEGA "Picked up the MegaArmor!" +#define GOTHTHBONUS "Picked up a health bonus." +#define GOTARMBONUS "Picked up an armor bonus." +#define GOTSTIM "Picked up a stimpack." +#define GOTMEDINEED "Picked up a medikit that you REALLY need!" +#define GOTMEDIKIT "Picked up a medikit." +#define GOTSUPER "Supercharge!" + +#define GOTBLUECARD "Picked up a blue keycard." +#define GOTYELWCARD "Picked up a yellow keycard." +#define GOTREDCARD "Picked up a red keycard." +#define GOTBLUESKUL "Picked up a blue skull key." +#define GOTYELWSKUL "Picked up a yellow skull key." +#define GOTREDSKULL "Picked up a red skull key." + +#define GOTINVUL "Invulnerability!" +#define GOTBERSERK "Berserk!" +#define GOTINVIS "Partial Invisibility" +#define GOTSUIT "Radiation Shielding Suit" +#define GOTMAP "Computer Area Map" +#define GOTVISOR "Light Amplification Visor" +#define GOTMSPHERE "MegaSphere!" + +#define GOTCLIP "Picked up a clip." +#define GOTCLIPBOX "Picked up a box of bullets." +#define GOTROCKET "Picked up a rocket." +#define GOTROCKBOX "Picked up a box of rockets." +#define GOTCELL "Picked up an energy cell." +#define GOTCELLBOX "Picked up an energy cell pack." +#define GOTSHELLS "Picked up 4 shotgun shells." +#define GOTSHELLBOX "Picked up a box of shotgun shells." +#define GOTBACKPACK "Picked up a backpack full of ammo!" + +#define GOTBFG9000 "You got the BFG9000! Oh, yes." +#define GOTCHAINGUN "You got the chaingun!" +#define GOTCHAINSAW "A chainsaw! Find some meat!" +#define GOTLAUNCHER "You got the rocket launcher!" +#define GOTPLASMA "You got the plasma gun!" +#define GOTSHOTGUN "You got the shotgun!" +#define GOTSHOTGUN2 "You got the super shotgun!" + +/* p_doors.c */ +#define PD_BLUEO "You need a blue key to activate this object" +#define PD_REDO "You need a red key to activate this object" +#define PD_YELLOWO "You need a yellow key to activate this object" +#define PD_BLUEK "You need a blue key to open this door" +#define PD_REDK "You need a red key to open this door" +#define PD_YELLOWK "You need a yellow key to open this door" +/* jff 02/05/98 Create messages specific to card and skull keys */ +#define PD_BLUEC "You need a blue card to open this door" +#define PD_REDC "You need a red card to open this door" +#define PD_YELLOWC "You need a yellow card to open this door" +#define PD_BLUES "You need a blue skull to open this door" +#define PD_REDS "You need a red skull to open this door" +#define PD_YELLOWS "You need a yellow skull to open this door" +#define PD_ANY "Any key will open this door" +#define PD_ALL3 "You need all three keys to open this door" +#define PD_ALL6 "You need all six keys to open this door" + +/* g_game.c */ +#define GGSAVED "game saved." + +/* hu_stuff.c */ +#define HUSTR_MSGU "[Message unsent]" + +#define HUSTR_E1M1 "E1M1: Hangar" +#define HUSTR_E1M2 "E1M2: Nuclear Plant" +#define HUSTR_E1M3 "E1M3: Toxin Refinery" +#define HUSTR_E1M4 "E1M4: Command Control" +#define HUSTR_E1M5 "E1M5: Phobos Lab" +#define HUSTR_E1M6 "E1M6: Central Processing" +#define HUSTR_E1M7 "E1M7: Computer Station" +#define HUSTR_E1M8 "E1M8: Phobos Anomaly" +#define HUSTR_E1M9 "E1M9: Military Base" + +#define HUSTR_E2M1 "E2M1: Deimos Anomaly" +#define HUSTR_E2M2 "E2M2: Containment Area" +#define HUSTR_E2M3 "E2M3: Refinery" +#define HUSTR_E2M4 "E2M4: Deimos Lab" +#define HUSTR_E2M5 "E2M5: Command Center" +#define HUSTR_E2M6 "E2M6: Halls of the Damned" +#define HUSTR_E2M7 "E2M7: Spawning Vats" +#define HUSTR_E2M8 "E2M8: Tower of Babel" +#define HUSTR_E2M9 "E2M9: Fortress of Mystery" + +#define HUSTR_E3M1 "E3M1: Hell Keep" +#define HUSTR_E3M2 "E3M2: Slough of Despair" +#define HUSTR_E3M3 "E3M3: Pandemonium" +#define HUSTR_E3M4 "E3M4: House of Pain" +#define HUSTR_E3M5 "E3M5: Unholy Cathedral" +#define HUSTR_E3M6 "E3M6: Mt. Erebus" +#define HUSTR_E3M7 "E3M7: Limbo" +#define HUSTR_E3M8 "E3M8: Dis" +#define HUSTR_E3M9 "E3M9: Warrens" + +#define HUSTR_E4M1 "E4M1: Hell Beneath" +#define HUSTR_E4M2 "E4M2: Perfect Hatred" +#define HUSTR_E4M3 "E4M3: Sever The Wicked" +#define HUSTR_E4M4 "E4M4: Unruly Evil" +#define HUSTR_E4M5 "E4M5: They Will Repent" +#define HUSTR_E4M6 "E4M6: Against Thee Wickedly" +#define HUSTR_E4M7 "E4M7: And Hell Followed" +#define HUSTR_E4M8 "E4M8: Unto The Cruel" +#define HUSTR_E4M9 "E4M9: Fear" + +#define HUSTR_1 "level 1: entryway" +#define HUSTR_2 "level 2: underhalls" +#define HUSTR_3 "level 3: the gantlet" +#define HUSTR_4 "level 4: the focus" +#define HUSTR_5 "level 5: the waste tunnels" +#define HUSTR_6 "level 6: the crusher" +#define HUSTR_7 "level 7: dead simple" +#define HUSTR_8 "level 8: tricks and traps" +#define HUSTR_9 "level 9: the pit" +#define HUSTR_10 "level 10: refueling base" +#define HUSTR_11 "level 11: 'o' of destruction!" + +#define HUSTR_12 "level 12: the factory" +#define HUSTR_13 "level 13: downtown" +#define HUSTR_14 "level 14: the inmost dens" +#define HUSTR_15 "level 15: industrial zone" +#define HUSTR_16 "level 16: suburbs" +#define HUSTR_17 "level 17: tenements" +#define HUSTR_18 "level 18: the courtyard" +#define HUSTR_19 "level 19: the citadel" +#define HUSTR_20 "level 20: gotcha!" + +#define HUSTR_21 "level 21: nirvana" +#define HUSTR_22 "level 22: the catacombs" +#define HUSTR_23 "level 23: barrels o' fun" +#define HUSTR_24 "level 24: the chasm" +#define HUSTR_25 "level 25: bloodfalls" +#define HUSTR_26 "level 26: the abandoned mines" +#define HUSTR_27 "level 27: monster condo" +#define HUSTR_28 "level 28: the spirit world" +#define HUSTR_29 "level 29: the living end" +#define HUSTR_30 "level 30: icon of sin" + +#define HUSTR_31 "level 31: wolfenstein" +#define HUSTR_32 "level 32: grosse" + +#define PHUSTR_1 "level 1: congo" +#define PHUSTR_2 "level 2: well of souls" +#define PHUSTR_3 "level 3: aztec" +#define PHUSTR_4 "level 4: caged" +#define PHUSTR_5 "level 5: ghost town" +#define PHUSTR_6 "level 6: baron's lair" +#define PHUSTR_7 "level 7: caughtyard" +#define PHUSTR_8 "level 8: realm" +#define PHUSTR_9 "level 9: abattoire" +#define PHUSTR_10 "level 10: onslaught" +#define PHUSTR_11 "level 11: hunted" + +#define PHUSTR_12 "level 12: speed" +#define PHUSTR_13 "level 13: the crypt" +#define PHUSTR_14 "level 14: genesis" +#define PHUSTR_15 "level 15: the twilight" +#define PHUSTR_16 "level 16: the omen" +#define PHUSTR_17 "level 17: compound" +#define PHUSTR_18 "level 18: neurosphere" +#define PHUSTR_19 "level 19: nme" +#define PHUSTR_20 "level 20: the death domain" + +#define PHUSTR_21 "level 21: slayer" +#define PHUSTR_22 "level 22: impossible mission" +#define PHUSTR_23 "level 23: tombstone" +#define PHUSTR_24 "level 24: the final frontier" +#define PHUSTR_25 "level 25: the temple of darkness" +#define PHUSTR_26 "level 26: bunker" +#define PHUSTR_27 "level 27: anti-christ" +#define PHUSTR_28 "level 28: the sewers" +#define PHUSTR_29 "level 29: odyssey of noises" +#define PHUSTR_30 "level 30: the gateway of hell" + +#define PHUSTR_31 "level 31: cyberden" +#define PHUSTR_32 "level 32: go 2 it" + +#define THUSTR_1 "level 1: system control" +#define THUSTR_2 "level 2: human bbq" +#define THUSTR_3 "level 3: power control" +#define THUSTR_4 "level 4: wormhole" +#define THUSTR_5 "level 5: hanger" +#define THUSTR_6 "level 6: open season" +#define THUSTR_7 "level 7: prison" +#define THUSTR_8 "level 8: metal" +#define THUSTR_9 "level 9: stronghold" +#define THUSTR_10 "level 10: redemption" +#define THUSTR_11 "level 11: storage facility" + +#define THUSTR_12 "level 12: crater" +#define THUSTR_13 "level 13: nukage processing" +#define THUSTR_14 "level 14: steel works" +#define THUSTR_15 "level 15: dead zone" +#define THUSTR_16 "level 16: deepest reaches" +#define THUSTR_17 "level 17: processing area" +#define THUSTR_18 "level 18: mill" +#define THUSTR_19 "level 19: shipping/respawning" +#define THUSTR_20 "level 20: central processing" + +#define THUSTR_21 "level 21: administration center" +#define THUSTR_22 "level 22: habitat" +#define THUSTR_23 "level 23: lunar mining project" +#define THUSTR_24 "level 24: quarry" +#define THUSTR_25 "level 25: baron's den" +#define THUSTR_26 "level 26: ballistyx" +#define THUSTR_27 "level 27: mount pain" +#define THUSTR_28 "level 28: heck" +#define THUSTR_29 "level 29: river styx" +#define THUSTR_30 "level 30: last call" + +#define THUSTR_31 "level 31: pharaoh" +#define THUSTR_32 "level 32: caribbean" + +#define HUSTR_CHATMACRO1 "I'm ready to kick butt!" +#define HUSTR_CHATMACRO2 "I'm OK." +#define HUSTR_CHATMACRO3 "I'm not looking too good!" +#define HUSTR_CHATMACRO4 "Help!" +#define HUSTR_CHATMACRO5 "You suck!" +#define HUSTR_CHATMACRO6 "Next time, scumbag..." +#define HUSTR_CHATMACRO7 "Come here!" +#define HUSTR_CHATMACRO8 "I'll take care of it." +#define HUSTR_CHATMACRO9 "Yes" +#define HUSTR_CHATMACRO0 "No" + +#define HUSTR_TALKTOSELF1 "You mumble to yourself" +#define HUSTR_TALKTOSELF2 "Who's there?" +#define HUSTR_TALKTOSELF3 "You scare yourself" +#define HUSTR_TALKTOSELF4 "You start to rave" +#define HUSTR_TALKTOSELF5 "You've lost it..." + +#define HUSTR_MESSAGESENT "[Message Sent]" + +/* The following should NOT be changed unless it seems + * just AWFULLY necessary */ + +#define HUSTR_PLRGREEN "Player 1: " +#define HUSTR_PLRINDIGO "Player 2: " +#define HUSTR_PLRBROWN "Player 3: " +#define HUSTR_PLRRED "Player 4: " + +#define HUSTR_KEYGREEN 'g' +#define HUSTR_KEYINDIGO 'i' +#define HUSTR_KEYBROWN 'b' +#define HUSTR_KEYRED 'r' + +/* am_map.c */ + +#define AMSTR_FOLLOWON "Follow Mode ON" +#define AMSTR_FOLLOWOFF "Follow Mode OFF" + +#define AMSTR_GRIDON "Grid ON" +#define AMSTR_GRIDOFF "Grid OFF" + +#define AMSTR_MARKEDSPOT "Marked Spot" +#define AMSTR_MARKSCLEARED "All Marks Cleared" + +#define AMSTR_ROTATEON "Rotate Mode ON" +#define AMSTR_ROTATEOFF "Rotate Mode OFF" + +#define AMSTR_OVERLAYON "Overlay Mode ON" +#define AMSTR_OVERLAYOFF "Overlay Mode OFF" + +/* st_stuff.c */ + +#define STSTR_MUS "Music Change" +#define STSTR_NOMUS "IMPOSSIBLE SELECTION" +#define STSTR_DQDON "Degreelessness Mode On" +#define STSTR_DQDOFF "Degreelessness Mode Off" + +#define STSTR_KFAADDED "Very Happy Ammo Added" +#define STSTR_FAADDED "Ammo (no keys) Added" + +#define STSTR_NCON "No Clipping Mode ON" +#define STSTR_NCOFF "No Clipping Mode OFF" + +#define STSTR_BEHOLD "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp" +#define STSTR_BEHOLDX "Power-up Toggled" + +#define STSTR_CHOPPERS "... doesn't suck - GM" +#define STSTR_CLEV "Changing Level..." + +#define STSTR_COMPON "Compatibility Mode On" /* phares */ +#define STSTR_COMPOFF "Compatibility Mode Off" /* phares */ + +/* f_finale.c */ + +#define E1TEXT \ + "Once you beat the big badasses and\n"\ + "clean out the moon base you're supposed\n"\ + "to win, aren't you? Aren't you? Where's\n"\ + "your fat reward and ticket home? What\n"\ + "the hell is this? It's not supposed to\n"\ + "end this way!\n"\ + "\n" \ + "It stinks like rotten meat, but looks\n"\ + "like the lost Deimos base. Looks like\n"\ + "you're stuck on The Shores of Hell.\n"\ + "The only way out is through.\n"\ + "\n"\ + "To continue the DOOM experience, play\n"\ + "The Shores of Hell and its amazing\n"\ + "sequel, Inferno!\n" + + +#define E2TEXT \ + "You've done it! The hideous cyber-\n"\ + "demon lord that ruled the lost Deimos\n"\ + "moon base has been slain and you\n"\ + "are triumphant! But ... where are\n"\ + "you? You clamber to the edge of the\n"\ + "moon and look down to see the awful\n"\ + "truth.\n" \ + "\n"\ + "Deimos floats above Hell itself!\n"\ + "You've never heard of anyone escaping\n"\ + "from Hell, but you'll make the bastards\n"\ + "sorry they ever heard of you! Quickly,\n"\ + "you rappel down to the surface of\n"\ + "Hell.\n"\ + "\n" \ + "Now, it's on to the final chapter of\n"\ + "DOOM! -- Inferno." + + +#define E3TEXT \ + "The loathsome spiderdemon that\n"\ + "masterminded the invasion of the moon\n"\ + "bases and caused so much death has had\n"\ + "its ass kicked for all time.\n"\ + "\n"\ + "A hidden doorway opens and you enter.\n"\ + "You've proven too tough for Hell to\n"\ + "contain, and now Hell at last plays\n"\ + "fair -- for you emerge from the door\n"\ + "to see the green fields of Earth!\n"\ + "Home at last.\n" \ + "\n"\ + "You wonder what's been happening on\n"\ + "Earth while you were battling evil\n"\ + "unleashed. It's good that no Hell-\n"\ + "spawn could have come through that\n"\ + "door with you ..." + + +#define E4TEXT \ + "the spider mastermind must have sent forth\n"\ + "its legions of hellspawn before your\n"\ + "final confrontation with that terrible\n"\ + "beast from hell. but you stepped forward\n"\ + "and brought forth eternal damnation and\n"\ + "suffering upon the horde as a true hero\n"\ + "would in the face of something so evil.\n"\ + "\n"\ + "besides, someone was gonna pay for what\n"\ + "happened to daisy, your pet rabbit.\n"\ + "\n"\ + "but now, you see spread before you more\n"\ + "potential pain and gibbitude as a nation\n"\ + "of demons run amok among our cities.\n"\ + "\n"\ + "next stop, hell on earth!" + + +/* after level 6, put this: */ + +#define C1TEXT \ + "YOU HAVE ENTERED DEEPLY INTO THE INFESTED\n" \ + "STARPORT. BUT SOMETHING IS WRONG. THE\n" \ + "MONSTERS HAVE BROUGHT THEIR OWN REALITY\n" \ + "WITH THEM, AND THE STARPORT'S TECHNOLOGY\n" \ + "IS BEING SUBVERTED BY THEIR PRESENCE.\n" \ + "\n"\ + "AHEAD, YOU SEE AN OUTPOST OF HELL, A\n" \ + "FORTIFIED ZONE. IF YOU CAN GET PAST IT,\n" \ + "YOU CAN PENETRATE INTO THE HAUNTED HEART\n" \ + "OF THE STARBASE AND FIND THE CONTROLLING\n" \ + "SWITCH WHICH HOLDS EARTH'S POPULATION\n" \ + "HOSTAGE." + +/* After level 11, put this: */ + +#define C2TEXT \ + "YOU HAVE WON! YOUR VICTORY HAS ENABLED\n" \ + "HUMANKIND TO EVACUATE EARTH AND ESCAPE\n"\ + "THE NIGHTMARE. NOW YOU ARE THE ONLY\n"\ + "HUMAN LEFT ON THE FACE OF THE PLANET.\n"\ + "CANNIBAL MUTATIONS, CARNIVOROUS ALIENS,\n"\ + "AND EVIL SPIRITS ARE YOUR ONLY NEIGHBORS.\n"\ + "YOU SIT BACK AND WAIT FOR DEATH, CONTENT\n"\ + "THAT YOU HAVE SAVED YOUR SPECIES.\n"\ + "\n"\ + "BUT THEN, EARTH CONTROL BEAMS DOWN A\n"\ + "MESSAGE FROM SPACE: \"SENSORS HAVE LOCATED\n"\ + "THE SOURCE OF THE ALIEN INVASION. IF YOU\n"\ + "GO THERE, YOU MAY BE ABLE TO BLOCK THEIR\n"\ + "ENTRY. THE ALIEN BASE IS IN THE HEART OF\n"\ + "YOUR OWN HOME CITY, NOT FAR FROM THE\n"\ + "STARPORT.\" SLOWLY AND PAINFULLY YOU GET\n"\ + "UP AND RETURN TO THE FRAY." + + +/* After level 20, put this: */ + +#define C3TEXT \ + "YOU ARE AT THE CORRUPT HEART OF THE CITY,\n"\ + "SURROUNDED BY THE CORPSES OF YOUR ENEMIES.\n"\ + "YOU SEE NO WAY TO DESTROY THE CREATURES'\n"\ + "ENTRYWAY ON THIS SIDE, SO YOU CLENCH YOUR\n"\ + "TEETH AND PLUNGE THROUGH IT.\n"\ + "\n"\ + "THERE MUST BE A WAY TO CLOSE IT ON THE\n"\ + "OTHER SIDE. WHAT DO YOU CARE IF YOU'VE\n"\ + "GOT TO GO THROUGH HELL TO GET TO IT?" + + +/* After level 29, put this: */ + +#define C4TEXT \ + "THE HORRENDOUS VISAGE OF THE BIGGEST\n"\ + "DEMON YOU'VE EVER SEEN CRUMBLES BEFORE\n"\ + "YOU, AFTER YOU PUMP YOUR ROCKETS INTO\n"\ + "HIS EXPOSED BRAIN. THE MONSTER SHRIVELS\n"\ + "UP AND DIES, ITS THRASHING LIMBS\n"\ + "DEVASTATING UNTOLD MILES OF HELL'S\n"\ + "SURFACE.\n"\ + "\n"\ + "YOU'VE DONE IT. THE INVASION IS OVER.\n"\ + "EARTH IS SAVED. HELL IS A WRECK. YOU\n"\ + "WONDER WHERE BAD FOLKS WILL GO WHEN THEY\n"\ + "DIE, NOW. WIPING THE SWEAT FROM YOUR\n"\ + "FOREHEAD YOU BEGIN THE LONG TREK BACK\n"\ + "HOME. REBUILDING EARTH OUGHT TO BE A\n"\ + "LOT MORE FUN THAN RUINING IT WAS.\n" + +/* Before level 31, put this: */ + +#define C5TEXT \ + "CONGRATULATIONS, YOU'VE FOUND THE SECRET\n"\ + "LEVEL! LOOKS LIKE IT'S BEEN BUILT BY\n"\ + "HUMANS, RATHER THAN DEMONS. YOU WONDER\n"\ + "WHO THE INMATES OF THIS CORNER OF HELL\n"\ + "WILL BE." + + +/* Before level 32, put this: */ + +#define C6TEXT \ + "CONGRATULATIONS, YOU'VE FOUND THE\n"\ + "SUPER SECRET LEVEL! YOU'D BETTER\n"\ + "BLAZE THROUGH THIS ONE!\n" + +/*** Plutonia ***/ +/* after map 06 */ + +#define P1TEXT \ + "You gloat over the steaming carcass of the\n"\ + "Guardian. With its death, you've wrested\n"\ + "the Accelerator from the stinking claws\n"\ + "of Hell. You relax and glance around the\n"\ + "room. Damn! There was supposed to be at\n"\ + "least one working prototype, but you can't\n"\ + "see it. The demons must have taken it.\n"\ + "\n"\ + "You must find the prototype, or all your\n"\ + "struggles will have been wasted. Keep\n"\ + "moving, keep fighting, keep killing.\n"\ + "Oh yes, keep living, too." + + +/* after map 11 */ + +#define P2TEXT \ + "Even the deadly Arch-Vile labyrinth could\n"\ + "not stop you, and you've gotten to the\n"\ + "prototype Accelerator which is soon\n"\ + "efficiently and permanently deactivated.\n"\ + "\n"\ + "You're good at that kind of thing." + + +/* after map 20 */ + +#define P3TEXT \ + "You've bashed and battered your way into\n"\ + "the heart of the devil-hive. Time for a\n"\ + "Search-and-Destroy mission, aimed at the\n"\ + "Gatekeeper, whose foul offspring is\n"\ + "cascading to Earth. Yeah, he's bad. But\n"\ + "you know who's worse!\n"\ + "\n"\ + "Grinning evilly, you check your gear, and\n"\ + "get ready to give the bastard a little Hell\n"\ + "of your own making!" + +/* after map 30 */ + +#define P4TEXT \ + "The Gatekeeper's evil face is splattered\n"\ + "all over the place. As its tattered corpse\n"\ + "collapses, an inverted Gate forms and\n"\ + "sucks down the shards of the last\n"\ + "prototype Accelerator, not to mention the\n"\ + "few remaining demons. You're done. Hell\n"\ + "has gone back to pounding bad dead folks \n"\ + "instead of good live ones. Remember to\n"\ + "tell your grandkids to put a rocket\n"\ + "launcher in your coffin. If you go to Hell\n"\ + "when you die, you'll need it for some\n"\ + "final cleaning-up ..." + +/* before map 31 */ + +#define P5TEXT \ + "You've found the second-hardest level we\n"\ + "got. Hope you have a saved game a level or\n"\ + "two previous. If not, be prepared to die\n"\ + "aplenty. For master marines only." + +/* before map 32 */ + +#define P6TEXT \ + "Betcha wondered just what WAS the hardest\n"\ + "level we had ready for ya? Now you know.\n"\ + "No one gets out alive." + +/*** TNT: Evilution ***/ + +#define T1TEXT \ + "You've fought your way out of the infested\n"\ + "experimental labs. It seems that UAC has\n"\ + "once again gulped it down. With their\n"\ + "high turnover, it must be hard for poor\n"\ + "old UAC to buy corporate health insurance\n"\ + "nowadays..\n"\ + "\n"\ + "Ahead lies the military complex, now\n"\ + "swarming with diseased horrors hot to get\n"\ + "their teeth into you. With luck, the\n"\ + "complex still has some warlike ordnance\n"\ + "laying around." + + +#define T2TEXT \ + "You hear the grinding of heavy machinery\n"\ + "ahead. You sure hope they're not stamping\n"\ + "out new hellspawn, but you're ready to\n"\ + "ream out a whole herd if you have to.\n"\ + "They might be planning a blood feast, but\n"\ + "you feel about as mean as two thousand\n"\ + "maniacs packed into one mad killer.\n"\ + "\n"\ + "You don't plan to go down easy." + + +#define T3TEXT \ + "The vista opening ahead looks real damn\n"\ + "familiar. Smells familiar, too -- like\n"\ + "fried excrement. You didn't like this\n"\ + "place before, and you sure as hell ain't\n"\ + "planning to like it now. The more you\n"\ + "brood on it, the madder you get.\n"\ + "Hefting your gun, an evil grin trickles\n"\ + "onto your face. Time to take some names." + +#define T4TEXT \ + "Suddenly, all is silent, from one horizon\n"\ + "to the other. The agonizing echo of Hell\n"\ + "fades away, the nightmare sky turns to\n"\ + "blue, the heaps of monster corpses start \n"\ + "to evaporate along with the evil stench \n"\ + "that filled the air. Jeeze, maybe you've\n"\ + "done it. Have you really won?\n"\ + "\n"\ + "Something rumbles in the distance.\n"\ + "A blue light begins to glow inside the\n"\ + "ruined skull of the demon-spitter." + + +#define T5TEXT \ + "What now? Looks totally different. Kind\n"\ + "of like King Tut's condo. Well,\n"\ + "whatever's here can't be any worse\n"\ + "than usual. Can it? Or maybe it's best\n"\ + "to let sleeping gods lie.." + + +#define T6TEXT \ + "Time for a vacation. You've burst the\n"\ + "bowels of hell and by golly you're ready\n"\ + "for a break. You mutter to yourself,\n"\ + "Maybe someone else can kick Hell's ass\n"\ + "next time around. Ahead lies a quiet town,\n"\ + "with peaceful flowing water, quaint\n"\ + "buildings, and presumably no Hellspawn.\n"\ + "\n"\ + "As you step off the transport, you hear\n"\ + "the stomp of a cyberdemon's iron shoe." + + + +/* + * Character cast strings F_FINALE.C + */ +#define CC_ZOMBIE "ZOMBIEMAN" +#define CC_SHOTGUN "SHOTGUN GUY" +#define CC_HEAVY "HEAVY WEAPON DUDE" +#define CC_IMP "IMP" +#define CC_DEMON "DEMON" +#define CC_LOST "LOST SOUL" +#define CC_CACO "CACODEMON" +#define CC_HELL "HELL KNIGHT" +#define CC_BARON "BARON OF HELL" +#define CC_ARACH "ARACHNOTRON" +#define CC_PAIN "PAIN ELEMENTAL" +#define CC_REVEN "REVENANT" +#define CC_MANCU "MANCUBUS" +#define CC_ARCH "ARCH-VILE" +#define CC_SPIDER "THE SPIDER MASTERMIND" +#define CC_CYBER "THE CYBERDEMON" +#define CC_HERO "OUR HERO" + + +#endif diff --git a/src/d_event.h b/src/d_event.h new file mode 100644 index 0000000..da5e702 --- /dev/null +++ b/src/d_event.h @@ -0,0 +1,125 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Event information structures. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __D_EVENT__ +#define __D_EVENT__ + + +#include "doomtype.h" + + +// +// Event handling. +// + +// Input event types. +typedef enum +{ + ev_keydown, + ev_keyup, + ev_mouse, + ev_joystick +} 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 +} event_t; + + +typedef enum +{ + ga_nothing, + ga_loadlevel, + ga_newgame, + ga_loadgame, + ga_savegame, + ga_playdemo, + ga_completed, + ga_victory, + ga_worlddone, +} gameaction_t; + + + +// +// Button/action code definitions. +// +typedef enum +{ + // Press "Fire". + BT_ATTACK = 1, + + // Use button, to open doors, activate switches. + BT_USE = 2, + + // Flag: game events, not really buttons. + BT_SPECIAL = 128, + BT_SPECIALMASK = 3, + + // Flag, weapon change pending. + // If true, the next 4 bits hold weapon num. + BT_CHANGE = 4, + + // The 4bit weapon mask and shift, convenience. +//BT_WEAPONMASK = (8+16+32), + BT_WEAPONMASK = (8+16+32+64), // extended to pick up SSG // phares + BT_WEAPONSHIFT = 3, + + // Special events + BTS_LOADGAME = 0, // Loads a game + // Pause the game. + BTS_PAUSE = 1, + // Save the game at each console. + BTS_SAVEGAME = 2, + BTS_RESTARTLEVEL= 3, // Restarts the current level + + // Savegame slot numbers occupy the second byte of buttons. + BTS_SAVEMASK = (4+8+16), + BTS_SAVESHIFT = 2, + +} buttoncode_t; + + +// +// GLOBAL VARIABLES +// + +extern gameaction_t gameaction; + +#endif diff --git a/src/d_items.c b/src/d_items.c new file mode 100644 index 0000000..5adc28d --- /dev/null +++ b/src/d_items.c @@ -0,0 +1,140 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Something to do with weapon sprite frames. Don't ask me. + * + *----------------------------------------------------------------------------- + */ + +// We are referring to sprite numbers. +#include "doomtype.h" +#include "info.h" + +#ifdef __GNUG__ +#pragma implementation "d_items.h" +#endif +#include "d_items.h" + + +// +// PSPRITE ACTIONS for waepons. +// This struct controls the weapon animations. +// +// Each entry is: +// ammo/amunition type +// upstate +// downstate +// readystate +// atkstate, i.e. attack/fire/hit frame +// flashstate, muzzle flash +// +weaponinfo_t weaponinfo[NUMWEAPONS] = +{ + { + // fist + am_noammo, + S_PUNCHUP, + S_PUNCHDOWN, + S_PUNCH, + S_PUNCH1, + S_NULL + }, + { + // pistol + am_clip, + S_PISTOLUP, + S_PISTOLDOWN, + S_PISTOL, + S_PISTOL1, + S_PISTOLFLASH + }, + { + // shotgun + am_shell, + S_SGUNUP, + S_SGUNDOWN, + S_SGUN, + S_SGUN1, + S_SGUNFLASH1 + }, + { + // chaingun + am_clip, + S_CHAINUP, + S_CHAINDOWN, + S_CHAIN, + S_CHAIN1, + S_CHAINFLASH1 + }, + { + // missile launcher + am_misl, + S_MISSILEUP, + S_MISSILEDOWN, + S_MISSILE, + S_MISSILE1, + S_MISSILEFLASH1 + }, + { + // plasma rifle + am_cell, + S_PLASMAUP, + S_PLASMADOWN, + S_PLASMA, + S_PLASMA1, + S_PLASMAFLASH1 + }, + { + // bfg 9000 + am_cell, + S_BFGUP, + S_BFGDOWN, + S_BFG, + S_BFG1, + S_BFGFLASH1 + }, + { + // chainsaw + am_noammo, + S_SAWUP, + S_SAWDOWN, + S_SAW, + S_SAW1, + S_NULL + }, + { + // super shotgun + am_shell, + S_DSGUNUP, + S_DSGUNDOWN, + S_DSGUN, + S_DSGUN1, + S_DSGUNFLASH1 + }, +}; diff --git a/src/d_items.h b/src/d_items.h new file mode 100644 index 0000000..8da4df2 --- /dev/null +++ b/src/d_items.h @@ -0,0 +1,59 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Items: key cards, artifacts, weapon, ammunition. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __D_ITEMS__ +#define __D_ITEMS__ + +#include "doomdef.h" + +#ifdef __GNUG__ +#pragma interface +#endif + + +/* Weapon info: sprite frames, ammunition use. */ +typedef struct +{ + ammotype_t ammo; + int upstate; + int downstate; + int readystate; + int atkstate; + int flashstate; + +} weaponinfo_t; + +extern weaponinfo_t weaponinfo[NUMWEAPONS]; + +#endif diff --git a/src/d_main.c b/src/d_main.c new file mode 100644 index 0000000..6d8493e --- /dev/null +++ b/src/d_main.c @@ -0,0 +1,1725 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2004 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * DOOM main program (D_DoomMain) and game loop (D_DoomLoop), + * plus functions to determine game mode (shareware, registered), + * parse command line parameters, configure game parameters (turbo), + * and call the startup functions. + * + *----------------------------------------------------------------------------- + */ + + +#ifdef _MSC_VER +#define F_OK 0 /* Check for file existence */ +#define W_OK 2 /* Check for write permission */ +#define R_OK 4 /* Check for read permission */ +#include +#include +#else +#include +#endif +#include +#include +#include + +#include "doomdef.h" +#include "doomtype.h" +#include "doomstat.h" +#include "d_net.h" +#include "dstrings.h" +#include "sounds.h" +#include "z_zone.h" +#include "w_wad.h" +#include "s_sound.h" +#include "v_video.h" +#include "f_finale.h" +#include "f_wipe.h" +#include "m_argv.h" +#include "m_misc.h" +#include "m_menu.h" +#include "p_checksum.h" +#include "i_main.h" +#include "i_system.h" +#include "i_sound.h" +#include "i_video.h" +#include "g_game.h" +#include "hu_stuff.h" +#include "wi_stuff.h" +#include "st_stuff.h" +#include "am_map.h" +#include "p_setup.h" +#include "r_draw.h" +#include "r_main.h" +#include "r_fps.h" +#include "d_main.h" +#include "d_deh.h" // Ty 04/08/98 - Externalizations +#include "lprintf.h" // jff 08/03/98 - declaration of lprintf +#include "am_map.h" + +void GetFirstMap(int *ep, int *map); // Ty 08/29/98 - add "-warp x" functionality +static void D_PageDrawer(void); + +// CPhipps - removed wadfiles[] stuff + +boolean devparm; // started game with -devparm + +// jff 1/24/98 add new versions of these variables to remember command line +boolean clnomonsters; // checkparm of -nomonsters +boolean clrespawnparm; // checkparm of -respawn +boolean clfastparm; // checkparm of -fast +// jff 1/24/98 end definition of command line version of play mode switches + +boolean nomonsters; // working -nomonsters +boolean respawnparm; // working -respawn +boolean fastparm; // working -fast + +boolean singletics = false; // debug flag to cancel adaptiveness + +//jff 1/22/98 parms for disabling music and sound +boolean nosfxparm; +boolean nomusicparm; + +//jff 4/18/98 +extern boolean inhelpscreens; + +skill_t startskill; +int startepisode; +int startmap; +boolean autostart; +FILE *debugfile; +int ffmap; + +boolean advancedemo; + +char wadfile[PATH_MAX+1]; // primary wad file +char mapdir[PATH_MAX+1]; // directory of development maps +char baseiwad[PATH_MAX+1]; // jff 3/23/98: iwad directory +char basesavegame[PATH_MAX+1]; // killough 2/16/98: savegame directory + +//jff 4/19/98 list of standard IWAD names +const char *const standard_iwads[]= +{ + "doom2f.wad", + "doom2.wad", + "plutonia.wad", + "tnt.wad", + "doom.wad", + "doom1.wad", + "doomu.wad", /* CPhipps - alow doomu.wad */ + "freedoom.wad", /* wart@kobold.org: added freedoom for Fedora Extras */ +}; +static const int nstandard_iwads = sizeof standard_iwads/sizeof*standard_iwads; + +/* + * D_PostEvent - Event handling + * + * Called by I/O functions when an event is received. + * Try event handlers for each code area in turn. + * cph - in the true spirit of the Boom source, let the + * short ciruit operator madness begin! + */ + +void D_PostEvent(event_t *ev) +{ + /* cph - suppress all input events at game start + * FIXME: This is a lousy kludge */ + if (gametic < 3) return; + M_Responder(ev) || + (gamestate == GS_LEVEL && ( + HU_Responder(ev) || + ST_Responder(ev) || + AM_Responder(ev) + ) + ) || + G_Responder(ev); +} + +// +// D_Wipe +// +// CPhipps - moved the screen wipe code from D_Display to here +// The screens to wipe between are already stored, this just does the timing +// and screen updating + +static void D_Wipe(void) +{ + boolean done; + int wipestart = I_GetTime () - 1; + + do + { + int nowtime, tics; + do + { + I_uSleep(5000); // CPhipps - don't thrash cpu in this loop + nowtime = I_GetTime(); + tics = nowtime - wipestart; + } + while (!tics); + wipestart = nowtime; + done = wipe_ScreenWipe(tics); + I_UpdateNoBlit(); + M_Drawer(); // menu is drawn even on top of wipes + I_FinishUpdate(); // page flip or blit buffer + } + while (!done); +} + +// +// D_Display +// draw current display, possibly wiping it from the previous +// + +// wipegamestate can be set to -1 to force a wipe on the next draw +gamestate_t wipegamestate = GS_DEMOSCREEN; +extern boolean setsizeneeded; +extern int showMessages; + +void D_Display (void) +{ + static boolean inhelpscreensstate = false; + static boolean isborderstate = false; + static boolean borderwillneedredraw = false; + static gamestate_t oldgamestate = -1; + boolean wipe; + boolean viewactive = false, isborder = false; + + if (nodrawers) // for comparative timing / profiling + return; + + if (!I_StartDisplay()) + return; + + // save the current screen if about to wipe + if ((wipe = gamestate != wipegamestate) && (V_GetMode() != VID_MODEGL)) + wipe_StartScreen(); + + if (gamestate != GS_LEVEL) { // Not a level + switch (oldgamestate) { + case -1: + case GS_LEVEL: + V_SetPalette(0); // cph - use default (basic) palette + default: + break; + } + + switch (gamestate) { + case GS_INTERMISSION: + WI_Drawer(); + break; + case GS_FINALE: + F_Drawer(); + break; + case GS_DEMOSCREEN: + D_PageDrawer(); + break; + default: + break; + } + } else if (gametic != basetic) { // In a level + boolean redrawborderstuff; + + HU_Erase(); + + if (setsizeneeded) { // change the view size if needed + R_ExecuteSetViewSize(); + oldgamestate = -1; // force background redraw + } + + // Work out if the player view is visible, and if there is a border + viewactive = (!(automapmode & am_active) || (automapmode & am_overlay)) && !inhelpscreens; + isborder = viewactive ? (viewheight != SCREENHEIGHT) : (!inhelpscreens && (automapmode & am_active)); + + if (oldgamestate != GS_LEVEL) { + R_FillBackScreen (); // draw the pattern into the back screen + redrawborderstuff = isborder; + } else { + // CPhipps - + // If there is a border, and either there was no border last time, + // or the border might need refreshing, then redraw it. + redrawborderstuff = isborder && (!isborderstate || borderwillneedredraw); + // The border may need redrawing next time if the border surrounds the screen, + // and there is a menu being displayed + borderwillneedredraw = menuactive && isborder && viewactive && (viewwidth != SCREENWIDTH); + } + if (redrawborderstuff || (V_GetMode() == VID_MODEGL)) + R_DrawViewBorder(); + + // Now do the drawing + if (viewactive) + R_RenderPlayerView (&players[displayplayer]); + if (automapmode & am_active) + AM_Drawer(); + ST_Drawer((viewheight != SCREENHEIGHT) || ((automapmode & am_active) && !(automapmode & am_overlay)), redrawborderstuff); + if (V_GetMode() != VID_MODEGL) + R_DrawViewBorder(); + HU_Drawer(); + } + + inhelpscreensstate = inhelpscreens; + isborderstate = isborder; + oldgamestate = wipegamestate = gamestate; + + // draw pause pic + if (paused) { + // Simplified the "logic" here and no need for x-coord caching - POPE + V_DrawNamePatch((320 - V_NamePatchWidth("M_PAUSE"))/2, 4, + 0, "M_PAUSE", CR_DEFAULT, VPT_STRETCH); + } + + // menus go directly to the screen + M_Drawer(); // menu is drawn even on top of everything +#ifdef HAVE_NET + NetUpdate(); // send out any new accumulation +#else + D_BuildNewTiccmds(); +#endif + + // normal update + if (!wipe || (V_GetMode() == VID_MODEGL)) + I_FinishUpdate (); // page flip or blit buffer + else { + // wipe update + wipe_EndScreen(); + D_Wipe(); + } + + I_EndDisplay(); + + //e6y: don't thrash cpu during pausing + if (paused) { + I_uSleep(1000); + } +} + +// CPhipps - Auto screenshot Variables + +static int auto_shot_count, auto_shot_time; +static const char *auto_shot_fname; + +// +// D_DoomLoop() +// +// Not a globally visible function, +// just included for source reference, +// called by D_DoomMain, never exits. +// Manages timing and IO, +// calls all ?_Responder, ?_Ticker, and ?_Drawer, +// calls I_GetTime, I_StartFrame, and I_StartTic +// + +static void D_DoomLoop(void) +{ + for (;;) + { + WasRenderedInTryRunTics = false; + // frame syncronous IO operations + I_StartFrame (); + + if (ffmap == gamemap) ffmap = 0; + + // process one or more tics + if (singletics) + { + I_StartTic (); + G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]); + if (advancedemo) + D_DoAdvanceDemo (); + M_Ticker (); + G_Ticker (); + P_Checksum(gametic); + gametic++; + maketic++; + } + else + TryRunTics (); // will run at least one tic + + // killough 3/16/98: change consoleplayer to displayplayer + if (players[displayplayer].mo) // cph 2002/08/10 + S_UpdateSounds(players[displayplayer].mo);// move positional sounds + + if (V_GetMode() == VID_MODEGL ? + !movement_smooth || !WasRenderedInTryRunTics : + !movement_smooth || !WasRenderedInTryRunTics || gamestate != wipegamestate + ) + { + // Update display, next frame, with current state. + D_Display(); + } + + // CPhipps - auto screenshot + if (auto_shot_fname && !--auto_shot_count) { + auto_shot_count = auto_shot_time; + M_DoScreenShot(auto_shot_fname); + } + } +} + +// +// DEMO LOOP +// + +static int demosequence; // killough 5/2/98: made static +static int pagetic; +static const char *pagename; // CPhipps - const + +// +// D_PageTicker +// Handles timing for warped projection +// +void D_PageTicker(void) +{ + if (--pagetic < 0) + D_AdvanceDemo(); +} + +// +// D_PageDrawer +// +static void D_PageDrawer(void) +{ + // proff/nicolas 09/14/98 -- now stretchs bitmaps to fullscreen! + // CPhipps - updated for new patch drawing + // proff - added M_DrawCredits + if (pagename) + { + V_DrawNamePatch(0, 0, 0, pagename, CR_DEFAULT, VPT_STRETCH); + } + else + M_DrawCredits(); +} + +// +// D_AdvanceDemo +// Called after each demo or intro demosequence finishes +// +void D_AdvanceDemo (void) +{ + advancedemo = true; +} + +/* killough 11/98: functions to perform demo sequences + * cphipps 10/99: constness fixes + */ + +static void D_SetPageName(const char *name) +{ + pagename = name; +} + +static void D_DrawTitle1(const char *name) +{ + S_StartMusic(mus_intro); + pagetic = (TICRATE*170)/35; + D_SetPageName(name); +} + +static void D_DrawTitle2(const char *name) +{ + S_StartMusic(mus_dm2ttl); + D_SetPageName(name); +} + +/* killough 11/98: tabulate demo sequences + */ + +static struct +{ + void (*func)(const char *); + const char *name; +} const demostates[][4] = + { + { + {D_DrawTitle1, "TITLEPIC"}, + {D_DrawTitle1, "TITLEPIC"}, + {D_DrawTitle2, "TITLEPIC"}, + {D_DrawTitle1, "TITLEPIC"}, + }, + + { + {G_DeferedPlayDemo, "demo1"}, + {G_DeferedPlayDemo, "demo1"}, + {G_DeferedPlayDemo, "demo1"}, + {G_DeferedPlayDemo, "demo1"}, + }, + { + {D_SetPageName, NULL}, + {D_SetPageName, NULL}, + {D_SetPageName, NULL}, + {D_SetPageName, NULL}, + }, + + { + {G_DeferedPlayDemo, "demo2"}, + {G_DeferedPlayDemo, "demo2"}, + {G_DeferedPlayDemo, "demo2"}, + {G_DeferedPlayDemo, "demo2"}, + }, + + { + {D_SetPageName, "HELP2"}, + {D_SetPageName, "HELP2"}, + {D_SetPageName, "CREDIT"}, + {D_DrawTitle1, "TITLEPIC"}, + }, + + { + {G_DeferedPlayDemo, "demo3"}, + {G_DeferedPlayDemo, "demo3"}, + {G_DeferedPlayDemo, "demo3"}, + {G_DeferedPlayDemo, "demo3"}, + }, + + { + {NULL}, + {NULL}, + {NULL}, + {D_SetPageName, "CREDIT"}, + }, + + { + {NULL}, + {NULL}, + {NULL}, + {G_DeferedPlayDemo, "demo4"}, + }, + + { + {NULL}, + {NULL}, + {NULL}, + {NULL}, + } + }; + +/* + * This cycles through the demo sequences. + * killough 11/98: made table-driven + */ + +void D_DoAdvanceDemo(void) +{ + players[consoleplayer].playerstate = PST_LIVE; /* not reborn */ + advancedemo = usergame = paused = false; + gameaction = ga_nothing; + + pagetic = TICRATE * 11; /* killough 11/98: default behavior */ + gamestate = GS_DEMOSCREEN; + + if (netgame && !demoplayback) { + demosequence = 0; + } else + if (!demostates[++demosequence][gamemode].func) + demosequence = 0; + demostates[demosequence][gamemode].func + (demostates[demosequence][gamemode].name); +} + +// +// D_StartTitle +// +void D_StartTitle (void) +{ + gameaction = ga_nothing; + demosequence = -1; + D_AdvanceDemo(); +} + +// +// D_AddFile +// +// Rewritten by Lee Killough +// +// Ty 08/29/98 - add source parm to indicate where this came from +// CPhipps - static, const char* parameter +// - source is an enum +// - modified to allocate & use new wadfiles array +void D_AddFile (const char *file, wad_source_t source) +{ + char *gwa_filename=NULL; + + wadfiles = realloc(wadfiles, sizeof(*wadfiles)*(numwadfiles+1)); + wadfiles[numwadfiles].name = + AddDefaultExtension(strcpy(malloc(strlen(file)+5), file), ".wad"); + wadfiles[numwadfiles].src = source; // Ty 08/29/98 + numwadfiles++; + // proff: automatically try to add the gwa files + // proff - moved from w_wad.c + gwa_filename=AddDefaultExtension(strcpy(malloc(strlen(file)+5), file), ".wad"); + if (strlen(gwa_filename)>4) + if (!strcasecmp(gwa_filename+(strlen(gwa_filename)-4),".wad")) + { + char *ext; + ext = &gwa_filename[strlen(gwa_filename)-4]; + ext[1] = 'g'; ext[2] = 'w'; ext[3] = 'a'; + wadfiles = realloc(wadfiles, sizeof(*wadfiles)*(numwadfiles+1)); + wadfiles[numwadfiles].name = gwa_filename; + wadfiles[numwadfiles].src = source; // Ty 08/29/98 + numwadfiles++; + } +} + +// killough 10/98: support -dehout filename +// cph - made const, don't cache results +static const char *D_dehout(void) +{ + int p = M_CheckParm("-dehout"); + if (!p) + p = M_CheckParm("-bexout"); + return (p && ++p < myargc ? myargv[p] : NULL); +} + +// +// CheckIWAD +// +// Verify a file is indeed tagged as an IWAD +// Scan its lumps for levelnames and return gamemode as indicated +// Detect missing wolf levels in DOOM II +// +// The filename to check is passed in iwadname, the gamemode detected is +// returned in gmode, hassec returns the presence of secret levels +// +// jff 4/19/98 Add routine to test IWAD for validity and determine +// the gamemode from it. Also note if DOOM II, whether secret levels exist +// CPhipps - const char* for iwadname, made static +static void CheckIWAD(const char *iwadname,GameMode_t *gmode,boolean *hassec) +{ + if ( !access (iwadname,R_OK) ) + { + int ud=0,rg=0,sw=0,cm=0,sc=0; + FILE* fp; + + // Identify IWAD correctly + if ((fp = fopen(iwadname, "rb"))) + { + wadinfo_t header; + + // read IWAD header + if (fread(&header, sizeof(header), 1, fp) == 1 && !strncmp(header.identification, "IWAD", 4)) + { + size_t length; + filelump_t *fileinfo; + + // read IWAD directory + header.numlumps = LONG(header.numlumps); + header.infotableofs = LONG(header.infotableofs); + length = header.numlumps; + fileinfo = malloc(length*sizeof(filelump_t)); + if (fseek (fp, header.infotableofs, SEEK_SET) || + fread (fileinfo, sizeof(filelump_t), length, fp) != length || + fclose(fp)) + I_Error("CheckIWAD: failed to read directory %s",iwadname); + + // scan directory for levelname lumps + while (length--) + if (fileinfo[length].name[0] == 'E' && + fileinfo[length].name[2] == 'M' && + fileinfo[length].name[4] == 0) + { + if (fileinfo[length].name[1] == '4') + ++ud; + else if (fileinfo[length].name[1] == '3') + ++rg; + else if (fileinfo[length].name[1] == '2') + ++rg; + else if (fileinfo[length].name[1] == '1') + ++sw; + } + else if (fileinfo[length].name[0] == 'M' && + fileinfo[length].name[1] == 'A' && + fileinfo[length].name[2] == 'P' && + fileinfo[length].name[5] == 0) + { + ++cm; + if (fileinfo[length].name[3] == '3') + if (fileinfo[length].name[4] == '1' || + fileinfo[length].name[4] == '2') + ++sc; + } + + free(fileinfo); + } + else // missing IWAD tag in header + I_Error("CheckIWAD: IWAD tag %s not present", iwadname); + } + else // error from open call + I_Error("CheckIWAD: Can't open IWAD %s", iwadname); + + // Determine game mode from levels present + // Must be a full set for whichever mode is present + // Lack of wolf-3d levels also detected here + + *gmode = indetermined; + *hassec = false; + if (cm>=30) + { + *gmode = commercial; + *hassec = sc>=2; + } + else if (ud>=9) + *gmode = retail; + else if (rg>=18) + *gmode = registered; + else if (sw>=9) + *gmode = shareware; + } + else // error from access call + I_Error("CheckIWAD: IWAD %s not readable", iwadname); +} + + + +// NormalizeSlashes +// +// Remove trailing slashes, translate backslashes to slashes +// The string to normalize is passed and returned in str +// +// jff 4/19/98 Make killoughs slash fixer a subroutine +// +static void NormalizeSlashes(char *str) +{ + int l; + + // killough 1/18/98: Neater / \ handling. + // Remove trailing / or \ to prevent // /\ \/ \\, and change \ to / + + if (!str || !(l = strlen(str))) + return; + if (str[--l]=='/' || str[l]=='\\') // killough 1/18/98 + str[l]=0; + while (l--) + if (str[l]=='\\') + str[l]='/'; +} + +/* + * FindIWADFIle + * + * Search for one of the standard IWADs + * CPhipps - static, proper prototype + * - 12/1999 - rewritten to use I_FindFile + */ +static char *FindIWADFile(void) +{ + int i; + char * iwad = NULL; + + i = M_CheckParm("-iwad"); + if (i && (++i < myargc)) { + iwad = I_FindFile(myargv[i], ".wad"); + } else { + for (i=0; !iwad && i PATH_MAX-12) p = NULL; + + strcpy(basesavegame,(p == NULL) ? I_DoomExeDir() : p); + } + if ((i=M_CheckParm("-save")) && i=10 && !strnicmp(iwad+i-10,"doom2f.wad",10)) + language=french; + else if (i>=7 && !strnicmp(iwad+i-7,"tnt.wad",7)) + gamemission = pack_tnt; + else if (i>=12 && !strnicmp(iwad+i-12,"plutonia.wad",12)) + gamemission = pack_plut; + break; + default: + gamemission = none; + break; + } + if (gamemode == indetermined) + //jff 9/3/98 use logical output routine + lprintf(LO_WARN,"Unknown Game Version, may not work\n"); + D_AddFile(iwad,source_iwad); + free(iwad); + } + else + I_Error("IdentifyVersion: IWAD not found\n"); +} + + + +// killough 5/3/98: old code removed +// +// Find a Response File +// + +#define MAXARGVS 100 + +static void FindResponseFile (void) +{ + int i; + + for (i = 1;i < myargc;i++) + if (myargv[i][0] == '@') + { + int size; + int index; + int indexinfile; + byte *file = NULL; + const char **moreargs = malloc(myargc * sizeof(const char*)); + const char **newargv; + // proff 04/05/2000: Added for searching responsefile + char fname[PATH_MAX+1]; + + strcpy(fname,&myargv[i][1]); + AddDefaultExtension(fname,".rsp"); + + // READ THE RESPONSE FILE INTO MEMORY + // proff 04/05/2000: changed for searching responsefile + // cph 2002/08/09 - use M_ReadFile for simplicity + size = M_ReadFile(fname, &file); + // proff 04/05/2000: Added for searching responsefile + if (size < 0) + { + strcat(strcpy(fname,I_DoomExeDir()),&myargv[i][1]); + AddDefaultExtension(fname,".rsp"); + size = M_ReadFile(fname, &file); + } + if (size < 0) + { + /* proff 04/05/2000: Changed from LO_FATAL + * proff 04/05/2000: Simply removed the exit(1); + * cph - made fatal, don't drop through and SEGV + */ + I_Error("No such response file: %s",fname); + } + //jff 9/3/98 use logical output routine + lprintf(LO_CONFIRM,"Found response file %s\n",fname); + // proff 04/05/2000: Added check for empty rsp file + if (size<=0) + { + int k; + lprintf(LO_ERROR,"\nResponse file empty!\n"); + + newargv = calloc(sizeof(char *),MAXARGVS); + newargv[0] = myargv[0]; + for (k = 1,index = 1;k < myargc;k++) + { + if (i!=k) + newargv[index++] = myargv[k]; + } + myargc = index; myargv = newargv; + return; + } + + // KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG + memcpy((void *)moreargs,&myargv[i+1],(index = myargc - i - 1) * sizeof(myargv[0])); + + { + const char *firstargv = myargv[0]; + newargv = calloc(sizeof(char *),MAXARGVS); + newargv[0] = firstargv; + } + + { + byte *infile = file; + indexinfile = 0; + indexinfile++; // SKIP PAST ARGV[0] (KEEP IT) + do { + while (size > 0 && isspace(*infile)) { infile++; size--; } + if (size > 0) { + char *s = malloc(size+1); + char *p = s; + int quoted = 0; + + while (size > 0) { + // Whitespace terminates the token unless quoted + if (!quoted && isspace(*infile)) break; + if (*infile == '\"') { + // Quotes are removed but remembered + infile++; size--; quoted ^= 1; + } else { + *p++ = *infile++; size--; + } + } + if (quoted) I_Error("Runaway quoted string in response file"); + + // Terminate string, realloc and add to argv + *p = 0; + newargv[indexinfile++] = realloc(s,strlen(s)+1); + } + } while(size > 0); + } + free(file); + + memcpy((void *)&newargv[indexinfile],moreargs,index*sizeof(moreargs[0])); + free((void *)moreargs); + + myargc = indexinfile+index; myargv = newargv; + + // DISPLAY ARGS + //jff 9/3/98 use logical output routine + lprintf(LO_CONFIRM,"%d command-line args:\n",myargc); + for (index=1;index 0) + { + tmyargv[tmyargc++] = strdup("-file"); // put the switch in + for (i=0;i 0) + { + tmyargv[tmyargc++] = strdup("-deh"); + for (i=0;i 0) + { + tmyargv[tmyargc++] = strdup("-playdemo"); + for (i=0;i 400) + scale = 400; + //jff 9/3/98 use logical output routine + lprintf (LO_CONFIRM,"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; + } + + modifiedgame = false; + + // get skill / episode / map from parms + + startskill = sk_none; // jff 3/24/98 was sk_medium, just note not picked + startepisode = 1; + startmap = 1; + autostart = false; + + if ((p = M_CheckParm ("-skill")) && p < myargc-1) + { + startskill = myargv[p+1][0]-'1'; + autostart = true; + } + + if ((p = M_CheckParm ("-episode")) && p < myargc-1) + { + startepisode = myargv[p+1][0]-'0'; + startmap = 1; + autostart = true; + } + + if ((p = M_CheckParm ("-timer")) && p < myargc-1 && deathmatch) + { + int time = atoi(myargv[p+1]); + //jff 9/3/98 use logical output routine + lprintf(LO_CONFIRM,"Levels will end after %d minute%s.\n", time, time>1 ? "s" : ""); + } + + if ((p = M_CheckParm ("-avg")) && p < myargc-1 && deathmatch) + //jff 9/3/98 use logical output routine + lprintf(LO_CONFIRM,"Austin Virtual Gaming: Levels will end after 20 minutes\n"); + + if ((p = M_CheckParm ("-warp")) || // killough 5/2/98 + (p = M_CheckParm ("-wart"))) + // Ty 08/29/98 - moved this check later so we can have -warp alone: && p < myargc-1) + { + startmap = 0; // Ty 08/29/98 - allow "-warp x" to go to first map in wad(s) + autostart = true; // Ty 08/29/98 - move outside the decision tree + if (gamemode == commercial) + { + if (p < myargc-1) + startmap = atoi(myargv[p+1]); // Ty 08/29/98 - add test if last parm + } + else // 1/25/98 killough: fix -warp xxx from crashing Doom 1 / UD + { + if (p < myargc-2) + { + startepisode = atoi(myargv[++p]); + startmap = atoi(myargv[p+1]); + } + } + } + // Ty 08/29/98 - later we'll check for startmap=0 and autostart=true + // as a special case that -warp * was used. Actually -warp with any + // non-numeric will do that but we'll only document "*" + + //jff 1/22/98 add command line parms to disable sound and music + { + int nosound = M_CheckParm("-nosound"); + nomusicparm = nosound || M_CheckParm("-nomusic"); + nosfxparm = nosound || M_CheckParm("-nosfx"); + } + //jff end of sound/music command line parms + + // killough 3/2/98: allow -nodraw -noblit generally + nodrawers = M_CheckParm ("-nodraw"); + noblit = M_CheckParm ("-noblit"); + + //proff 11/22/98: Added setting of viewangleoffset + p = M_CheckParm("-viewangle"); + if (p) + { + viewangleoffset = atoi(myargv[p+1]); + viewangleoffset = viewangleoffset<0 ? 0 : (viewangleoffset>7 ? 7 : viewangleoffset); + viewangleoffset = (8-viewangleoffset) * ANG45; + } + + // init subsystems + + G_ReloadDefaults(); // killough 3/4/98: set defaults just loaded. + // jff 3/24/98 this sets startskill if it was -1 + + // Video stuff + if ((p = M_CheckParm("-width"))) + if (myargv[p+1]) + desired_screenwidth = atoi(myargv[p+1]); + + if ((p = M_CheckParm("-height"))) + if (myargv[p+1]) + desired_screenheight = atoi(myargv[p+1]); + + if ((p = M_CheckParm("-fullscreen"))) + use_fullscreen = 1; + + if ((p = M_CheckParm("-nofullscreen"))) + use_fullscreen = 0; + + // e6y + // New command-line options for setting a window (-window) + // or fullscreen (-nowindow) mode temporarily which is not saved in cfg. + // It works like "-geom" switch + desired_fullscreen = use_fullscreen; + if ((p = M_CheckParm("-window"))) + desired_fullscreen = 0; + + if ((p = M_CheckParm("-nowindow"))) + desired_fullscreen = 1; + + { // -geometry handling, change screen size for this session only + // e6y: new code by me + int w, h; + + if (!(p = M_CheckParm("-geom"))) + p = M_CheckParm("-geometry"); + + if (!(p && (p+1= MAXLOADFILES) + ProcessDehFile(fpath, D_dehout(), 0); + else { + D_AddFile(fpath,source_auto_load); + } + modifiedgame = true; + free(fpath); + } + } + } + + // e6y: DEH files preloaded in wrong order + // http://sourceforge.net/tracker/index.php?func=detail&aid=1418158&group_id=148658&atid=772943 + // The dachaked stuff has been moved from above + + // ty 03/09/98 do dehacked stuff + // Note: do this before any other since it is expected by + // the deh patch author that this is actually part of the EXE itself + // Using -deh in BOOM, others use -dehacked. + // Ty 03/18/98 also allow .bex extension. .bex overrides if both exist. + + D_BuildBEXTables(); // haleyjd + + p = M_CheckParm ("-deh"); + if (p) + { + char file[PATH_MAX+1]; // cph - localised + // the parms after p are deh/bex file names, + // until end of parms or another - preceded parm + // Ty 04/11/98 - Allow multiple -deh files in a row + + while (++p != myargc && *myargv[p] != '-') + { + AddDefaultExtension(strcpy(file, myargv[p]), ".bex"); + if (access(file, F_OK)) // nope + { + AddDefaultExtension(strcpy(file, myargv[p]), ".deh"); + if (access(file, F_OK)) // still nope + I_Error("D_DoomMainSetup: Cannot find .deh or .bex file named %s",myargv[p]); + } + // during the beta we have debug output to dehout.txt + ProcessDehFile(file,D_dehout(),0); + } + } + // ty 03/09/98 end of do dehacked stuff + + // add any files specified on the command line with -file wadfile + // to the wad list + + // killough 1/31/98, 5/2/98: reload hack removed, -wart same as -warp now. + + if ((p = M_CheckParm ("-file"))) + { + // 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] != '-') + D_AddFile(myargv[p],source_pwad); + } + + if (!(p = M_CheckParm("-playdemo")) || p >= myargc-1) { /* killough */ + if ((p = M_CheckParm ("-fastdemo")) && p < myargc-1) /* killough */ + fastdemo = true; // run at fastest speed possible + else + p = M_CheckParm ("-timedemo"); + } + + if (p && p < myargc-1) + { + char file[PATH_MAX+1]; // cph - localised + strcpy(file,myargv[p+1]); + AddDefaultExtension(file,".lmp"); // killough + D_AddFile (file,source_lmp); + //jff 9/3/98 use logical output routine + lprintf(LO_CONFIRM,"Playing demo %s\n",file); + if ((p = M_CheckParm ("-ffmap")) && p < myargc-1) { + ffmap = atoi(myargv[p+1]); + } + + } + + // internal translucency set to config file value // phares + general_translucency = default_translucency; // phares + + // 1/18/98 killough: Z_Init() call moved to i_main.c + + // CPhipps - move up netgame init + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"D_InitNetGame: Checking for network game.\n"); + D_InitNetGame(); + + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"W_Init: Init WADfiles.\n"); + W_Init(); // CPhipps - handling of wadfiles init changed + + lprintf(LO_INFO,"\n"); // killough 3/6/98: add a newline, by popular demand :) + + // e6y + // option to disable automatic loading of dehacked-in-wad lump + if (!M_CheckParm ("-nodeh")) + if ((p = W_CheckNumForName("DEHACKED")) != -1) // cph - add dehacked-in-a-wad support + ProcessDehFile(NULL, D_dehout(), p); + + V_InitColorTranslation(); //jff 4/24/98 load color translation lumps + + // killough 2/22/98: copyright / "modified game" / SPA banners removed + + // Ty 04/08/98 - Add 5 lines of misc. data, only if nonblank + // The expectation is that these will be set in a .bex file + //jff 9/3/98 use logical output routine + if (*startup1) lprintf(LO_INFO,"%s",startup1); + if (*startup2) lprintf(LO_INFO,"%s",startup2); + if (*startup3) lprintf(LO_INFO,"%s",startup3); + if (*startup4) lprintf(LO_INFO,"%s",startup4); + if (*startup5) lprintf(LO_INFO,"%s",startup5); + // End new startup strings + + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"M_Init: Init miscellaneous info.\n"); + M_Init(); + +#ifdef HAVE_NET + // CPhipps - now wait for netgame start + D_CheckNetGame(); +#endif + + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"R_Init: Init DOOM refresh daemon - "); + R_Init(); + + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"\nP_Init: Init Playloop state.\n"); + P_Init(); + + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"I_Init: Setting up machine state.\n"); + I_Init(); + + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"S_Init: Setting up sound.\n"); + S_Init(snd_SfxVolume /* *8 */, snd_MusicVolume /* *8*/ ); + + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"HU_Init: Setting up heads up display.\n"); + HU_Init(); + + if (!(M_CheckParm("-nodraw") && M_CheckParm("-nosound"))) + I_InitGraphics(); + + //jff 9/3/98 use logical output routine + lprintf(LO_INFO,"ST_Init: Init status bar.\n"); + ST_Init(); + + idmusnum = -1; //jff 3/17/98 insure idmus number is blank + + // CPhipps - auto screenshots + if ((p = M_CheckParm("-autoshot")) && (p < myargc-2)) + if ((auto_shot_count = auto_shot_time = atoi(myargv[p+1]))) + auto_shot_fname = myargv[p+2]; + + // start the apropriate game based on parms + + // killough 12/98: + // Support -loadgame with -record and reimplement -recordfrom. + + if ((slot = M_CheckParm("-recordfrom")) && (p = slot+2) < myargc) + G_RecordDemo(myargv[p]); + else + { + slot = M_CheckParm("-loadgame"); + if ((p = M_CheckParm("-record")) && ++p < myargc) + { + autostart = true; + G_RecordDemo(myargv[p]); + } + } + + if ((p = M_CheckParm ("-checksum")) && ++p < myargc) + { + P_RecordChecksum (myargv[p]); + } + + if ((p = M_CheckParm ("-fastdemo")) && ++p < myargc) + { // killough + fastdemo = true; // run at fastest speed possible + timingdemo = true; // show stats after quit + G_DeferedPlayDemo(myargv[p]); + singledemo = true; // quit after one demo + } + else + if ((p = M_CheckParm("-timedemo")) && ++p < myargc) + { + singletics = true; + timingdemo = true; // show stats after quit + G_DeferedPlayDemo(myargv[p]); + singledemo = true; // quit after one demo + } + else + if ((p = M_CheckParm("-playdemo")) && ++p < myargc) + { + G_DeferedPlayDemo(myargv[p]); + singledemo = true; // quit after one demo + } + + if (slot && ++slot < myargc) + { + slot = atoi(myargv[slot]); // killough 3/16/98: add slot info + G_LoadGame(slot, true); // killough 5/15/98: add command flag // cph - no filename + } + else + if (!singledemo) { /* killough 12/98 */ + if (autostart || netgame) + { + G_InitNew(startskill, startepisode, startmap); + if (demorecording) + G_BeginRecording(); + } + else + D_StartTitle(); // start up intro loop + } +} + +// +// D_DoomMain +// + +void D_DoomMain(void) +{ + D_DoomMainSetup(); // CPhipps - setup out of main execution stack + + D_DoomLoop (); // never returns +} + +// +// GetFirstMap +// +// Ty 08/29/98 - determine first available map from the loaded wads and run it +// + +void GetFirstMap(int *ep, int *map) +{ + int i,j; // used to generate map name + boolean done = false; // Ty 09/13/98 - to exit inner loops + char test[6]; // MAPxx or ExMx plus terminator for testing + char name[6]; // MAPxx or ExMx plus terminator for display + boolean newlevel = false; // Ty 10/04/98 - to test for new level + int ix; // index for lookup + + strcpy(name,""); // initialize + if (*map == 0) // unknown so go search for first changed one + { + *ep = 1; + *map = 1; // default E1M1 or MAP01 + if (gamemode == commercial) + { + for (i=1;!done && i<33;i++) // Ty 09/13/98 - add use of !done + { + sprintf(test,"MAP%02d",i); + ix = W_CheckNumForName(test); + if (ix != -1) // Ty 10/04/98 avoid -1 subscript + { + if (lumpinfo[ix].source == source_pwad) + { + *map = i; + strcpy(name,test); // Ty 10/04/98 + done = true; // Ty 09/13/98 + newlevel = true; // Ty 10/04/98 + } + else + { + if (!*name) // found one, not pwad. First default. + strcpy(name,test); + } + } + } + } + else // one of the others + { + strcpy(name,"E1M1"); // Ty 10/04/98 - default for display + for (i=1;!done && i<5;i++) // Ty 09/13/98 - add use of !done + { + for (j=1;!done && j<10;j++) // Ty 09/13/98 - add use of !done + { + sprintf(test,"E%dM%d",i,j); + ix = W_CheckNumForName(test); + if (ix != -1) // Ty 10/04/98 avoid -1 subscript + { + if (lumpinfo[ix].source == source_pwad) + { + *ep = i; + *map = j; + strcpy(name,test); // Ty 10/04/98 + done = true; // Ty 09/13/98 + newlevel = true; // Ty 10/04/98 + } + else + { + if (!*name) // found one, not pwad. First default. + strcpy(name,test); + } + } + } + } + } + //jff 9/3/98 use logical output routine + lprintf(LO_CONFIRM,"Auto-warping to first %slevel: %s\n", + newlevel ? "new " : "", name); // Ty 10/04/98 - new level test + } +} diff --git a/src/d_main.h b/src/d_main.h new file mode 100644 index 0000000..ccd1910 --- /dev/null +++ b/src/d_main.h @@ -0,0 +1,82 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Main startup and splash screenstuff. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __D_MAIN__ +#define __D_MAIN__ + +#include "d_event.h" +#include "w_wad.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +/* CPhipps - removed wadfiles[] stuff to w_wad.h */ + +extern char basesavegame[]; // killough 2/16/98: savegame path + +//jff 1/24/98 make command line copies of play modes available +extern boolean clnomonsters; // checkparm of -nomonsters +extern boolean clrespawnparm; // checkparm of -respawn +extern boolean clfastparm; // checkparm of -fast +//jff end of external declaration of command line playmode + +extern boolean nosfxparm; +extern boolean nomusicparm; +extern int ffmap; + +// Called by IO functions when input is detected. +void D_PostEvent(event_t* ev); + +// Demo stuff +extern boolean advancedemo; +void D_AdvanceDemo(void); +void D_DoAdvanceDemo (void); + +// +// BASE LEVEL +// + +void D_Display(void); +void D_PageTicker(void); +void D_StartTitle(void); +void D_DoomMain(void); +void D_AddFile (const char *file, wad_source_t source); + +/* cph - MBF-like wad/deh/bex autoload code */ +/* proff 2001/7/1 - added prboom.wad as last entry so it's always loaded and + doesn't overlap with the cfg settings */ +#define MAXLOADFILES 3 +extern const char *wad_files[MAXLOADFILES], *deh_files[MAXLOADFILES]; + +#endif diff --git a/src/d_net.h b/src/d_net.h new file mode 100644 index 0000000..fcdeb6c --- /dev/null +++ b/src/d_net.h @@ -0,0 +1,214 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * 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 + + +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; + +// +// Startup packet difference +// SG: 4/12/98 +// Added so we can send more startup data to synch things like +// bobbing, recoil, etc. +// this is just mapped over the ticcmd_t array when setup packet is sent +// +// Note: the original code takes care of startskill, deathmatch, nomonsters +// respawn, startepisode, startmap +// Note: for phase 1 we need to add monsters_remember, variable_friction, +// weapon_recoil, allow_pushers, over_under, player_bobbing, +// fastparm, demo_insurance, and the rngseed +//Stick all options into bytes so we don't need to mess with bitfields +//WARNING: make sure this doesn't exceed the size of the ticcmds area! +//sizeof(ticcmd_t)*BACKUPTICS +//This is the current length of our extra stuff +// +//killough 5/2/98: this should all be replaced by calls to G_WriteOptions() +//and G_ReadOptions(), which were specifically designed to set up packets. +//By creating a separate struct and functions to read/write the options, +//you now have two functions and data to maintain instead of just one. +//If the array in g_game.c which G_WriteOptions()/G_ReadOptions() operates +//on, is too large (more than sizeof(ticcmd_t)*BACKUPTICS), it can +//either be shortened, or the net code needs to divide it up +//automatically into packets. The STARTUPLEN below is non-portable. +//There's a portable way to do it without having to know the sizes. + +#define STARTUPLEN 12 +typedef struct +{ + byte monsters_remember; + byte variable_friction; + byte weapon_recoil; + byte allow_pushers; + byte over_under; + byte player_bobbing; + byte fastparm; + byte demo_insurance; + unsigned long rngseed; + char filler[sizeof(ticcmd_t)*BACKUPTICS-STARTUPLEN]; +} startup_t; + +typedef enum { + // Leave space, so low values corresponding to normal netgame setup packets can be ignored + nm_plcolour = 3, + nm_savegamename = 4, +} netmisctype_t; + +typedef struct +{ + netmisctype_t type; + size_t len; + byte value[sizeof(ticcmd_t)*BACKUPTICS - sizeof(netmisctype_t) - sizeof(size_t)]; +} netmisc_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. +#ifdef HAVE_NET +void NetUpdate (void); +#else +void D_BuildNewTiccmds(void); +#endif + +//? how many ticks to run? +void TryRunTics (void); + +// CPhipps - move to header file +void D_InitNetGame (void); // This does the setup +void D_CheckNetGame(void); // This waits for game start + +// CPhipps - misc info broadcast +void D_NetSendMisc(netmisctype_t type, size_t len, void* data); + +// CPhipps - ask server for a wad file we need +boolean D_NetGetWad(const char* name); + +// Netgame stuff (buffers and pointers, i.e. indices). +extern doomcom_t *doomcom; +extern doomdata_t *netbuffer; // This points inside doomcom. + +#endif diff --git a/src/d_player.h b/src/d_player.h new file mode 100644 index 0000000..a45abe8 --- /dev/null +++ b/src/d_player.h @@ -0,0 +1,234 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Player state structure. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __D_PLAYER__ +#define __D_PLAYER__ + + +// The player data structure depends on a number +// of other structs: items (internal inventory), +// animation states (closely tied to the sprites +// used to represent them, unfortunately). +#include "d_items.h" +#include "p_pspr.h" + +// In addition, the player is just a special +// case of the generic moving object/actor. +#include "p_mobj.h" + +// Finally, for odd reasons, the player input +// is buffered within the player data struct, +// as commands per game tick. +#include "d_ticcmd.h" + +#ifdef __GNUG__ +#pragma interface +#endif + + +// +// Player states. +// +typedef enum +{ + // Playing or camping. + PST_LIVE, + // Dead on the ground, view follows killer. + PST_DEAD, + // Ready to restart/respawn??? + PST_REBORN + +} playerstate_t; + + +// +// Player internal flags, for cheats and debug. +// +typedef enum +{ + // No clipping, walk through barriers. + CF_NOCLIP = 1, + // No damage, no health loss. + CF_GODMODE = 2, + // Not really a cheat, just a debug aid. + CF_NOMOMENTUM = 4 + +} cheat_t; + + +// +// Extended player object info: player_t +// +typedef struct player_s +{ + mobj_t* mo; + playerstate_t playerstate; + ticcmd_t cmd; + + // Determine POV, + // including viewpoint bobbing during movement. + // Focal origin above r.z + fixed_t viewz; + // Base height above floor for viewz. + fixed_t viewheight; + // Bob/squat speed. + fixed_t deltaviewheight; + // bounded/scaled total momentum. + fixed_t bob; + + /* killough 10/98: used for realistic bobbing (i.e. not simply overall speed) + * mo->momx and mo->momy represent true momenta experienced by player. + * This only represents the thrust that the player applies himself. + * This avoids anomolies with such things as Boom ice and conveyors. + */ + fixed_t momx, momy; // killough 10/98 + + // This is only used between levels, + // mo->health is used during levels. + int health; + int armorpoints; + // Armor type is 0-2. + int armortype; + + // Power ups. invinc and invis are tic counters. + int powers[NUMPOWERS]; + boolean cards[NUMCARDS]; + boolean backpack; + + // Frags, kills of other players. + int frags[MAXPLAYERS]; + weapontype_t readyweapon; + + // Is wp_nochange if not changing. + weapontype_t pendingweapon; + + boolean weaponowned[NUMWEAPONS]; + int ammo[NUMAMMO]; + int maxammo[NUMAMMO]; + + // True if button down last tic. + int attackdown; + int usedown; + + // Bit flags, for cheats and debug. + // See cheat_t, above. + int cheats; + + // Refired shots are less accurate. + int refire; + + // For intermission stats. + int killcount; + int itemcount; + int secretcount; + + // Hint messages. // CPhipps - const + const char* message; + + // For screen flashing (red or bright). + int damagecount; + int bonuscount; + + // Who did damage (NULL for floors/ceilings). + mobj_t* attacker; + + // So gun flashes light up areas. + int extralight; + + // Current PLAYPAL, ??? + // can be set to REDCOLORMAP for pain, etc. + int fixedcolormap; + + // Player skin colorshift, + // 0-3 for which color to draw player. + int colormap; + + // Overlay view sprites (gun, etc). + pspdef_t psprites[NUMPSPRITES]; + + // True if secret level has been done. + boolean didsecret; + +} player_t; + + +// +// INTERMISSION +// Structure passed e.g. to WI_Start(wb) +// +typedef struct +{ + boolean in; // whether the player is in game + + // Player stats, kills, collected items etc. + int skills; + int sitems; + int ssecret; + int stime; + int frags[4]; + int score; // current score on entry, modified on return + +} wbplayerstruct_t; + +typedef struct +{ + int epsd; // episode # (0-2) + + // if true, splash the secret level + boolean didsecret; + + // previous and next levels, origin 0 + int last; + int next; + + int maxkills; + int maxitems; + int maxsecret; + int maxfrags; + + // the par time + int partime; + + // index of this player in game + int pnum; + + wbplayerstruct_t plyr[MAXPLAYERS]; + + // CPhipps - total game time for completed levels so far + int totaltimes; + +} wbstartstruct_t; + + +#endif diff --git a/src/d_think.h b/src/d_think.h new file mode 100644 index 0000000..63e6626 --- /dev/null +++ b/src/d_think.h @@ -0,0 +1,94 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * 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 + +/* + * Experimental stuff. + * To compile this as "ANSI C with classes" + * we will need to handle the various + * action functions cleanly. + */ +// killough 11/98: convert back to C instead of C++ +typedef void (*actionf_t)(); +//typedef void (*actionf_v)(); +//typedef void (*actionf_p1)( void* ); +//typedef void (*actionf_p2)( void*, void* ); + +/* Note: In d_deh.c you will find references to these + * wherever code pointers and function handlers exist + */ +/* +typedef union +{ + actionf_p1 acp1; + actionf_v acv; + actionf_p2 acp2; + +} actionf_t; +*/ + +/* Historically, "think_t" is yet another + * function pointer to a routine to handle + * an actor. + */ +typedef actionf_t think_t; + + +/* Doubly linked list of actors. */ +typedef struct thinker_s +{ + struct thinker_s* prev; + struct thinker_s* next; + think_t function; + + /* killough 8/29/98: we maintain thinkers in several equivalence classes, + * according to various criteria, so as to allow quicker searches. + */ + + struct thinker_s *cnext, *cprev; /* Next, previous thinkers in same class */ + + /* killough 11/98: count of how many other objects reference + * this one using pointers. Used for garbage collection. + */ + unsigned references; +} thinker_t; + +#endif diff --git a/src/d_ticcmd.h b/src/d_ticcmd.h new file mode 100644 index 0000000..4469dfb --- /dev/null +++ b/src/d_ticcmd.h @@ -0,0 +1,59 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * System specific interface stuff. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __D_TICCMD__ +#define __D_TICCMD__ + +#include "doomtype.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +/* The data sampled per tick (single player) + * and transmitted to other peers (multiplayer). + * Mainly movements/button commands per game tick, + * plus a checksum for internal state consistency. + * CPhipps - explicitely signed the elements, since they have to be signed to work right + */ +typedef struct +{ + signed char forwardmove; /* *2048 for move */ + signed char sidemove; /* *2048 for move */ + signed short angleturn; /* <<16 for angle delta */ + short consistancy; /* checks for net game */ + byte chatchar; + byte buttons; +} ticcmd_t; + +#endif diff --git a/src/doomdata.h b/src/doomdata.h new file mode 100644 index 0000000..20eb99a --- /dev/null +++ b/src/doomdata.h @@ -0,0 +1,204 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * 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__ + +// The most basic types we use, portability. +#include "config.h" +#include "doomtype.h" + +// +// Map level types. +// The following data structures define the persistent format +// used in the lumps of the WAD files. +// + +// Lump order in a map WAD: each map needs a couple of lumps +// to provide a complete scene geometry description. +enum { + ML_LABEL, // A separator, name, ExMx or MAPxx + ML_THINGS, // Monsters, items.. + ML_LINEDEFS, // LineDefs, from editing + ML_SIDEDEFS, // SideDefs, from editing + ML_VERTEXES, // Vertices, edited and BSP splits generated + ML_SEGS, // LineSegs, from LineDefs split by BSP + ML_SSECTORS, // SubSectors, list of LineSegs + ML_NODES, // BSP nodes + ML_SECTORS, // Sectors, from editing + ML_REJECT, // LUT, sector-sector visibility + ML_BLOCKMAP // LUT, motion clipping, walls/grid element +}; + +#ifdef _MSC_VER // proff: This is the same as __attribute__ ((packed)) in GNUC +#pragma pack(push) +#pragma pack(1) +#endif //_MSC_VER + +// A single Vertex. +typedef struct { + short x,y; +} PACKEDATTR mapvertex_t; + +// A SideDef, defining the visual appearance of a wall, +// by setting textures and offsets. +typedef struct { + short textureoffset; + short rowoffset; + char toptexture[8]; + char bottomtexture[8]; + char midtexture[8]; + short sector; // Front sector, towards viewer. +} PACKEDATTR mapsidedef_t; + +// A LineDef, as used for editing, and as input to the BSP builder. + +typedef struct { + unsigned short v1; + unsigned short v2; + unsigned short flags; + short special; + short tag; + // proff 07/23/2006 - support more than 32768 sidedefs + // use the unsigned value and special case the -1 + // sidenum[1] will be -1 (NO_INDEX) if one sided + unsigned short sidenum[2]; +} PACKEDATTR maplinedef_t; + +#define NO_INDEX ((unsigned short)-1) + +// +// LineDef attributes. +// + +// Solid, is an obstacle. +#define ML_BLOCKING 1 + +// Blocks monsters only. +#define ML_BLOCKMONSTERS 2 + +// Backside will not be drawn if not two sided. +#define ML_TWOSIDED 4 + +// If a texture is pegged, the texture will have +// the end exposed to air held constant at the +// top or bottom of the texture (stairs or pulled +// down things) and will move with a height change +// of one of the neighbor sectors. +// Unpegged textures always have the first row of +// the texture at the top pixel of the line for both +// top and bottom textures (use next to windows). + +// upper texture unpegged +#define ML_DONTPEGTOP 8 + +// lower texture unpegged +#define ML_DONTPEGBOTTOM 16 + +// In AutoMap: don't map as two sided: IT'S A SECRET! +#define ML_SECRET 32 + +// Sound rendering: don't let sound cross two of these. +#define ML_SOUNDBLOCK 64 + +// Don't draw on the automap at all. +#define ML_DONTDRAW 128 + +// Set if already seen, thus drawn in automap. +#define ML_MAPPED 256 + +//jff 3/21/98 Set if line absorbs use by player +//allow multiple push/switch triggers to be used on one push +#define ML_PASSUSE 512 + +// Sector definition, from editing. +typedef struct { + short floorheight; + short ceilingheight; + char floorpic[8]; + char ceilingpic[8]; + short lightlevel; + short special; + short tag; +} PACKEDATTR mapsector_t; + +// SubSector, as generated by BSP. +typedef struct { + unsigned short numsegs; + unsigned short firstseg; // Index of first one; segs are stored sequentially. +} PACKEDATTR mapsubsector_t; + +// LineSeg, generated by splitting LineDefs +// using partition lines selected by BSP builder. +typedef struct { + unsigned short v1; + unsigned short v2; + short angle; + unsigned short linedef; + short side; + short offset; +} PACKEDATTR mapseg_t; + +// BSP node structure. + +// Indicate a leaf. +#define NF_SUBSECTOR 0x8000 + +typedef struct { + short x; // Partition line from (x,y) to x+dx,y+dy) + short y; + short dx; + short dy; + // Bounding box for each child, clip against view frustum. + short bbox[2][4]; + // If NF_SUBSECTOR its a subsector, else it's a node of another subtree. + unsigned short children[2]; +} PACKEDATTR mapnode_t; + +// Thing definition, position, orientation and type, +// plus skill/visibility flags and attributes. +typedef struct { + short x; + short y; + short angle; + short type; + short options; +} PACKEDATTR mapthing_t; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif //_MSC_VER + +#endif // __DOOMDATA__ diff --git a/src/doomdef.c b/src/doomdef.c new file mode 100644 index 0000000..c99c113 --- /dev/null +++ b/src/doomdef.c @@ -0,0 +1,48 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * DoomDef - basic defines for DOOM, e.g. Version, game mode + * and skill level, and display parameters. + * + *----------------------------------------------------------------------------- + */ + +#ifdef __GNUG__ +#pragma implementation "doomdef.h" +#endif + +#include "doomdef.h" + +// Location for any defines turned variables. +// None. + +// proff 08/17/98: Changed for high-res +int SCREENWIDTH=320; +int SCREENHEIGHT=200; +int SCREENPITCH=320; diff --git a/src/doomdef.h b/src/doomdef.h new file mode 100644 index 0000000..140db82 --- /dev/null +++ b/src/doomdef.h @@ -0,0 +1,330 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Internally used data structures for virtually everything, + * key definitions, lots of other stuff. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __DOOMDEF__ +#define __DOOMDEF__ + +/* use config.h if autoconf made one -- josh */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// killough 4/25/98: Make gcc extensions mean nothing on other compilers +#ifndef __GNUC__ +#define __attribute__(x) +#endif + +// This must come first, since it redefines malloc(), free(), etc. -- killough: +#include "z_zone.h" + +#include +#include +#include +#include +#include + +// this should go here, not in makefile/configure.ac -- josh +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#include "m_swap.h" +#include "version.h" + +// 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; + +// +// For resize of screen, at start of game. +// + +#define BASE_WIDTH 320 + +// 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 INV_ASPECT_RATIO 0.625 /* 0.75, ideally */ + +// killough 2/8/98: MAX versions for maximum screen sizes +// allows us to avoid the overhead of dynamic allocation +// when multiple screen sizes are supported + +// proff 08/17/98: Changed for high-res +#define MAX_SCREENWIDTH 2048 +#define MAX_SCREENHEIGHT 1536 + +// SCREENWIDTH and SCREENHEIGHT define the visible size +extern int SCREENWIDTH; +extern int SCREENHEIGHT; +// SCREENPITCH is the size of one line in the buffer and +// can be bigger than the SCREENWIDTH depending on the size +// of one pixel (8, 16 or 32 bit) and the padding at the +// end of the line caused by hardware considerations +extern int SCREENPITCH; + +// The maximum number of players, multiplayer/networking. +#define MAXPLAYERS 4 + +// phares 5/14/98: +// DOOM Editor Numbers (aka doomednum in mobj_t) + +#define DEN_PLAYER5 4001 +#define DEN_PLAYER6 4002 +#define DEN_PLAYER7 4003 +#define DEN_PLAYER8 4004 + +// State updates, number of tics / second. +#define TICRATE 35 + +// The current state of the game: whether we are playing, gazing +// at the intermission screen, the game final animation, or a demo. + +typedef enum { + GS_LEVEL, + GS_INTERMISSION, + GS_FINALE, + GS_DEMOSCREEN +} gamestate_t; + +// +// Difficulty/skill settings/filters. +// +// These are Thing flags + +// Skill flags. +#define MTF_EASY 1 +#define MTF_NORMAL 2 +#define MTF_HARD 4 +// Deaf monsters/do not react to sound. +#define MTF_AMBUSH 8 + +/* killough 11/98 */ +#define MTF_NOTSINGLE 16 +#define MTF_NOTDM 32 +#define MTF_NOTCOOP 64 +#define MTF_FRIEND 128 +#define MTF_RESERVED 256 + +typedef enum { + sk_none=-1, //jff 3/24/98 create unpicked skill setting + sk_baby=0, + sk_easy, + sk_medium, + sk_hard, + sk_nightmare +} skill_t; + +// +// Key cards. +// + +typedef enum { + it_bluecard, + it_yellowcard, + it_redcard, + it_blueskull, + it_yellowskull, + it_redskull, + NUMCARDS +} card_t; + +// The defined weapons, including a marker +// indicating user has not changed weapon. +typedef enum { + wp_fist, + wp_pistol, + wp_shotgun, + wp_chaingun, + wp_missile, + wp_plasma, + wp_bfg, + wp_chainsaw, + wp_supershotgun, + + NUMWEAPONS, + wp_nochange // No pending weapon change. +} weapontype_t; + +// Ammunition types defined. +typedef enum { + am_clip, // Pistol / chaingun ammo. + am_shell, // Shotgun / double barreled shotgun. + am_cell, // Plasma rifle, BFG. + am_misl, // Missile launcher. + NUMAMMO, + am_noammo // Unlimited for chainsaw / fist. +} ammotype_t; + +// Power up artifacts. +typedef enum { + pw_invulnerability, + pw_strength, + pw_invisibility, + pw_ironfeet, + pw_allmap, + pw_infrared, + NUMPOWERS +} powertype_t; + +// Power up durations (how many seconds till expiration). +typedef enum { + INVULNTICS = (30*TICRATE), + INVISTICS = (60*TICRATE), + INFRATICS = (120*TICRATE), + IRONTICS = (60*TICRATE) +} powerduration_t; + +// DOOM keyboard definition. +// This is the stuff configured by Setup.Exe. +// Most key data are simple ascii (uppercased). + +#define KEYD_RIGHTARROW 0xae +#define KEYD_LEFTARROW 0xac +#define KEYD_UPARROW 0xad +#define KEYD_DOWNARROW 0xaf +#define KEYD_ESCAPE 27 +#define KEYD_ENTER 13 +#define KEYD_TAB 9 +#define KEYD_F1 (0x80+0x3b) +#define KEYD_F2 (0x80+0x3c) +#define KEYD_F3 (0x80+0x3d) +#define KEYD_F4 (0x80+0x3e) +#define KEYD_F5 (0x80+0x3f) +#define KEYD_F6 (0x80+0x40) +#define KEYD_F7 (0x80+0x41) +#define KEYD_F8 (0x80+0x42) +#define KEYD_F9 (0x80+0x43) +#define KEYD_F10 (0x80+0x44) +#define KEYD_F11 (0x80+0x57) +#define KEYD_F12 (0x80+0x58) +#define KEYD_BACKSPACE 127 +#define KEYD_PAUSE 0xff +#define KEYD_EQUALS 0x3d +#define KEYD_MINUS 0x2d +#define KEYD_RSHIFT (0x80+0x36) +#define KEYD_RCTRL (0x80+0x1d) +#define KEYD_RALT (0x80+0x38) +#define KEYD_LALT KEYD_RALT +#define KEYD_CAPSLOCK 0xba // phares + +// phares 3/2/98: +#define KEYD_INSERT 0xd2 +#define KEYD_HOME 0xc7 +#define KEYD_PAGEUP 0xc9 +#define KEYD_PAGEDOWN 0xd1 +#define KEYD_DEL 0xc8 +#define KEYD_END 0xcf +#define KEYD_SCROLLLOCK 0xc6 +#define KEYD_SPACEBAR 0x20 +// phares 3/2/98 + +#define KEYD_NUMLOCK 0xC5 // killough 3/6/98 + +// cph - Add the numeric keypad keys, as suggested by krose 4/22/99: +// The way numbers are assigned to keys is a mess, but it's too late to +// change that easily. At least these additions are don neatly. +// Codes 0x100-0x200 are reserved for number pad + +#define KEYD_KEYPAD0 (0x100 + '0') +#define KEYD_KEYPAD1 (0x100 + '1') +#define KEYD_KEYPAD2 (0x100 + '2') +#define KEYD_KEYPAD3 (0x100 + '3') +#define KEYD_KEYPAD4 (0x100 + '4') +#define KEYD_KEYPAD5 (0x100 + '5') +#define KEYD_KEYPAD6 (0x100 + '6') +#define KEYD_KEYPAD7 (0x100 + '7') +#define KEYD_KEYPAD8 (0x100 + '8') +#define KEYD_KEYPAD9 (0x100 + '9') +#define KEYD_KEYPADENTER (0x100 + KEYD_ENTER) +#define KEYD_KEYPADDIVIDE (0x100 + '/') +#define KEYD_KEYPADMULTIPLY (0x100 + '*') +#define KEYD_KEYPADMINUS (0x100 + '-') +#define KEYD_KEYPADPLUS (0x100 + '+') +#define KEYD_KEYPADPERIOD (0x100 + '.') + +// phares 4/19/98: +// Defines Setup Screen groups that config variables appear in. +// Used when resetting the defaults for every item in a Setup group. + +typedef enum { + ss_none, + ss_keys, + ss_weap, + ss_stat, + ss_auto, + ss_enem, + ss_mess, + ss_chat, + ss_gen, /* killough 10/98 */ + ss_comp, /* killough 10/98 */ + ss_max +} ss_types; + +// phares 3/20/98: +// +// Player friction is variable, based on controlling +// linedefs. More friction can create mud, sludge, +// magnetized floors, etc. Less friction can create ice. + +#define MORE_FRICTION_MOMENTUM 15000 // mud factor based on momentum +#define ORIG_FRICTION 0xE800 // original value +#define ORIG_FRICTION_FACTOR 2048 // original value + +#endif // __DOOMDEF__ diff --git a/src/doomstat.c b/src/doomstat.c new file mode 100644 index 0000000..56506ad --- /dev/null +++ b/src/doomstat.c @@ -0,0 +1,108 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Put all global state variables here. + * + *----------------------------------------------------------------------------- + */ + +#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; + +// Set if homebrew PWAD stuff has been added. +boolean modifiedgame; + +//----------------------------------------------------------------------------- + +// CPhipps - compatibility vars +complevel_t compatibility_level, default_compatibility_level; + +int comp[COMP_TOTAL], default_comp[COMP_TOTAL]; // killough 10/98 + +// v1.1-like pitched sounds +int pitched_sounds; // killough + +int default_translucency; // config file says // phares +boolean general_translucency; // true if translucency is ok // phares + +int demo_insurance, default_demo_insurance; // killough 1/16/98 + +int allow_pushers = 1; // MT_PUSH Things // phares 3/10/98 +int default_allow_pushers; // killough 3/1/98: make local to each game + +int variable_friction = 1; // ice & mud // phares 3/10/98 +int default_variable_friction; // killough 3/1/98: make local to each game + +int weapon_recoil; // weapon recoil // phares +int default_weapon_recoil; // killough 3/1/98: make local to each game + +int player_bobbing; // whether player bobs or not // phares 2/25/98 +int default_player_bobbing; // killough 3/1/98: make local to each game + +int monsters_remember; // killough 3/1/98 +int default_monsters_remember; + +int monster_infighting=1; // killough 7/19/98: monster<=>monster attacks +int default_monster_infighting=1; + +int monster_friction=1; // killough 10/98: monsters affected by friction +int default_monster_friction=1; + +#ifdef DOGS +int dogs, default_dogs; // killough 7/19/98: Marine's best friend :) +int dog_jumping, default_dog_jumping; // killough 10/98 +#endif + +// killough 8/8/98: distance friends tend to move towards players +int distfriend = 128, default_distfriend = 128; + +// killough 9/8/98: whether monsters are allowed to strafe or retreat +int monster_backing, default_monster_backing; + +// killough 9/9/98: whether monsters are able to avoid hazards (e.g. crushers) +int monster_avoid_hazards, default_monster_avoid_hazards; + +// killough 9/9/98: whether monsters help friends +int help_friends, default_help_friends; + +int flashing_hom; // killough 10/98 + +int doom_weapon_toggles; // killough 10/98 + +int monkeys, default_monkeys; + diff --git a/src/doomstat.h b/src/doomstat.h new file mode 100644 index 0000000..88f7b8d --- /dev/null +++ b/src/doomstat.h @@ -0,0 +1,332 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2006 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * All the global variables that store the internal state. + * Theoretically speaking, the internal state of the engine + * should be found by looking at the variables collected + * here, and every relevant module will have to include + * this header file. + * In practice, things are a bit messy. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __D_STATE__ +#define __D_STATE__ + +// We need the playr data structure as well. +#include "d_player.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +// ------------------------ +// Command line parameters. +// + +extern boolean nomonsters; // checkparm of -nomonsters +extern boolean respawnparm; // checkparm of -respawn +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; + +// Set if homebrew PWAD stuff has been added. +extern boolean modifiedgame; + +// CPhipps - new compatibility handling +extern complevel_t compatibility_level, default_compatibility_level; + +// CPhipps - old compatibility testing flags aliased to new handling +#define compatibility (compatibility_level<=boom_compatibility_compatibility) +#define demo_compatibility (compatibility_level < boom_compatibility_compatibility) +#define mbf_features (compatibility_level>=mbf_compatibility) + +// v1.1-like pitched sounds +extern int pitched_sounds; // killough + +extern int default_translucency; // config file says // phares +extern boolean general_translucency; // true if translucency is ok // phares + +extern int demo_insurance, default_demo_insurance; // killough 4/5/98 + +// ------------------------------------------- +// killough 10/98: compatibility vector + +enum { + comp_telefrag, + comp_dropoff, + comp_vile, + comp_pain, + comp_skull, + comp_blazing, + comp_doorlight, + comp_model, + comp_god, + comp_falloff, + comp_floors, + comp_skymap, + comp_pursuit, + comp_doorstuck, + comp_staylift, + comp_zombie, + comp_stairs, + comp_infcheat, + comp_zerotags, + comp_moveblock, + comp_respawn, /* cph - this is the inverse of comp_respawnfix from eternity */ + comp_sound, + comp_666, + comp_soul, + comp_maskedanim, + COMP_NUM, /* cph - should be last in sequence */ + COMP_TOTAL=32 // Some extra room for additional variables +}; + +extern int comp[COMP_TOTAL], default_comp[COMP_TOTAL]; + +// ------------------------------------------- +// Language. +extern Language_t language; + +// ------------------------------------------- +// Selected skill type, map etc. +// + +// Defaults for menu, methinks. +extern skill_t startskill; +extern int startepisode; +extern int startmap; + +extern boolean autostart; + +// Selected by user. +extern skill_t gameskill; +extern int gameepisode; +extern int gamemap; + +// 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; + +// ------------------------------------------ +// 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 + +// CPhipps - screen parameters +extern unsigned int desired_screenwidth, desired_screenheight; + +// ------------------------- +// Status flags for refresh. +// + +enum automapmode_e { + am_active = 1, // currently shown + am_overlay= 2, // covers the screen, i.e. not overlay mode + am_rotate = 4, // rotates to the player facing direction + am_follow = 8, // keep the player centred + am_grid =16, // show grid +}; +extern enum automapmode_e automapmode; // Mode that the automap is in + +extern boolean menuactive; // Menu overlayed? +extern boolean paused; // Game Pause? +extern boolean nodrawers; +extern boolean noblit; + +// This one is related to the 3-screen display mode. +// ANG90 = left side, ANG270 = right +extern int viewangleoffset; + +// Player taking events, and displaying. +extern int consoleplayer; +extern int displayplayer; + +// ------------------------------------- +// Scores, rating. +// Statistics on a given map, for intermission. +// +extern int totalkills, totallive; +extern int totalitems; +extern int totalsecret; + +// Timer, for scores. +extern int basetic; /* killough 9/29/98: levelstarttic, adjusted */ +extern int leveltime; // tics in game play for par + +// -------------------------------------- +// DEMO playback/recording related stuff. + +extern boolean usergame; +extern boolean demoplayback; +extern boolean demorecording; +extern int demover; + +// Quit after playing a demo from cmdline. +extern boolean singledemo; +// Print timing information after quitting. killough +extern boolean timingdemo; +// Run tick clock at fastest speed possible while playing demo. killough +extern boolean fastdemo; + +extern gamestate_t gamestate; + +//----------------------------- +// Internal parameters, fixed. +// These are set by the engine, and not changed +// according to user inputs. Partly load from +// WAD, partly set at startup time. + +extern int gametic; + + +// Bookkeeping on players - state. +extern player_t players[MAXPLAYERS]; + +// Alive? Disconnected? +extern boolean playeringame[MAXPLAYERS]; +extern boolean realplayeringame[MAXPLAYERS]; + +extern mapthing_t *deathmatchstarts; // killough +extern size_t num_deathmatchstarts; // killough + +extern mapthing_t *deathmatch_p; + +// Player spawn spots. +extern mapthing_t playerstarts[]; + +// Intermission stats. +// Parameters for world map / intermission. +extern wbstartstruct_t wminfo; + +//----------------------------------------- +// Internal parameters, used for engine. +// + +// File handling stuff. +extern FILE *debugfile; + +// if true, load all graphics at level load +extern boolean precache; + +// wipegamestate can be set to -1 +// to force a wipe on the next draw +extern gamestate_t wipegamestate; + +extern int mouseSensitivity_horiz; // killough +extern int mouseSensitivity_vert; + +// debug flag to cancel adaptiveness +extern boolean singletics; + +extern int bodyqueslot; + +// Needed to store the number of the dummy sky flat. +// Used for rendering, as well as tracking projectiles etc. + +extern int skyflatnum; + +extern int maketic; + +// Networking and tick handling related. +#define BACKUPTICS 12 + +extern ticcmd_t netcmds[][BACKUPTICS]; +extern int ticdup; + +//----------------------------------------------------------------------------- + +extern int allow_pushers; // MT_PUSH Things // phares 3/10/98 +extern int default_allow_pushers; + +extern int variable_friction; // ice & mud // phares 3/10/98 +extern int default_variable_friction; + +extern int monsters_remember; // killough 3/1/98 +extern int default_monsters_remember; + +extern int weapon_recoil; // weapon recoil // phares +extern int default_weapon_recoil; + +extern int player_bobbing; // whether player bobs or not // phares 2/25/98 +extern int default_player_bobbing; // killough 3/1/98: make local to each game + +#ifdef DOGS +extern int dogs, default_dogs; // killough 7/19/98: Marine's best friend :) +extern int dog_jumping, default_dog_jumping; // killough 10/98 +#endif + +/* killough 8/8/98: distance friendly monsters tend to stay from player */ +extern int distfriend, default_distfriend; + +/* killough 9/8/98: whether monsters are allowed to strafe or retreat */ +extern int monster_backing, default_monster_backing; + +/* killough 9/9/98: whether monsters intelligently avoid hazards */ +extern int monster_avoid_hazards, default_monster_avoid_hazards; + +/* killough 10/98: whether monsters are affected by friction */ +extern int monster_friction, default_monster_friction; + +/* killough 9/9/98: whether monsters help friends */ +extern int help_friends, default_help_friends; + +extern int flashing_hom; // killough 10/98 + +extern int doom_weapon_toggles; // killough 10/98 + +/* killough 7/19/98: whether monsters should fight against each other */ +extern int monster_infighting, default_monster_infighting; + +extern int monkeys, default_monkeys; + +extern int HelperThing; // type of thing to use for helper + +#endif diff --git a/src/doomtype.h b/src/doomtype.h new file mode 100644 index 0000000..bfc2f0a --- /dev/null +++ b/src/doomtype.h @@ -0,0 +1,128 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2006 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Simple basic typedefs, isolated here to make it easier + * separating modules. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __DOOMTYPE__ +#define __DOOMTYPE__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef __BYTEBOOL__ +#define __BYTEBOOL__ +/* Fixed to use builtin bool type with C++. */ +#ifdef __cplusplus +typedef bool boolean; +#else +typedef enum {false, true} boolean; +#endif +typedef unsigned char byte; +#endif + +//e6y +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + +/* cph - Wrapper for the long long type, as Win32 used a different name. + * Except I don't know what to test as it's compiler specific + * Proff - I fixed it */ +#ifndef _MSC_VER +typedef signed long long int_64_t; +typedef unsigned long long uint_64_t; +// define compiled-specific long-long contstant notation here +#define LONGLONG(num) (uint_64_t)num ## ll +#else +typedef __int64 int_64_t; +typedef unsigned __int64 uint_64_t; +// define compiled-specific long-long contstant notation here +#define LONGLONG(num) (uint_64_t)num +#undef PATH_MAX +#define PATH_MAX 1024 +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define S_ISDIR(x) (((sbuf.st_mode & S_IFDIR)==S_IFDIR)?1:0) +#endif + +#ifdef __GNUC__ +#define CONSTFUNC __attribute__((const)) +#define PUREFUNC __attribute__((pure)) +#define NORETURN __attribute__ ((noreturn)) +#else +#define CONSTFUNC +#define PUREFUNC +#define NORETURN +#endif + +/* CPhipps - use limits.h instead of depreciated values.h */ +#include + +/* cph - move compatibility levels here so we can use them in d_server.c */ +typedef enum { + doom_12_compatibility, /* Doom v1.2 */ + doom_1666_compatibility, /* Doom v1.666 */ + doom2_19_compatibility, /* Doom & Doom 2 v1.9 */ + ultdoom_compatibility, /* Doom 2 v1.9 */ + finaldoom_compatibility, /* Final & Ultimate Doom v1.9, and Doom95 */ + dosdoom_compatibility, /* Early dosdoom & tasdoom */ + tasdoom_compatibility, /* Early dosdoom & tasdoom */ + boom_compatibility_compatibility, /* Boom's compatibility mode */ + boom_201_compatibility, /* Compatible with Boom v2.01 */ + boom_202_compatibility, /* Compatible with Boom v2.01 */ + lxdoom_1_compatibility, /* LxDoom v1.3.2+ */ + mbf_compatibility, /* MBF */ + prboom_1_compatibility, /* PrBoom 2.03beta? */ + prboom_2_compatibility, /* PrBoom 2.1.0-2.1.1 */ + prboom_3_compatibility, /* PrBoom 2.2.x */ + prboom_4_compatibility, /* PrBoom 2.3.x */ + prboom_5_compatibility, /* PrBoom 2.4.0 */ + prboom_6_compatibility, /* Latest PrBoom */ + MAX_COMPATIBILITY_LEVEL, /* Must be last entry */ + /* Aliases follow */ + boom_compatibility = boom_201_compatibility, /* Alias used by G_Compatibility */ + best_compatibility = prboom_6_compatibility, +} complevel_t; + +/* cph - from v_video.h, needed by gl_struct.h */ +enum patch_translation_e { + VPT_NONE = 0, // Normal + VPT_FLIP = 1, // Flip image horizontally + VPT_TRANS = 2, // Translate image via a translation table + VPT_STRETCH = 4, // Stretch to compensate for high-res +}; + +#endif diff --git a/src/dstrings.c b/src/dstrings.c new file mode 100644 index 0000000..4e27ea5 --- /dev/null +++ b/src/dstrings.c @@ -0,0 +1,85 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Globally defined strings. + * + *----------------------------------------------------------------------------- + */ + +#ifdef __GNUG__ +#pragma implementation "dstrings.h" +#endif +#include "dstrings.h" + + +// killough 1/18/98: remove hardcoded limit, add const: +const char *const endmsg[]= +{ + // DOOM1 + QUITMSG, + "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.", // 1/15/98 killough + + // QuitDOOM II messages + "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.", // 1/15/98 killough + + // FinalDOOM? + +// Note that these ending "bad taste" strings were commented out +// in the original id code as the #else case of an #if 1 +// Obviously they were internal playthings before the release of +// DOOM2 and were not intended for public use. +// +// Following messages commented out for now. Bad taste. // phares + +// "fuck you, pussy!\nget the fuck out!", +// "you quit and i'll jizz\nin your cystholes!", +// "if you leave, i'll make\nthe lord drink my jizz.", +// "hey, ron! can we say\n'fuck' in the game?", +// "i'd leave: this is just\nmore monsters and levels.\nwhat a load.", +// "suck it down, asshole!\nyou're a fucking wimp!", +// "don't quit now! we're \nstill spending your money!", + + // Internal debug. Different style, too. + "THIS IS NO MESSAGE!\nPage intentionally left blank.", // 1/15/98 killough +}; + +// killough 1/18/98: remove hardcoded limit and replace with var (silly hack): +const size_t NUM_QUITMESSAGES = sizeof(endmsg)/sizeof(*endmsg) - 1; diff --git a/src/dstrings.h b/src/dstrings.h new file mode 100644 index 0000000..abb77f8 --- /dev/null +++ b/src/dstrings.h @@ -0,0 +1,80 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * DOOM strings, by language. + * Note: In BOOM, some new strings hav ebeen defined that are + * not found in the French version. A better approach is + * to create a BEX text-replacement file for other + * languages since any language can be supported that way + * without recompiling the program. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __DSTRINGS__ +#define __DSTRINGS__ + +/* All important printed strings. + * Language selection (message strings). + * Use -DFRENCH etc. + */ + +#ifdef FRENCH +#include "d_french.h" +#else +#include "d_englsh.h" +#endif + +/* Note this is not externally modifiable through DEH/BEX + * Misc. other strings. + * #define SAVEGAMENAME "boomsav" * killough 3/22/98 * + * Ty 05/04/98 - replaced with a modifiable string, see d_deh.c + */ + +/* + * File locations, + * relative to current position. + * Path names are OS-sensitive. + */ +#define DEVMAPS "devmaps" +#define DEVDATA "devdata" + + +/* Not done in french? + * QuitDOOM messages * + * killough 1/18/98: + * replace hardcoded limit with extern var (silly hack, I know) + */ + +#include + +extern const size_t NUM_QUITMESSAGES; /* Calculated in dstrings.c */ + +extern const char* const endmsg[]; /* killough 1/18/98 const added */ + +#endif diff --git a/src/f_finale.c b/src/f_finale.c new file mode 100644 index 0000000..1a96c33 --- /dev/null +++ b/src/f_finale.c @@ -0,0 +1,668 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Game completion, final screen animation. + * + *----------------------------------------------------------------------------- + */ + +#include "doomstat.h" +#include "d_event.h" +#include "v_video.h" +#include "w_wad.h" +#include "s_sound.h" +#include "sounds.h" +#include "d_deh.h" // Ty 03/22/98 - externalizations +#include "f_finale.h" // CPhipps - hmm... + +// Stage of animation: +// 0 = text, 1 = art screen, 2 = character cast +static int finalestage; // cph - +static int finalecount; // made static +static const char* finaletext; // cph - +static const char* finaleflat; // made static const + +// defines for the end mission display text // phares + +#define TEXTSPEED 3 // original value // phares +#define TEXTWAIT 250 // original value // phares +#define NEWTEXTSPEED 0.01f // new value // phares +#define NEWTEXTWAIT 1000 // new value // phares + +// CPhipps - removed the old finale screen text message strings; +// they were commented out for ages already +// Ty 03/22/98 - ... the new s_WHATEVER extern variables are used +// in the code below instead. + +void F_StartCast (void); +void F_CastTicker (void); +boolean F_CastResponder (event_t *ev); +void F_CastDrawer (void); + +void WI_checkForAccelerate(void); // killough 3/28/98: used to +extern int acceleratestage; // accelerate intermission screens +static int midstage; // whether we're in "mid-stage" + +// +// F_StartFinale +// +void F_StartFinale (void) +{ + gameaction = ga_nothing; + gamestate = GS_FINALE; + automapmode &= ~am_active; + + // killough 3/28/98: clear accelerative text flags + acceleratestage = midstage = 0; + + // Okay - IWAD dependend stuff. + // This has been changed severly, and + // some stuff might have changed in the process. + switch ( gamemode ) + { + // 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 = bgflatE1; // Ty 03/30/98 - new externalized bg flats + finaletext = s_E1TEXT; // Ty 03/23/98 - Was e1text variable. + break; + case 2: + finaleflat = bgflatE2; + finaletext = s_E2TEXT; // Ty 03/23/98 - Same stuff for each + break; + case 3: + finaleflat = bgflatE3; + finaletext = s_E3TEXT; + break; + case 4: + finaleflat = bgflatE4; + finaletext = s_E4TEXT; + break; + default: + // Ouch. + break; + } + break; + } + + // DOOM II and missions packs with E1, M34 + case commercial: + { + S_ChangeMusic(mus_read_m, true); + + // Ty 08/27/98 - added the gamemission logic + switch (gamemap) + { + case 6: + finaleflat = bgflat06; + finaletext = (gamemission==pack_tnt) ? s_T1TEXT : + (gamemission==pack_plut) ? s_P1TEXT : s_C1TEXT; + break; + case 11: + finaleflat = bgflat11; + finaletext = (gamemission==pack_tnt) ? s_T2TEXT : + (gamemission==pack_plut) ? s_P2TEXT : s_C2TEXT; + break; + case 20: + finaleflat = bgflat20; + finaletext = (gamemission==pack_tnt) ? s_T3TEXT : + (gamemission==pack_plut) ? s_P3TEXT : s_C3TEXT; + break; + case 30: + finaleflat = bgflat30; + finaletext = (gamemission==pack_tnt) ? s_T4TEXT : + (gamemission==pack_plut) ? s_P4TEXT : s_C4TEXT; + break; + case 15: + finaleflat = bgflat15; + finaletext = (gamemission==pack_tnt) ? s_T5TEXT : + (gamemission==pack_plut) ? s_P5TEXT : s_C5TEXT; + break; + case 31: + finaleflat = bgflat31; + finaletext = (gamemission==pack_tnt) ? s_T6TEXT : + (gamemission==pack_plut) ? s_P6TEXT : s_C6TEXT; + break; + default: + // Ouch. + break; + } + break; + // Ty 08/27/98 - end gamemission logic + } + + // Indeterminate. + default: // Ty 03/30/98 - not externalized + S_ChangeMusic(mus_read_m, true); + finaleflat = "F_SKY1"; // Not used anywhere else. + finaletext = s_C1TEXT; // FIXME - other text, music? + break; + } + + finalestage = 0; + finalecount = 0; +} + + + +boolean F_Responder (event_t *event) +{ + if (finalestage == 2) + return F_CastResponder (event); + + return false; +} + +// Get_TextSpeed() returns the value of the text display speed // phares +// Rewritten to allow user-directed acceleration -- killough 3/28/98 + +static float Get_TextSpeed(void) +{ + return midstage ? NEWTEXTSPEED : (midstage=acceleratestage) ? + acceleratestage=0, NEWTEXTSPEED : TEXTSPEED; +} + + +// +// F_Ticker +// +// killough 3/28/98: almost totally rewritten, to use +// player-directed acceleration instead of constant delays. +// Now the player can accelerate the text display by using +// the fire/use keys while it is being printed. The delay +// automatically responds to the user, and gives enough +// time to read. +// +// killough 5/10/98: add back v1.9 demo compatibility +// + +void F_Ticker(void) +{ + int i; + if (!demo_compatibility) + WI_checkForAccelerate(); // killough 3/28/98: check for acceleration + else + if (gamemode == commercial && finalecount > 50) // check for skipping + for (i=0; i strlen(finaletext)*speed + + (midstage ? NEWTEXTWAIT : TEXTWAIT) || + (midstage && acceleratestage)) { + if (gamemode != commercial) // Doom 1 / Ultimate Doom episode end + { // with enough time, it's automatic + finalecount = 0; + finalestage = 1; + wipegamestate = -1; // force a wipe + if (gameepisode == 3) + S_StartMusic(mus_bunny); + } + else // you must press a button to continue in Doom 2 + if (!demo_compatibility && midstage) + { + next_level: + if (gamemap == 30) + F_StartCast(); // cast of Doom 2 characters + else + gameaction = ga_worlddone; // next level, e.g. MAP07 + } + } + } +} + +// +// F_TextWrite +// +// This program displays the background and text at end-mission // phares +// text time. It draws both repeatedly so that other displays, // | +// like the main menu, can be drawn over it dynamically and // V +// erased dynamically. The TEXTSPEED constant is changed into +// the Get_TextSpeed function so that the speed of writing the // ^ +// text can be increased, and there's still time to read what's // | +// written. // phares +// CPhipps - reformatted + +#include "hu_stuff.h" +extern patchnum_t hu_font[HU_FONTSIZE]; + + +static void F_TextWrite (void) +{ + V_DrawBackground(finaleflat, 0); + { // draw some of the text onto the screen + int cx = 10; + int cy = 10; + const char* ch = finaletext; // CPhipps - const + int count = (int)((float)(finalecount - 10)/Get_TextSpeed()); // phares + int w; + + if (count < 0) + count = 0; + + for ( ; count ; count-- ) { + int c = *ch++; + + if (!c) + break; + if (c == '\n') { + cx = 10; + cy += 11; + continue; + } + + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c> HU_FONTSIZE) { + cx += 4; + continue; + } + + w = hu_font[c].width; + if (cx+w > SCREENWIDTH) + break; + // CPhipps - patch drawing updated + V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH); + cx+=w; + } + } +} + +// +// Final DOOM 2 animation +// Casting by id Software. +// in order of appearance +// +typedef struct +{ + const char **name; // CPhipps - const** + mobjtype_t type; +} castinfo_t; + +#define MAX_CASTORDER 18 /* Ty - hard coded for now */ +static const castinfo_t castorder[] = { // CPhipps - static const, initialised here + { &s_CC_ZOMBIE, MT_POSSESSED }, + { &s_CC_SHOTGUN, MT_SHOTGUY }, + { &s_CC_HEAVY, MT_CHAINGUY }, + { &s_CC_IMP, MT_TROOP }, + { &s_CC_DEMON, MT_SERGEANT }, + { &s_CC_LOST, MT_SKULL }, + { &s_CC_CACO, MT_HEAD }, + { &s_CC_HELL, MT_KNIGHT }, + { &s_CC_BARON, MT_BRUISER }, + { &s_CC_ARACH, MT_BABY }, + { &s_CC_PAIN, MT_PAIN }, + { &s_CC_REVEN, MT_UNDEAD }, + { &s_CC_MANCU, MT_FATSO }, + { &s_CC_ARCH, MT_VILE }, + { &s_CC_SPIDER, MT_SPIDER }, + { &s_CC_CYBER, MT_CYBORG }, + { &s_CC_HERO, MT_PLAYER }, + { NULL, 0} + }; + +int castnum; +int casttics; +state_t* caststate; +boolean castdeath; +int castframes; +int castonmelee; +boolean castattacking; + + +// +// F_StartCast +// + +void F_StartCast (void) +{ + wipegamestate = -1; // force a screen wipe + castnum = 0; + caststate = &states[mobjinfo[castorder[castnum].type].seestate]; + casttics = caststate->tics; + castdeath = false; + finalestage = 2; + castframes = 0; + castonmelee = 0; + castattacking = false; + S_ChangeMusic(mus_evil, true); +} + + +// +// F_CastTicker +// +void F_CastTicker (void) +{ + int st; + int sfx; + + if (--casttics > 0) + return; // not time to change state yet + + if (caststate->tics == -1 || caststate->nextstate == S_NULL) + { + // switch from deathstate to next monster + castnum++; + castdeath = false; + if (castorder[castnum].name == NULL) + castnum = 0; + if (mobjinfo[castorder[castnum].type].seesound) + S_StartSound (NULL, mobjinfo[castorder[castnum].type].seesound); + caststate = &states[mobjinfo[castorder[castnum].type].seestate]; + castframes = 0; + } + else + { + // just advance to next state in animation + if (caststate == &states[S_PLAY_ATK1]) + goto stopattack; // Oh, gross hack! + st = caststate->nextstate; + caststate = &states[st]; + castframes++; + + // sound hacks.... + switch (st) + { + case S_PLAY_ATK1: sfx = sfx_dshtgn; break; + case S_POSS_ATK2: sfx = sfx_pistol; break; + case S_SPOS_ATK2: sfx = sfx_shotgn; break; + case S_VILE_ATK2: sfx = sfx_vilatk; break; + case S_SKEL_FIST2: sfx = sfx_skeswg; break; + case S_SKEL_FIST4: sfx = sfx_skepch; break; + case S_SKEL_MISS2: sfx = sfx_skeatk; break; + case S_FATT_ATK8: + case S_FATT_ATK5: + case S_FATT_ATK2: sfx = sfx_firsht; break; + case S_CPOS_ATK2: + case S_CPOS_ATK3: + case S_CPOS_ATK4: sfx = sfx_shotgn; break; + case S_TROO_ATK3: sfx = sfx_claw; break; + case S_SARG_ATK2: sfx = sfx_sgtatk; break; + case S_BOSS_ATK2: + case S_BOS2_ATK2: + case S_HEAD_ATK2: sfx = sfx_firsht; break; + case S_SKULL_ATK2: sfx = sfx_sklatk; break; + case S_SPID_ATK2: + case S_SPID_ATK3: sfx = sfx_shotgn; break; + case S_BSPI_ATK2: sfx = sfx_plasma; break; + case S_CYBER_ATK2: + case S_CYBER_ATK4: + case S_CYBER_ATK6: sfx = sfx_rlaunc; break; + case S_PAIN_ATK3: sfx = sfx_sklatk; break; + default: sfx = 0; break; + } + + if (sfx) + S_StartSound (NULL, sfx); + } + + if (castframes == 12) + { + // go into attack frame + castattacking = true; + if (castonmelee) + caststate=&states[mobjinfo[castorder[castnum].type].meleestate]; + else + caststate=&states[mobjinfo[castorder[castnum].type].missilestate]; + castonmelee ^= 1; + if (caststate == &states[S_NULL]) + { + if (castonmelee) + caststate= + &states[mobjinfo[castorder[castnum].type].meleestate]; + else + caststate= + &states[mobjinfo[castorder[castnum].type].missilestate]; + } + } + + if (castattacking) + { + if (castframes == 24 + || caststate == &states[mobjinfo[castorder[castnum].type].seestate] ) + { + stopattack: + castattacking = false; + castframes = 0; + caststate = &states[mobjinfo[castorder[castnum].type].seestate]; + } + } + + casttics = caststate->tics; + if (casttics == -1) + casttics = 15; +} + + +// +// F_CastResponder +// + +boolean F_CastResponder (event_t* ev) +{ + if (ev->type != ev_keydown) + return false; + + if (castdeath) + return true; // already in dying frames + + // go into death frame + castdeath = true; + caststate = &states[mobjinfo[castorder[castnum].type].deathstate]; + casttics = caststate->tics; + castframes = 0; + castattacking = false; + if (mobjinfo[castorder[castnum].type].deathsound) + S_StartSound (NULL, mobjinfo[castorder[castnum].type].deathsound); + + return true; +} + + +static void F_CastPrint (const char* text) // CPhipps - static, const char* +{ + const char* ch; // CPhipps - const + int c; + int cx; + int w; + int width; + + // find width + ch = text; + width = 0; + + while (ch) + { + c = *ch++; + if (!c) + break; + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c> HU_FONTSIZE) + { + width += 4; + continue; + } + + w = hu_font[c].width; + width += w; + } + + // draw it + cx = 160-width/2; + ch = text; + while (ch) + { + c = *ch++; + if (!c) + break; + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c> HU_FONTSIZE) + { + cx += 4; + continue; + } + + w = hu_font[c].width; + // CPhipps - patch drawing updated + V_DrawNumPatch(cx, 180, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH); + cx+=w; + } +} + + +// +// F_CastDrawer +// + +void F_CastDrawer (void) +{ + spritedef_t* sprdef; + spriteframe_t* sprframe; + int lump; + boolean flip; + + // erase the entire screen to a background + // CPhipps - patch drawing updated + V_DrawNamePatch(0,0,0, bgcastcall, CR_DEFAULT, VPT_STRETCH); // Ty 03/30/98 bg texture extern + + F_CastPrint (*(castorder[castnum].name)); + + // draw the current frame in the middle of the screen + sprdef = &sprites[caststate->sprite]; + sprframe = &sprdef->spriteframes[ caststate->frame & FF_FRAMEMASK]; + lump = sprframe->lump[0]; + flip = (boolean)sprframe->flip[0]; + + // CPhipps - patch drawing updated + V_DrawNumPatch(160, 170, 0, lump+firstspritelump, CR_DEFAULT, + VPT_STRETCH | (flip ? VPT_FLIP : 0)); +} + +// +// F_BunnyScroll +// +static const char pfub2[] = { "PFUB2" }; +static const char pfub1[] = { "PFUB1" }; + +static void F_BunnyScroll (void) +{ + char name[10]; + int stage; + static int laststage; + + { + int scrolled = 320 - (finalecount-230)/2; + if (scrolled <= 0) { + V_DrawNamePatch(0, 0, 0, pfub2, CR_DEFAULT, VPT_STRETCH); + } else if (scrolled >= 320) { + V_DrawNamePatch(0, 0, 0, pfub1, CR_DEFAULT, VPT_STRETCH); + } else { + V_DrawNamePatch(320-scrolled, 0, 0, pfub1, CR_DEFAULT, VPT_STRETCH); + V_DrawNamePatch(-scrolled, 0, 0, pfub2, CR_DEFAULT, VPT_STRETCH); + } + } + + if (finalecount < 1130) + return; + if (finalecount < 1180) + { + // CPhipps - patch drawing updated + V_DrawNamePatch((320-13*8)/2, (200-8*8)/2,0, "END0", CR_DEFAULT, VPT_STRETCH); + laststage = 0; + return; + } + + stage = (finalecount-1180) / 5; + if (stage > 6) + stage = 6; + if (stage > laststage) + { + S_StartSound (NULL, sfx_pistol); + laststage = stage; + } + + sprintf (name,"END%i",stage); + // CPhipps - patch drawing updated + V_DrawNamePatch((320-13*8)/2, (200-8*8)/2, 0, name, CR_DEFAULT, VPT_STRETCH); +} + + +// +// F_Drawer +// +void F_Drawer (void) +{ + if (finalestage == 2) + { + F_CastDrawer (); + return; + } + + if (!finalestage) + F_TextWrite (); + else + { + switch (gameepisode) + { + // CPhipps - patch drawing updated + case 1: + if ( gamemode == retail ) + V_DrawNamePatch(0, 0, 0, "CREDIT", CR_DEFAULT, VPT_STRETCH); + else + V_DrawNamePatch(0, 0, 0, "HELP2", CR_DEFAULT, VPT_STRETCH); + break; + case 2: + V_DrawNamePatch(0, 0, 0, "VICTORY2", CR_DEFAULT, VPT_STRETCH); + break; + case 3: + F_BunnyScroll (); + break; + case 4: + V_DrawNamePatch(0, 0, 0, "ENDPIC", CR_DEFAULT, VPT_STRETCH); + break; + } + } +} diff --git a/src/f_finale.h b/src/f_finale.h new file mode 100644 index 0000000..6214f38 --- /dev/null +++ b/src/f_finale.h @@ -0,0 +1,56 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Related to f_finale.c, which is called at the end of a level + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __F_FINALE__ +#define __F_FINALE__ + +#include "doomtype.h" +#include "d_event.h" + +/* + * FINALE + */ + +/* Called by main loop. */ +boolean F_Responder (event_t* ev); + +/* Called by main loop. */ +void F_Ticker (void); + +/* Called by main loop. */ +void F_Drawer (void); + +void F_StartFinale (void); + +#endif diff --git a/src/f_wipe.c b/src/f_wipe.c new file mode 100644 index 0000000..fc3ac1d --- /dev/null +++ b/src/f_wipe.c @@ -0,0 +1,202 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Mission begin melt/wipe screen special effect. + * + *----------------------------------------------------------------------------- + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "z_zone.h" +#include "doomdef.h" +#include "i_video.h" +#include "v_video.h" +#include "m_random.h" +#include "f_wipe.h" + +// +// SCREEN WIPE PACKAGE +// + +// Parts re-written to support true-color video modes. Column-major +// formatting removed. - POPE + +// CPhipps - macros for the source and destination screens +#define SRC_SCR 2 +#define DEST_SCR 3 + +static screeninfo_t wipe_scr_start; +static screeninfo_t wipe_scr_end; +static screeninfo_t wipe_scr; + +static int y_lookup[MAX_SCREENWIDTH]; + + +static int wipe_initMelt(int ticks) +{ + int i; + + // copy start screen to main screen + for(i=0;i not ready to scroll yet) + y_lookup[0] = -(M_Random()%16); + for (i=1;i 0) + y_lookup[i] = 0; + else + if (y_lookup[i] == -16) + y_lookup[i] = -15; + } + return 0; +} + +static int wipe_doMelt(int ticks) +{ + boolean done = true; + int i; + const int depth = V_GetPixelDepth(); + + while (ticks--) { + for (i=0;i<(SCREENWIDTH);i++) { + if (y_lookup[i]<0) { + y_lookup[i]++; + done = false; + continue; + } + if (y_lookup[i] < SCREENHEIGHT) { + byte *s, *d; + int j, k, dy; + + /* cph 2001/07/29 - + * The original melt rate was 8 pixels/sec, i.e. 25 frames to melt + * the whole screen, so make the melt rate depend on SCREENHEIGHT + * so it takes no longer in high res + */ + dy = (y_lookup[i] < 16) ? y_lookup[i]+1 : SCREENHEIGHT/25; + if (y_lookup[i]+dy >= SCREENHEIGHT) + dy = SCREENHEIGHT - y_lookup[i]; + + s = wipe_scr_end.data + (y_lookup[i]*wipe_scr_end.byte_pitch+(i*depth)); + d = wipe_scr.data + (y_lookup[i]*wipe_scr.byte_pitch+(i*depth)); + for (j=dy;j;j--) { + for (k=0; k +#include +#include +#ifdef _MSC_VER +#define F_OK 0 /* Check for file existence */ +#define W_OK 2 /* Check for write permission */ +#define R_OK 4 /* Check for read permission */ +#include +#else +#include +#endif +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "doomstat.h" +#include "d_net.h" +#include "f_finale.h" +#include "m_argv.h" +#include "m_misc.h" +#include "m_menu.h" +#include "m_random.h" +#include "p_setup.h" +#include "p_saveg.h" +#include "p_tick.h" +#include "p_map.h" +#include "p_checksum.h" +#include "d_main.h" +#include "wi_stuff.h" +#include "hu_stuff.h" +#include "st_stuff.h" +#include "am_map.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_draw.h" +#include "p_map.h" +#include "s_sound.h" +#include "dstrings.h" +#include "sounds.h" +#include "r_data.h" +#include "r_sky.h" +#include "d_deh.h" // Ty 3/27/98 deh declarations +#include "p_inter.h" +#include "g_game.h" +#include "lprintf.h" +#include "i_main.h" +#include "i_system.h" +#include "r_demo.h" +#include "r_fps.h" + +#define SAVEGAMESIZE 0x20000 +#define SAVESTRINGSIZE 24 + +static size_t savegamesize = SAVEGAMESIZE; // killough +static boolean netdemo; +static const byte *demobuffer; /* cph - only used for playback */ +static int demolength; // check for overrun (missing DEMOMARKER) +static FILE *demofp; /* cph - record straight to file */ +static const byte *demo_p; +static short consistancy[MAXPLAYERS][BACKUPTICS]; + +gameaction_t gameaction; +gamestate_t gamestate; +skill_t gameskill; +boolean respawnmonsters; +int gameepisode; +int gamemap; +boolean paused; +// CPhipps - moved *_loadgame vars here +static boolean forced_loadgame = false; +static boolean command_loadgame = false; + +boolean usergame; // ok to save / end game +boolean timingdemo; // if true, exit with report on completion +boolean fastdemo; // if true, run at full speed -- killough +boolean nodrawers; // for comparative timing purposes +boolean noblit; // for comparative timing purposes +int starttime; // for comparative timing purposes +boolean deathmatch; // only if started as net death +boolean netgame; // only true if packets are broadcast +boolean playeringame[MAXPLAYERS]; +player_t players[MAXPLAYERS]; +int consoleplayer; // player taking events and displaying +int displayplayer; // view being displayed +int gametic; +int basetic; /* killough 9/29/98: for demo sync */ +int totalkills, totallive, totalitems, totalsecret; // for intermission +boolean demorecording; +boolean demoplayback; +int demover; +boolean singledemo; // quit after playing a demo from cmdline +wbstartstruct_t wminfo; // parms for world map / intermission +boolean haswolflevels = false;// jff 4/18/98 wolf levels present +static byte *savebuffer; // CPhipps - static +int autorun = false; // always running? // phares +int totalleveltimes; // CPhipps - total time for all completed levels +int longtics; + +// +// controls (have defaults) +// + +int key_right; +int key_left; +int key_up; +int key_down; +int key_menu_right; // phares 3/7/98 +int key_menu_left; // | +int key_menu_up; // V +int key_menu_down; +int key_menu_backspace; // ^ +int key_menu_escape; // | +int key_menu_enter; // phares 3/7/98 +int key_strafeleft; +int key_straferight; +int key_fire; +int key_use; +int key_strafe; +int key_speed; +int key_escape = KEYD_ESCAPE; // phares 4/13/98 +int key_savegame; // phares +int key_loadgame; // | +int key_autorun; // V +int key_reverse; +int key_zoomin; +int key_zoomout; +int key_chat; +int key_backspace; +int key_enter; +int key_map_right; +int key_map_left; +int key_map_up; +int key_map_down; +int key_map_zoomin; +int key_map_zoomout; +int key_map; +int key_map_gobig; +int key_map_follow; +int key_map_mark; +int key_map_clear; +int key_map_grid; +int key_map_overlay; // cph - map overlay +int key_map_rotate; // cph - map rotation +int key_help = KEYD_F1; // phares 4/13/98 +int key_soundvolume; +int key_hud; +int key_quicksave; +int key_endgame; +int key_messages; +int key_quickload; +int key_quit; +int key_gamma; +int key_spy; +int key_pause; +int key_setup; +int destination_keys[MAXPLAYERS]; +int key_weapontoggle; +int key_weapon1; +int key_weapon2; +int key_weapon3; +int key_weapon4; +int key_weapon5; +int key_weapon6; +int key_weapon7; // ^ +int key_weapon8; // | +int key_weapon9; // phares + +int key_screenshot; // killough 2/22/98: screenshot key +int mousebfire; +int mousebstrafe; +int mousebforward; +int joybfire; +int joybstrafe; +int joybuse; +int joybspeed; + +#define MAXPLMOVE (forwardmove[1]) +#define TURBOTHRESHOLD 0x32 +#define SLOWTURNTICS 6 +#define QUICKREVERSE (short)32768 // 180 degree reverse // phares +#define NUMKEYS 512 + +fixed_t forwardmove[2] = {0x19, 0x32}; +fixed_t sidemove[2] = {0x18, 0x28}; +fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn + +// CPhipps - made lots of key/button state vars static +static boolean gamekeydown[NUMKEYS]; +static int turnheld; // for accelerative turning + +static boolean mousearray[4]; +static boolean *mousebuttons = &mousearray[1]; // allow [-1] + +// mouse values are used once +static int mousex; +static int mousey; +static int dclicktime; +static int dclickstate; +static int dclicks; +static int dclicktime2; +static int dclickstate2; +static int dclicks2; + +// joystick values are repeated +static int joyxmove; +static int joyymove; +static boolean joyarray[5]; +static boolean *joybuttons = &joyarray[1]; // allow [-1] + +// Game events info +static buttoncode_t special_event; // Event triggered by local player, to send +static byte savegameslot; // Slot to load if gameaction == ga_loadgame +char savedescription[SAVEDESCLEN]; // Description to save in savegame if gameaction == ga_savegame + +//jff 3/24/98 define defaultskill here +int defaultskill; //note 1-based + +// killough 2/8/98: make corpse queue variable in size +int bodyqueslot, bodyquesize; // killough 2/8/98 +mobj_t **bodyque = 0; // phares 8/10/98 + +static void G_DoSaveGame (boolean menu); +static const byte* G_ReadDemoHeader(const byte* demo_p, size_t size, boolean failonerror); + +// +// G_BuildTiccmd +// Builds a ticcmd from all of the available inputs +// or reads it from the demo buffer. +// If recording a demo, write it out +// +static inline signed char fudgef(signed char b) +{ + static int c; + if (!b || !demo_compatibility || longtics) return b; + if (++c & 0x1f) return b; + b |= 1; if (b>2) b-=2; + return b; +} + +static inline signed short fudgea(signed short b) +{ + if (!b || !demo_compatibility || !longtics) return b; + b |= 1; if (b>2) b-=2; + return b; +} + + +void G_BuildTiccmd(ticcmd_t* cmd) +{ + boolean strafe; + boolean bstrafe; + int speed; + int tspeed; + int forward; + int side; + int newweapon; // phares + /* cphipps - remove needless I_BaseTiccmd call, just set the ticcmd to zero */ + memset(cmd,0,sizeof*cmd); + cmd->consistancy = consistancy[consoleplayer][maketic%BACKUPTICS]; + + strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe] + || joybuttons[joybstrafe]; + //e6y: the "RUN" key inverts the autorun state + speed = (gamekeydown[key_speed] || joybuttons[joybspeed] ? !autorun : autorun); // phares + + forward = side = 0; + + // use two stage accelerative turning + // on the keyboard and joystick + if (joyxmove < 0 || joyxmove > 0 || + gamekeydown[key_right] || gamekeydown[key_left]) + turnheld += ticdup; + else + turnheld = 0; + + if (turnheld < SLOWTURNTICS) + tspeed = 2; // slow turn + else + tspeed = speed; + + // turn 180 degrees in one keystroke? // phares + // | + if (gamekeydown[key_reverse]) // V + { + cmd->angleturn += QUICKREVERSE; // ^ + gamekeydown[key_reverse] = false; // | + } // phares + + // let movement keys cancel each other out + + if (strafe) + { + if (gamekeydown[key_right]) + side += sidemove[speed]; + if (gamekeydown[key_left]) + side -= sidemove[speed]; + if (joyxmove > 0) + side += sidemove[speed]; + if (joyxmove < 0) + side -= sidemove[speed]; + } + else + { + if (gamekeydown[key_right]) + cmd->angleturn -= angleturn[tspeed]; + if (gamekeydown[key_left]) + cmd->angleturn += angleturn[tspeed]; + if (joyxmove > 0) + cmd->angleturn -= angleturn[tspeed]; + if (joyxmove < 0) + cmd->angleturn += angleturn[tspeed]; + } + + if (gamekeydown[key_up]) + forward += forwardmove[speed]; + if (gamekeydown[key_down]) + forward -= forwardmove[speed]; + if (joyymove < 0) + forward += forwardmove[speed]; + if (joyymove > 0) + forward -= forwardmove[speed]; + if (gamekeydown[key_straferight]) + side += sidemove[speed]; + if (gamekeydown[key_strafeleft]) + side -= sidemove[speed]; + + // buttons + cmd->chatchar = HU_dequeueChatChar(); + + if (gamekeydown[key_fire] || mousebuttons[mousebfire] || + joybuttons[joybfire]) + cmd->buttons |= BT_ATTACK; + + if (gamekeydown[key_use] || joybuttons[joybuse]) + { + cmd->buttons |= BT_USE; + // clear double clicks if hit use button + dclicks = 0; + } + + // Toggle between the top 2 favorite weapons. // phares + // If not currently aiming one of these, switch to // phares + // the favorite. Only switch if you possess the weapon. // phares + + // killough 3/22/98: + // + // Perform automatic weapons switch here rather than in p_pspr.c, + // except in demo_compatibility mode. + // + // killough 3/26/98, 4/2/98: fix autoswitch when no weapons are left + + if ((!demo_compatibility && players[consoleplayer].attackdown && // killough + !P_CheckAmmo(&players[consoleplayer])) || gamekeydown[key_weapontoggle]) + newweapon = P_SwitchWeapon(&players[consoleplayer]); // phares + else + { // phares 02/26/98: Added gamemode checks + newweapon = + gamekeydown[key_weapon1] ? wp_fist : // killough 5/2/98: reformatted + gamekeydown[key_weapon2] ? wp_pistol : + gamekeydown[key_weapon3] ? wp_shotgun : + gamekeydown[key_weapon4] ? wp_chaingun : + gamekeydown[key_weapon5] ? wp_missile : + gamekeydown[key_weapon6] && gamemode != shareware ? wp_plasma : + gamekeydown[key_weapon7] && gamemode != shareware ? wp_bfg : + gamekeydown[key_weapon8] ? wp_chainsaw : + (!demo_compatibility && gamekeydown[key_weapon9] && gamemode == commercial) ? wp_supershotgun : + wp_nochange; + + // killough 3/22/98: For network and demo consistency with the + // new weapons preferences, we must do the weapons switches here + // instead of in p_user.c. But for old demos we must do it in + // p_user.c according to the old rules. Therefore demo_compatibility + // determines where the weapons switch is made. + + // killough 2/8/98: + // Allow user to switch to fist even if they have chainsaw. + // Switch to fist or chainsaw based on preferences. + // Switch to shotgun or SSG based on preferences. + + if (!demo_compatibility) + { + const player_t *player = &players[consoleplayer]; + + // only select chainsaw from '1' if it's owned, it's + // not already in use, and the player prefers it or + // the fist is already in use, or the player does not + // have the berserker strength. + + if (newweapon==wp_fist && player->weaponowned[wp_chainsaw] && + player->readyweapon!=wp_chainsaw && + (player->readyweapon==wp_fist || + !player->powers[pw_strength] || + P_WeaponPreferred(wp_chainsaw, wp_fist))) + newweapon = wp_chainsaw; + + // Select SSG from '3' only if it's owned and the player + // does not have a shotgun, or if the shotgun is already + // in use, or if the SSG is not already in use and the + // player prefers it. + + if (newweapon == wp_shotgun && gamemode == commercial && + player->weaponowned[wp_supershotgun] && + (!player->weaponowned[wp_shotgun] || + player->readyweapon == wp_shotgun || + (player->readyweapon != wp_supershotgun && + P_WeaponPreferred(wp_supershotgun, wp_shotgun)))) + newweapon = wp_supershotgun; + } + // killough 2/8/98, 3/22/98 -- end of weapon selection changes + } + + if (newweapon != wp_nochange) + { + cmd->buttons |= BT_CHANGE; + cmd->buttons |= newweapon< 1 ) + { + dclickstate = mousebuttons[mousebforward]; + if (dclickstate) + dclicks++; + if (dclicks == 2) + { + cmd->buttons |= BT_USE; + dclicks = 0; + } + else + dclicktime = 0; + } + else + if ((dclicktime += ticdup) > 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 + if ((dclicktime2 += ticdup) > 20) + { + dclicks2 = 0; + dclickstate2 = 0; + } + forward += mousey; + if (strafe) + side += mousex / 4; /* mead Don't want to strafe as fast as turns.*/ + else + cmd->angleturn -= mousex; /* mead now have enough dynamic range 2-10-00 */ + + mousex = mousey = 0; + + if (forward > MAXPLMOVE) + forward = MAXPLMOVE; + else if (forward < -MAXPLMOVE) + forward = -MAXPLMOVE; + if (side > MAXPLMOVE) + side = MAXPLMOVE; + else if (side < -MAXPLMOVE) + side = -MAXPLMOVE; + + cmd->forwardmove += fudgef((signed char)forward); + cmd->sidemove += side; + cmd->angleturn = fudgea(cmd->angleturn); + + // CPhipps - special events (game new/load/save/pause) + if (special_event & BT_SPECIAL) { + cmd->buttons = special_event; + special_event = 0; + } +} + +// +// G_RestartLevel +// + +void G_RestartLevel(void) +{ + special_event = BT_SPECIAL | (BTS_RESTARTLEVEL & BT_SPECIALMASK); +} + +#include "z_bmalloc.h" +// +// G_DoLoadLevel +// + +static void G_DoLoadLevel (void) +{ + int i; + + // Set the sky map. + // First thing, we have a dummy sky texture name, + // 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 //jff 3/27/98 sorry guys pack_tnt,pack_plut + // || gamemode == pack_plut) //aren't gamemodes, this was matching retail + { + skytexture = R_TextureNumForName ("SKY3"); + if (gamemap < 12) + skytexture = R_TextureNumForName ("SKY1"); + else + if (gamemap < 21) + skytexture = R_TextureNumForName ("SKY2"); + } + else //jff 3/27/98 and lets not forget about DOOM and Ultimate DOOM huh? + switch (gameepisode) + { + case 1: + skytexture = R_TextureNumForName ("SKY1"); + break; + case 2: + skytexture = R_TextureNumForName ("SKY2"); + break; + case 3: + skytexture = R_TextureNumForName ("SKY3"); + break; + case 4: // Special Edition sky + skytexture = R_TextureNumForName ("SKY4"); + break; + }//jff 3/27/98 end sky setting fix + + /* cph 2006/07/31 - took out unused levelstarttic variable */ + + if (!demo_compatibility && !mbf_features) // killough 9/29/98 + basetic = gametic; + + if (wipegamestate == GS_LEVEL) + wipegamestate = -1; // force a wipe + + gamestate = GS_LEVEL; + + for (i=0 ; idata1 == key_spy && netgame && (demoplayback || !deathmatch) && + gamestate == GS_LEVEL) + { + if (ev->type == ev_keyup) + gamekeydown[key_spy] = false; + if (ev->type == ev_keydown && !gamekeydown[key_spy]) + { + gamekeydown[key_spy] = true; + do // spy mode + if (++displayplayer >= MAXPLAYERS) + displayplayer = 0; + while (!playeringame[displayplayer] && displayplayer!=consoleplayer); + + ST_Start(); // killough 3/7/98: switch status bar views too + HU_Start(); + S_UpdateSounds(players[displayplayer].mo); + R_ActivateSectorInterpolations(); + R_SmoothPlaying_Reset(NULL); + } + return true; + } + + // any other key pops up menu if in demos + // + // killough 8/2/98: enable automap in -timedemo demos + // + // killough 9/29/98: make any key pop up menu regardless of + // which kind of demo, and allow other events during playback + + if (gameaction == ga_nothing && (demoplayback || gamestate == GS_DEMOSCREEN)) + { + // killough 9/29/98: allow user to pause demos during playback + if (ev->type == ev_keydown && ev->data1 == key_pause) + { + if (paused ^= 2) + S_PauseSound(); + else + S_ResumeSound(); + return true; + } + + // killough 10/98: + // Don't pop up menu, if paused in middle + // of demo playback, or if automap active. + // Don't suck up keys, which may be cheats + + return gamestate == GS_DEMOSCREEN && + !(paused & 2) && !(automapmode & am_active) && + ((ev->type == ev_keydown) || + (ev->type == ev_mouse && ev->data1) || + (ev->type == ev_joystick && ev->data1)) ? + M_StartControlPanel(), true : false; + } + + if (gamestate == GS_FINALE && F_Responder(ev)) + return true; // finale ate the event + + switch (ev->type) + { + case ev_keydown: + if (ev->data1 == key_pause) // phares + { + special_event = BT_SPECIAL | (BTS_PAUSE & BT_SPECIALMASK); + return true; + } + if (ev->data1 data1] = true; + return true; // eat key down events + + case ev_keyup: + if (ev->data1 data1] = false; + 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; + /* + * bmead@surfree.com + * Modified by Barry Mead after adding vastly more resolution + * to the Mouse Sensitivity Slider in the options menu 1-9-2000 + * Removed the mouseSensitivity "*4" to allow more low end + * sensitivity resolution especially for lsdoom users. + */ + mousex += (ev->data2*(mouseSensitivity_horiz))/10; /* killough */ + mousey += (ev->data3*(mouseSensitivity_vert))/10; /*Mead rm *4 */ + 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; + joyxmove = ev->data2; + joyymove = ev->data3; + return true; // eat events + + default: + break; + } + return false; +} + +// +// G_Ticker +// Make ticcmd_ts for the players. +// + +void G_Ticker (void) +{ + int i; + static gamestate_t prevgamestate; + + // CPhipps - player colour changing + if (!demoplayback && mapcolor_plyr[consoleplayer] != mapcolor_me) { + // Changed my multiplayer colour - Inform the whole game + int net_cl = LONG(mapcolor_me); +#ifdef HAVE_NET + D_NetSendMisc(nm_plcolour, sizeof(net_cl), &net_cl); +#endif + G_ChangedPlayerColour(consoleplayer, mapcolor_me); + } + P_MapStart(); + // do player reborns if needed + for (i=0 ; iforwardmove > TURBOTHRESHOLD && + !(gametic&31) && ((gametic>>5)&3) == i ) + { + extern char *player_names[]; + /* cph - don't use sprintf, use doom_printf */ + doom_printf ("%s is turbo!", player_names[i]); + } + + if (netgame && !netdemo && !(gametic%ticdup) ) + { + if (gametic > BACKUPTICS + && consistancy[i][buf] != cmd->consistancy) + I_Error("G_Ticker: Consistency failure (%i should be %i)", + cmd->consistancy, consistancy[i][buf]); + if (players[i].mo) + consistancy[i][buf] = players[i].mo->x; + else + consistancy[i][buf] = 0; // killough 2/14/98 + } + } + } + + // check for special buttons + for (i=0; i>BTS_SAVESHIFT; + gameaction = ga_savegame; + break; + + // CPhipps - remote loadgame request + case BTS_LOADGAME: + savegameslot = + (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT; + gameaction = ga_loadgame; + forced_loadgame = netgame; // Force if a netgame + command_loadgame = false; + break; + + // CPhipps - Restart the level + case BTS_RESTARTLEVEL: + if (demoplayback || (compatibility_level < lxdoom_1_compatibility)) + break; // CPhipps - Ignore in demos or old games + gameaction = ga_loadlevel; + break; + } + players[i].cmd.buttons = 0; + } + } + } + } + + // cph - if the gamestate changed, we may need to clean up the old gamestate + if (gamestate != prevgamestate) { + switch (prevgamestate) { + case GS_LEVEL: + // This causes crashes at level end - Neil Stevens + // The crash is because the sounds aren't stopped before freeing them + // the following is a possible fix + // This fix does avoid the crash wowever, with this fix in, the exit + // switch sound is cut off + // S_Stop(); + // Z_FreeTags(PU_LEVEL, PU_PURGELEVEL-1); + break; + case GS_INTERMISSION: + WI_End(); + default: + break; + } + prevgamestate = gamestate; + } + + // e6y + // do nothing if a pause has been pressed during playback + // pausing during intermission can cause desynchs without that + if (paused & 2 && gamestate != GS_LEVEL) + return; + + // do main actions + switch (gamestate) + { + case GS_LEVEL: + P_Ticker (); + ST_Ticker (); + AM_Ticker (); + HU_Ticker (); + break; + + case GS_INTERMISSION: + WI_Ticker (); + break; + + case GS_FINALE: + F_Ticker (); + break; + + case GS_DEMOSCREEN: + D_PageTicker (); + break; + } +} + +// +// PLAYER STRUCTURE FUNCTIONS +// also see P_SpawnPlayer in P_Things +// + +// +// G_PlayerFinishLevel +// Can when a player completes a level. +// + +static void G_PlayerFinishLevel(int player) +{ + player_t *p = &players[player]; + memset(p->powers, 0, sizeof p->powers); + memset(p->cards, 0, sizeof p->cards); + p->mo = NULL; // cph - this is allocated PU_LEVEL so it's gone + p->extralight = 0; // cancel gun flashes + p->fixedcolormap = 0; // cancel ir gogles + p->damagecount = 0; // no palette changes + p->bonuscount = 0; +} + +// CPhipps - G_SetPlayerColour +// Player colours stuff +// +// G_SetPlayerColour + +#include "r_draw.h" + +void G_ChangedPlayerColour(int pn, int cl) +{ + int i; + + if (!netgame) return; + + mapcolor_plyr[pn] = cl; + + // Rebuild colour translation tables accordingly + R_InitTranslationTables(); + // Change translations on existing player mobj's + for (i=0; iflags &= ~MF_TRANSLATION; + players[i].mo->flags |= playernumtotrans[i] << MF_TRANSSHIFT; + } + } +} + +// +// G_PlayerReborn +// Called after a player dies +// almost everything is cleared and initialized +// + +void G_PlayerReborn (int player) +{ + player_t *p; + int i; + int frags[MAXPLAYERS]; + int killcount; + int itemcount; + int secretcount; + + memcpy (frags, players[player].frags, sizeof frags); + killcount = players[player].killcount; + itemcount = players[player].itemcount; + secretcount = players[player].secretcount; + + p = &players[player]; + + // killough 3/10/98,3/21/98: preserve cheats across idclev + { + int cheats = p->cheats; + memset (p, 0, sizeof(*p)); + p->cheats = cheats; + } + + memcpy(players[player].frags, frags, sizeof(players[player].frags)); + players[player].killcount = killcount; + players[player].itemcount = itemcount; + players[player].secretcount = secretcount; + + p->usedown = p->attackdown = true; // don't do anything immediately + p->playerstate = PST_LIVE; + p->health = initial_health; // Ty 03/12/98 - use dehacked values + p->readyweapon = p->pendingweapon = wp_pistol; + p->weaponowned[wp_fist] = true; + p->weaponowned[wp_pistol] = true; + p->ammo[am_clip] = initial_bullets; // Ty 03/12/98 - use dehacked values + + for (i=0 ; imaxammo[i] = maxammo[i]; +} + +// +// G_CheckSpot +// Returns false if the player cannot be respawned +// at the given mapthing_t spot +// because something is occupying it +// + +static boolean G_CheckSpot(int playernum, mapthing_t *mthing) +{ + fixed_t x,y; + subsector_t *ss; + int i; + + if (!players[playernum].mo) + { + // first spawn of level, before corpses + for (i=0 ; ix == mthing->x << FRACBITS + && players[i].mo->y == mthing->y << FRACBITS) + return false; + return true; + } + + x = mthing->x << FRACBITS; + y = mthing->y << FRACBITS; + + // killough 4/2/98: fix bug where P_CheckPosition() uses a non-solid + // corpse to detect collisions with other players in DM starts + // + // Old code: + // if (!P_CheckPosition (players[playernum].mo, x, y)) + // return false; + + players[playernum].mo->flags |= MF_SOLID; + i = P_CheckPosition(players[playernum].mo, x, y); + players[playernum].mo->flags &= ~MF_SOLID; + if (!i) + return false; + + // flush an old corpse if needed + // killough 2/8/98: make corpse queue have an adjustable limit + // killough 8/1/98: Fix bugs causing strange crashes + + if (bodyquesize > 0) + { + static int queuesize; + if (queuesize < bodyquesize) + { + bodyque = realloc(bodyque, bodyquesize*sizeof*bodyque); + memset(bodyque+queuesize, 0, + (bodyquesize-queuesize)*sizeof*bodyque); + queuesize = bodyquesize; + } + if (bodyqueslot >= bodyquesize) + P_RemoveMobj(bodyque[bodyqueslot % bodyquesize]); + bodyque[bodyqueslot++ % bodyquesize] = players[playernum].mo; + } + else + if (!bodyquesize) + P_RemoveMobj(players[playernum].mo); + + // spawn a teleport fog + ss = R_PointInSubsector (x,y); + { // Teleport fog at respawn point + fixed_t xa,ya; + int an; + mobj_t *mo; + +/* BUG: an can end up negative, because mthing->angle is (signed) short. + * We have to emulate original Doom's behaviour, deferencing past the start + * of the array, into the previous array (finetangent) */ + an = ( ANG45 * ((signed)mthing->angle/45) ) >> ANGLETOFINESHIFT; + xa = finecosine[an]; + ya = finesine[an]; + + if (compatibility_level <= finaldoom_compatibility || compatibility_level == prboom_4_compatibility) + switch (an) { + case -4096: xa = finetangent[2048]; // finecosine[-4096] + ya = finetangent[0]; // finesine[-4096] + break; + case -3072: xa = finetangent[3072]; // finecosine[-3072] + ya = finetangent[1024]; // finesine[-3072] + break; + case -2048: xa = finesine[0]; // finecosine[-2048] + ya = finetangent[2048]; // finesine[-2048] + break; + case -1024: xa = finesine[1024]; // finecosine[-1024] + ya = finetangent[3072]; // finesine[-1024] + break; + case 1024: + case 2048: + case 3072: + case 4096: + case 0: break; /* correct angles set above */ + default: I_Error("G_CheckSpot: unexpected angle %d\n",an); + } + + 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 + } + + return true; +} + + +// G_DeathMatchSpawnPlayer +// Spawns a player at one of the random death match spots +// called at level load and each death +// +void G_DeathMatchSpawnPlayer (int playernum) +{ + int j, selections = deathmatch_p - deathmatchstarts; + + if (selections < MAXPLAYERS) + I_Error("G_DeathMatchSpawnPlayer: Only %i deathmatch spots, %d required", + selections, MAXPLAYERS); + + for (j=0 ; j<20 ; j++) + { + int i = P_Random(pr_dmspawn) % selections; + if (G_CheckSpot (playernum, &deathmatchstarts[i]) ) + { + deathmatchstarts[i].type = playernum+1; + P_SpawnPlayer (playernum, &deathmatchstarts[i]); + return; + } + } + + // no good spot, so the player will probably get stuck + P_SpawnPlayer (playernum, &playerstarts[playernum]); +} + +// +// G_DoReborn +// + +void G_DoReborn (int playernum) +{ + if (!netgame) + gameaction = ga_loadlevel; // reload the level from scratch + else + { // respawn at the start + int i; + + // first dissasociate the corpse + players[playernum].mo->player = NULL; + + // spawn at random spot if in death match + if (deathmatch) + { + G_DeathMatchSpawnPlayer (playernum); + return; + } + + if (G_CheckSpot (playernum, &playerstarts[playernum]) ) + { + P_SpawnPlayer (playernum, &playerstarts[playernum]); + return; + } + + // try to spawn at one of the other players spots + for (i=0 ; i" when the player exits the current map + if (nodrawers && (demoplayback || timingdemo)) { + if (gamemode == commercial) + lprintf(LO_INFO, "FINISHED: MAP%02d\n", gamemap); + else + lprintf(LO_INFO, "FINISHED: E%dM%d\n", gameepisode, gamemap); + } + + WI_Start (&wminfo); +} + +// +// G_WorldDone +// + +void G_WorldDone (void) +{ + gameaction = ga_worlddone; + + if (secretexit) + players[consoleplayer].didsecret = true; + + if (gamemode == commercial) + { + switch (gamemap) + { + case 15: + case 31: + if (!secretexit) + break; + case 6: + case 11: + case 20: + case 30: + F_StartFinale (); + break; + } + } + else if (gamemap == 8) + gameaction = ga_victory; // cph - after ExM8 summary screen, show victory stuff +} + +void G_DoWorldDone (void) +{ + idmusnum = -1; //jff 3/17/98 allow new level's music to be loaded + gamestate = GS_LEVEL; + gamemap = wminfo.next+1; + G_DoLoadLevel(); + gameaction = ga_nothing; + AM_clearMarks(); //jff 4/12/98 clear any marks on the automap +} + +// killough 2/28/98: A ridiculously large number +// of players, the most you'll ever need in a demo +// or savegame. This is used to prevent problems, in +// case more players in a game are supported later. + +#define MIN_MAXPLAYERS 32 + +extern boolean setsizeneeded; + +//CPhipps - savename variable redundant + +/* killough 12/98: + * This function returns a signature for the current wad. + * It is used to distinguish between wads, for the purposes + * of savegame compatibility warnings, and options lookups. + */ + +static uint_64_t G_UpdateSignature(uint_64_t s, const char *name) +{ + int i, lump = W_CheckNumForName(name); + if (lump != -1 && (i = lump+10) < numlumps) + do + { + int size = W_LumpLength(i); + const byte *p = W_CacheLumpNum(i); + while (size--) + s <<= 1, s += *p++; + W_UnlockLumpNum(i); + } + while (--i > lump); + return s; +} + +static uint_64_t G_Signature(void) +{ + static uint_64_t s = 0; + static boolean computed = false; + char name[9]; + int episode, map; + + if (!computed) { + computed = true; + if (gamemode == commercial) + for (map = haswolflevels ? 32 : 30; map; map--) + sprintf(name, "map%02d", map), s = G_UpdateSignature(s, name); + else + for (episode = gamemode==retail ? 4 : + gamemode==shareware ? 1 : 3; episode; episode--) + for (map = 9; map; map--) + sprintf(name, "E%dM%d", episode, map), s = G_UpdateSignature(s, name); + } + return s; +} + +// +// killough 5/15/98: add forced loadgames, which allow user to override checks +// + +void G_ForcedLoadGame(void) +{ + // CPhipps - net loadgames are always forced, so we only reach here + // in single player + gameaction = ga_loadgame; + forced_loadgame = true; +} + +// killough 3/16/98: add slot info +// killough 5/15/98: add command-line +void G_LoadGame(int slot, boolean command) +{ + if (!demoplayback && !command) { + // CPhipps - handle savegame filename in G_DoLoadGame + // - Delay load so it can be communicated in net game + // - store info in special_event + special_event = BT_SPECIAL | (BTS_LOADGAME & BT_SPECIALMASK) | + ((slot << BTS_SAVESHIFT) & BTS_SAVEMASK); + forced_loadgame = netgame; // CPhipps - always force load netgames + } else { + // Do the old thing, immediate load + gameaction = ga_loadgame; + forced_loadgame = false; + savegameslot = slot; + demoplayback = false; + // Don't stay in netgame state if loading single player save + // while watching multiplayer demo + netgame = false; + } + command_loadgame = command; + R_SmoothPlaying_Reset(NULL); // e6y +} + +// killough 5/15/98: +// Consistency Error when attempting to load savegame. + +static void G_LoadGameErr(const char *msg) +{ + Z_Free(savebuffer); // Free the savegame buffer + M_ForcedLoadGame(msg); // Print message asking for 'Y' to force + if (command_loadgame) // If this was a command-line -loadgame + { + D_StartTitle(); // Start the title screen + gamestate = GS_DEMOSCREEN; // And set the game state accordingly + } +} + +// CPhipps - size of version header +#define VERSIONSIZE 16 + +const char * comp_lev_str[MAX_COMPATIBILITY_LEVEL] = +{ "doom v1.2", "doom v1.666", "doom/doom2 v1.9", "ultimate doom", "final doom", + "dosdoom compatibility", "tasdoom compatibility", "\"boom compatibility\"", "boom v2.01", "boom v2.02", "lxdoom v1.3.2+", + "MBF", "PrBoom 2.03beta", "PrBoom v2.1.0-2.1.1", "PrBoom v2.1.2-v2.2.6", + "PrBoom v2.3.x", "PrBoom 2.4.0", "Current PrBoom" }; + +// comp_options_by_version removed - see G_Compatibility + +static byte map_old_comp_levels[] = +{ 0, 1, 2, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; + +static const struct { + int comp_level; + const char* ver_printf; + int version; +} version_headers[] = { + /* cph - we don't need a new version_header for prboom_3_comp/v2.1.1, since + * the file format is unchanged. */ + { prboom_3_compatibility, "PrBoom %d", 210}, + { prboom_5_compatibility, "PrBoom %d", 211}, + { prboom_6_compatibility, "PrBoom %d", 212} +}; + +static const size_t num_version_headers = sizeof(version_headers) / sizeof(version_headers[0]); + +void G_DoLoadGame(void) +{ + int length, i; + // CPhipps - do savegame filename stuff here + char name[PATH_MAX+1]; // killough 3/22/98 + int savegame_compatibility = -1; + + G_SaveGameName(name,sizeof(name),savegameslot, demoplayback); + + gameaction = ga_nothing; + + length = M_ReadFile(name, &savebuffer); + if (length<=0) + I_Error("Couldn't read file %s: %s", name, "(Unknown Error)"); + save_p = savebuffer + SAVESTRINGSIZE; + + // CPhipps - read the description field, compare with supported ones + for (i=0; (size_t)i= prboom_4_compatibility) ? *save_p : savegame_compatibility; + if (savegame_compatibility < prboom_6_compatibility) + compatibility_level = map_old_comp_levels[compatibility_level]; + save_p++; + + gameskill = *save_p++; + gameepisode = *save_p++; + gamemap = *save_p++; + + for (i=0 ; i= prboom_2_compatibility) { + memcpy(&totalleveltimes, save_p, sizeof totalleveltimes); + save_p += sizeof totalleveltimes; + } + else totalleveltimes = 0; + + // killough 11/98: load revenant tracer state + basetic = gametic - *save_p++; + + // dearchive all the modifications + P_MapStart(); + P_UnArchivePlayers (); + P_UnArchiveWorld (); + P_UnArchiveThinkers (); + P_UnArchiveSpecials (); + P_UnArchiveRNG (); // killough 1/18/98: load RNG information + P_UnArchiveMap (); // killough 1/22/98: load automap information + P_MapEnd(); + R_SmoothPlaying_Reset(NULL); // e6y + + if (*save_p != 0xe6) + I_Error ("G_DoLoadGame: Bad savegame"); + + // done + Z_Free (savebuffer); + + if (setsizeneeded) + R_ExecuteSetViewSize (); + + // draw the pattern into the back screen + R_FillBackScreen (); + + /* killough 12/98: support -recordfrom and -loadgame -playdemo */ + if (!command_loadgame) + singledemo = false; /* Clear singledemo flag if loading from menu */ + else + if (singledemo) { + gameaction = ga_loadgame; /* Mark that we're loading a game before demo */ + G_DoPlayDemo(); /* This will detect it and won't reinit level */ + } else /* Command line + record means it's a recordfrom */ + if (demorecording) + G_BeginRecording(); +} + +// +// G_SaveGame +// Called by the menu task. +// Description is a 24 byte text string +// + +void G_SaveGame(int slot, char *description) +{ + strcpy(savedescription, description); + if (demoplayback) { + /* cph - We're doing a user-initiated save game while a demo is + * running so, go outside normal mechanisms + */ + savegameslot = slot; + G_DoSaveGame(true); + } + // CPhipps - store info in special_event + special_event = BT_SPECIAL | (BTS_SAVEGAME & BT_SPECIALMASK) | + ((slot << BTS_SAVESHIFT) & BTS_SAVEMASK); +#ifdef HAVE_NET + D_NetSendMisc(nm_savegamename, strlen(savedescription)+1, savedescription); +#endif +} + +// Check for overrun and realloc if necessary -- Lee Killough 1/22/98 +void (CheckSaveGame)(size_t size, const char* file, int line) +{ + size_t pos = save_p - savebuffer; + +#ifdef RANGECHECK + /* cph 2006/08/07 - after-the-fact sanity checking of CheckSaveGame calls */ + static size_t prev_check; + static const char* prevf; + static int prevl; + + if (pos > prev_check) + I_Error("CheckSaveGame at %s:%d called for insufficient buffer (%u < %u)", prevf, prevl, prev_check, pos); + prev_check = size + pos; + prevf = file; + prevl = line; +#endif + + size += 1024; // breathing room + if (pos+size > savegamesize) + save_p = (savebuffer = realloc(savebuffer, + savegamesize += (size+1023) & ~1023)) + pos; +} + +/* killough 3/22/98: form savegame name in one location + * (previously code was scattered around in multiple places) + * cph - Avoid possible buffer overflow problems by passing + * size to this function and using snprintf */ + +void G_SaveGameName(char *name, size_t size, int slot, boolean demoplayback) +{ + const char* sgn = demoplayback ? "demosav" : savegamename; +#ifdef HAVE_SNPRINTF + snprintf (name, size, "%s/%s%d.dsg", basesavegame, sgn, slot); +#else + sprintf (name, "%s/%s%d.dsg", basesavegame, sgn, slot); +#endif +} + +static void G_DoSaveGame (boolean menu) +{ + char name[PATH_MAX+1]; + char name2[VERSIONSIZE]; + char *description; + int length, i; + + gameaction = ga_nothing; // cph - cancel savegame at top of this function, + // in case later problems cause a premature exit + + G_SaveGameName(name,sizeof(name),savegameslot, demoplayback && !menu); + + description = savedescription; + + save_p = savebuffer = malloc(savegamesize); + + CheckSaveGame(SAVESTRINGSIZE+VERSIONSIZE+sizeof(uint_64_t)); + memcpy (save_p, description, SAVESTRINGSIZE); + save_p += SAVESTRINGSIZE; + memset (name2,0,sizeof(name2)); + + // CPhipps - scan for the version header + for (i=0; (size_t)i= prboom_2_compatibility) { + memcpy(save_p, &totalleveltimes, sizeof totalleveltimes); + save_p += sizeof totalleveltimes; + } + else totalleveltimes = 0; + + // killough 11/98: save revenant tracer state + *save_p++ = (gametic-basetic) & 255; + + // killough 3/22/98: add Z_CheckHeap after each call to ensure consistency + Z_CheckHeap(); + P_ArchivePlayers(); + Z_CheckHeap(); + + // phares 9/13/98: Move mobj_t->index out of P_ArchiveThinkers so the + // indices can be used by P_ArchiveWorld when the sectors are saved. + // This is so we can save the index of the mobj_t of the thinker that + // caused a sound, referenced by sector_t->soundtarget. + P_ThinkerToIndex(); + + P_ArchiveWorld(); + Z_CheckHeap(); + P_ArchiveThinkers(); + + // phares 9/13/98: Move index->mobj_t out of P_ArchiveThinkers, simply + // for symmetry with the P_ThinkerToIndex call above. + + P_IndexToThinker(); + + Z_CheckHeap(); + P_ArchiveSpecials(); + P_ArchiveRNG(); // killough 1/18/98: save RNG information + Z_CheckHeap(); + P_ArchiveMap(); // killough 1/22/98: save automap information + + *save_p++ = 0xe6; // consistancy marker + + length = save_p - savebuffer; + + Z_CheckHeap(); + doom_printf( "%s", M_WriteFile(name, savebuffer, length) + ? s_GGSAVED /* Ty - externalised */ + : "Game save failed!"); // CPhipps - not externalised + + free(savebuffer); // killough + savebuffer = save_p = NULL; + + savedescription[0] = 0; +} + +static skill_t d_skill; +static int d_episode; +static int d_map; + +void G_DeferedInitNew(skill_t skill, int episode, int map) +{ + d_skill = skill; + d_episode = episode; + d_map = map; + gameaction = ga_newgame; +} + +/* cph - + * G_Compatibility + * + * Initialises the comp[] array based on the compatibility_level + * For reference, MBF did: + * for (i=0; i < COMP_TOTAL; i++) + * comp[i] = compatibility; + * + * Instead, we have a lookup table showing at what version a fix was + * introduced, and made optional (replaces comp_options_by_version) + */ + +void G_Compatibility(void) +{ + static const struct { + complevel_t fix; // level at which fix/change was introduced + complevel_t opt; // level at which fix/change was made optional + } levels[] = { + // comp_telefrag - monsters used to telefrag only on MAP30, now they do it for spawners only + { mbf_compatibility, mbf_compatibility }, + // comp_dropoff - MBF encourages things to drop off of overhangs + { mbf_compatibility, mbf_compatibility }, + // comp_vile - original Doom archville bugs like ghosts + { boom_compatibility, mbf_compatibility }, + // comp_pain - original Doom limits Pain Elementals from spawning too many skulls + { boom_compatibility, mbf_compatibility }, + // comp_skull - original Doom let skulls be spit through walls by Pain Elementals + { boom_compatibility, mbf_compatibility }, + // comp_blazing - original Doom duplicated blazing door sound + { boom_compatibility, mbf_compatibility }, + // e6y: "Tagged doors don't trigger special lighting" handled wrong + // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943 + // comp_doorlight - MBF made door lighting changes more gradual + { boom_compatibility, mbf_compatibility }, + // comp_model - improvements to the game physics + { boom_compatibility, mbf_compatibility }, + // comp_god - fixes to God mode + { boom_compatibility, mbf_compatibility }, + // comp_falloff - MBF encourages things to drop off of overhangs + { mbf_compatibility, mbf_compatibility }, + // comp_floors - fixes for moving floors bugs + { boom_compatibility_compatibility, mbf_compatibility }, + // comp_skymap + { boom_compatibility, mbf_compatibility }, + // comp_pursuit - MBF AI change, limited pursuit? + { mbf_compatibility, mbf_compatibility }, + // comp_doorstuck - monsters stuck in doors fix + { boom_202_compatibility, mbf_compatibility }, + // comp_staylift - MBF AI change, monsters try to stay on lifts + { mbf_compatibility, mbf_compatibility }, + // comp_zombie - prevent dead players triggering stuff + { lxdoom_1_compatibility, mbf_compatibility }, + // comp_stairs - see p_floor.c + { boom_compatibility_compatibility, mbf_compatibility }, + // comp_infcheat - FIXME + { mbf_compatibility, mbf_compatibility }, + // comp_zerotags - allow zero tags in wads */ + { boom_compatibility, mbf_compatibility }, + // comp_moveblock - enables keygrab and mancubi shots going thru walls + { lxdoom_1_compatibility, prboom_2_compatibility }, + // comp_respawn - objects which aren't on the map at game start respawn at (0,0) + { prboom_2_compatibility, prboom_2_compatibility }, + // comp_sound - see s_sound.c + { boom_compatibility_compatibility, prboom_3_compatibility }, + // comp_666 - enables tag 666 in non-ExM8 levels + { ultdoom_compatibility, prboom_4_compatibility }, + // comp_soul - enables lost souls bouncing (see P_ZMovement) + { prboom_4_compatibility, prboom_4_compatibility }, + // comp_maskedanim - 2s mid textures don't animate + { doom_1666_compatibility, prboom_4_compatibility }, + }; + int i; + + if (sizeof(levels)/sizeof(*levels) != COMP_NUM) + I_Error("G_Compatibility: consistency error"); + + for (i = 0; i < sizeof(levels)/sizeof(*levels); i++) + if (compatibility_level < levels[i].opt) + comp[i] = (compatibility_level < levels[i].fix); + + if (!mbf_features) { + monster_infighting = 1; + monster_backing = 0; + monster_avoid_hazards = 0; + monster_friction = 0; + help_friends = 0; + +#ifdef DOGS + dogs = 0; + dog_jumping = 0; +#endif + + monkeys = 0; + } +} + +#ifdef DOGS +/* killough 7/19/98: Marine's best friend :) */ +static int G_GetHelpers(void) +{ + int j = M_CheckParm ("-dog"); + + if (!j) + j = M_CheckParm ("-dogs"); + return j ? j+1 < myargc ? atoi(myargv[j+1]) : 1 : default_dogs; +} +#endif + +// killough 3/1/98: function to reload all the default parameter +// settings before a new game begins + +void G_ReloadDefaults(void) +{ + // killough 3/1/98: Initialize options based on config file + // (allows functions above to load different values for demos + // and savegames without messing up defaults). + + weapon_recoil = default_weapon_recoil; // weapon recoil + + player_bobbing = default_player_bobbing; // whether player bobs or not + + /* cph 2007/06/31 - for some reason, the default_* of the next 2 vars was never implemented */ + variable_friction = default_variable_friction; + allow_pushers = default_allow_pushers; + + + monsters_remember = default_monsters_remember; // remember former enemies + + monster_infighting = default_monster_infighting; // killough 7/19/98 + +#ifdef DOGS + dogs = netgame ? 0 : G_GetHelpers(); // killough 7/19/98 + dog_jumping = default_dog_jumping; +#endif + + distfriend = default_distfriend; // killough 8/8/98 + + monster_backing = default_monster_backing; // killough 9/8/98 + + monster_avoid_hazards = default_monster_avoid_hazards; // killough 9/9/98 + + monster_friction = default_monster_friction; // killough 10/98 + + help_friends = default_help_friends; // killough 9/9/98 + + monkeys = default_monkeys; + + // jff 1/24/98 reset play mode to command line spec'd version + // killough 3/1/98: moved to here + respawnparm = clrespawnparm; + fastparm = clfastparm; + nomonsters = clnomonsters; + + //jff 3/24/98 set startskill from defaultskill in config file, unless + // it has already been set by a -skill parameter + if (startskill==sk_none) + startskill = (skill_t)(defaultskill-1); + + demoplayback = false; + singledemo = false; // killough 9/29/98: don't stop after 1 demo + netdemo = false; + + // killough 2/21/98: + memset(playeringame+1, 0, sizeof(*playeringame)*(MAXPLAYERS-1)); + + consoleplayer = 0; + + compatibility_level = default_compatibility_level; + { + int i = M_CheckParm("-complevel"); + if (i && (1+i) < myargc) { + int l = atoi(myargv[i+1]);; + if (l >= -1) compatibility_level = l; + } + } + if (compatibility_level == -1) + compatibility_level = best_compatibility; + + if (mbf_features) + memcpy(comp, default_comp, sizeof comp); + G_Compatibility(); + + // killough 3/31/98, 4/5/98: demo sync insurance + demo_insurance = default_demo_insurance == 1; + + rngseed += I_GetRandomTimeSeed() + gametic; // CPhipps +} + +void G_DoNewGame (void) +{ + G_ReloadDefaults(); // killough 3/1/98 + netgame = false; // killough 3/29/98 + deathmatch = false; + G_InitNew (d_skill, d_episode, d_map); + gameaction = ga_nothing; + + //jff 4/26/98 wake up the status bar in case were coming out of a DM demo + ST_Start(); +} + +// killough 4/10/98: New function to fix bug which caused Doom +// lockups when idclev was used in conjunction with -fast. + +void G_SetFastParms(int fast_pending) +{ + static int fast = 0; // remembers fast state + int i; + if (fast != fast_pending) { /* only change if necessary */ + if ((fast = fast_pending)) + { + for (i=S_SARG_RUN1; i<=S_SARG_PAIN2; i++) + if (states[i].tics != 1 || demo_compatibility) // killough 4/10/98 + states[i].tics >>= 1; // don't change 1->0 since it causes cycles + mobjinfo[MT_BRUISERSHOT].speed = 20*FRACUNIT; + mobjinfo[MT_HEADSHOT].speed = 20*FRACUNIT; + mobjinfo[MT_TROOPSHOT].speed = 20*FRACUNIT; + } + else + { + 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; + } + } +} + +// +// G_InitNew +// Can be called by the startup code or the menu task, +// consoleplayer, displayplayer, playeringame[] should be set. +// + +void G_InitNew(skill_t skill, int episode, int map) +{ + int i; + + if (paused) + { + paused = false; + S_ResumeSound(); + } + + if (skill > sk_nightmare) + skill = sk_nightmare; + + if (episode < 1) + episode = 1; + + if (gamemode == retail) + { + if (episode > 4) + episode = 4; + } + else + if (gamemode == shareware) + { + if (episode > 1) + episode = 1; // only start episode 1 on shareware + } + else + if (episode > 3) + episode = 3; + + if (map < 1) + map = 1; + if (map > 9 && gamemode != commercial) + map = 9; + + G_SetFastParms(fastparm || skill == sk_nightmare); // killough 4/10/98 + + M_ClearRandom(); + + respawnmonsters = skill == sk_nightmare || respawnparm; + + // force players to be initialized upon first level load + for (i=0 ; i demobuffer + demolength) + { + lprintf(LO_WARN, "G_ReadDemoTiccmd: missing DEMOMARKER\n"); + G_CheckDemoStatus(); + } + else + { + cmd->forwardmove = ((signed char)*demo_p++); + cmd->sidemove = ((signed char)*demo_p++); + if (!longtics) { + cmd->angleturn = ((unsigned char)(at = *demo_p++))<<8; + } else { + unsigned int lowbyte = (unsigned char)*demo_p++; + cmd->angleturn = (((signed int)(*demo_p++))<<8) + lowbyte; + } + cmd->buttons = (unsigned char)*demo_p++; + // e6y: ability to play tasdoom demos directly + if (compatibility_level == tasdoom_compatibility) + { + signed char k = cmd->forwardmove; + cmd->forwardmove = cmd->sidemove; + cmd->sidemove = (signed char)at; + cmd->angleturn = ((unsigned char)cmd->buttons)<<8; + cmd->buttons = (byte)k; + } + } +} + +/* Demo limits removed -- killough + * cph - record straight to file + */ +void G_WriteDemoTiccmd (ticcmd_t* cmd) +{ + char buf[5]; + char *p = buf; + + *p++ = cmd->forwardmove; + *p++ = cmd->sidemove; + if (!longtics) { + *p++ = (cmd->angleturn+128)>>8; + } else { + signed short a = cmd->angleturn; + *p++ = a & 0xff; + *p++ = (a >> 8) & 0xff; + } + *p++ = cmd->buttons; + if (fwrite(buf, p-buf, 1, demofp) != 1) + I_Error("G_WriteDemoTiccmd: error writing demo"); + + /* cph - alias demo_p to it so we can read it back */ + demo_p = buf; + G_ReadDemoTiccmd (cmd); // make SURE it is exactly the same +} + +// +// G_RecordDemo +// + +void G_RecordDemo (const char* name) +{ + char demoname[PATH_MAX]; + usergame = false; + AddDefaultExtension(strcpy(demoname, name), ".lmp"); // 1/18/98 killough + demorecording = true; + /* cph - Record demos straight to file + * If file already exists, try to continue existing demo + */ + if (access(demoname, F_OK)) { + demofp = fopen(demoname, "wb"); + } else { + demofp = fopen(demoname, "r+"); + if (demofp) { + int slot = -1; + int rc; + int bytes_per_tic; + const byte* pos; + + { /* Read the demo header for options etc */ + byte buf[200]; + size_t len = fread(buf, 1, sizeof(buf), demofp); + pos = G_ReadDemoHeader(buf, len, false); + if (pos) + { + fseek(demofp, pos - buf, SEEK_SET); + } + } + bytes_per_tic = longtics ? 5 : 4; + if (pos) + /* Now read the demo to find the last save slot */ + do { + byte buf[5]; + + rc = fread(buf, 1, bytes_per_tic, demofp); + if (buf[0] == DEMOMARKER) break; + if (buf[bytes_per_tic-1] & BT_SPECIAL) + if ((buf[bytes_per_tic-1] & BT_SPECIALMASK) == BTS_SAVEGAME) + slot = (buf[bytes_per_tic-1] & BTS_SAVEMASK)>>BTS_SAVESHIFT; + } while (rc == bytes_per_tic); + + if (slot == -1) I_Error("G_RecordDemo: No save in demo, can't continue"); + + /* Return to the last save position, and load the relevant savegame */ + fseek(demofp, -rc, SEEK_CUR); + G_LoadGame(slot, false); + autostart = false; + } + } + if (!demofp) I_Error("G_RecordDemo: failed to open %s", name); +} + +// These functions are used to read and write game-specific options in demos +// and savegames so that demo sync is preserved and savegame restoration is +// complete. Not all options (for example "compatibility"), however, should +// be loaded and saved here. It is extremely important to use the same +// positions as before for the variables, so if one becomes obsolete, the +// byte(s) should still be skipped over or padded with 0's. +// Lee Killough 3/1/98 + +extern int forceOldBsp; + +byte *G_WriteOptions(byte *demo_p) +{ + byte *target = demo_p + GAME_OPTION_SIZE; + + *demo_p++ = monsters_remember; // part of monster AI + + *demo_p++ = variable_friction; // ice & mud + + *demo_p++ = weapon_recoil; // weapon recoil + + *demo_p++ = allow_pushers; // MT_PUSH Things + + *demo_p++ = 0; + + *demo_p++ = player_bobbing; // whether player bobs or not + + // killough 3/6/98: add parameters to savegame, move around some in demos + *demo_p++ = respawnparm; + *demo_p++ = fastparm; + *demo_p++ = nomonsters; + + *demo_p++ = demo_insurance; // killough 3/31/98 + + // killough 3/26/98: Added rngseed. 3/31/98: moved here + *demo_p++ = (byte)((rngseed >> 24) & 0xff); + *demo_p++ = (byte)((rngseed >> 16) & 0xff); + *demo_p++ = (byte)((rngseed >> 8) & 0xff); + *demo_p++ = (byte)( rngseed & 0xff); + + // Options new to v2.03 begin here + + *demo_p++ = monster_infighting; // killough 7/19/98 + +#ifdef DOGS + *demo_p++ = dogs; // killough 7/19/98 +#else + *demo_p++ = 0; +#endif + + *demo_p++ = 0; + *demo_p++ = 0; + + *demo_p++ = (distfriend >> 8) & 0xff; // killough 8/8/98 + *demo_p++ = distfriend & 0xff; // killough 8/8/98 + + *demo_p++ = monster_backing; // killough 9/8/98 + + *demo_p++ = monster_avoid_hazards; // killough 9/9/98 + + *demo_p++ = monster_friction; // killough 10/98 + + *demo_p++ = help_friends; // killough 9/9/98 + +#ifdef DOGS + *demo_p++ = dog_jumping; +#else + *demo_p++ = 0; +#endif + + *demo_p++ = monkeys; + + { // killough 10/98: a compatibility vector now + int i; + for (i=0; i < COMP_TOTAL; i++) + *demo_p++ = comp[i] != 0; + } + + *demo_p++ = (compatibility_level >= prboom_2_compatibility) && forceOldBsp; // cph 2002/07/20 + + //---------------- + // Padding at end + //---------------- + while (demo_p < target) + *demo_p++ = 0; + + if (demo_p != target) + I_Error("G_WriteOptions: GAME_OPTION_SIZE is too small"); + + return target; +} + +/* Same, but read instead of write + * cph - const byte*'s + */ + +const byte *G_ReadOptions(const byte *demo_p) +{ + const byte *target = demo_p + GAME_OPTION_SIZE; + + monsters_remember = *demo_p++; + + variable_friction = *demo_p; // ice & mud + demo_p++; + + weapon_recoil = *demo_p; // weapon recoil + demo_p++; + + allow_pushers = *demo_p; // MT_PUSH Things + demo_p++; + + demo_p++; + + player_bobbing = *demo_p; // whether player bobs or not + demo_p++; + + // killough 3/6/98: add parameters to savegame, move from demo + respawnparm = *demo_p++; + fastparm = *demo_p++; + nomonsters = *demo_p++; + + demo_insurance = *demo_p++; // killough 3/31/98 + + // killough 3/26/98: Added rngseed to demos; 3/31/98: moved here + + rngseed = *demo_p++ & 0xff; + rngseed <<= 8; + rngseed += *demo_p++ & 0xff; + rngseed <<= 8; + rngseed += *demo_p++ & 0xff; + rngseed <<= 8; + rngseed += *demo_p++ & 0xff; + + // Options new to v2.03 + if (mbf_features) + { + monster_infighting = *demo_p++; // killough 7/19/98 + +#ifdef DOGS + dogs = *demo_p++; // killough 7/19/98 +#else + demo_p++; +#endif + + demo_p += 2; + + distfriend = *demo_p++ << 8; // killough 8/8/98 + distfriend+= *demo_p++; + + monster_backing = *demo_p++; // killough 9/8/98 + + monster_avoid_hazards = *demo_p++; // killough 9/9/98 + + monster_friction = *demo_p++; // killough 10/98 + + help_friends = *demo_p++; // killough 9/9/98 + +#ifdef DOGS + dog_jumping = *demo_p++; // killough 10/98 +#else + demo_p++; +#endif + + monkeys = *demo_p++; + + { // killough 10/98: a compatibility vector now + int i; + for (i=0; i < COMP_TOTAL; i++) + comp[i] = *demo_p++; + } + + forceOldBsp = *demo_p++; // cph 2002/07/20 + } + else /* defaults for versions <= 2.02 */ + { + /* G_Compatibility will set these */ + } + + G_Compatibility(); + return target; +} + +void G_BeginRecording (void) +{ + int i; + byte *demostart, *demo_p; + demostart = demo_p = malloc(1000); + longtics = 0; + + /* cph - 3 demo record formats supported: MBF+, BOOM, and Doom v1.9 */ + if (mbf_features) { + { /* Write version code into demo */ + unsigned char v; + switch(compatibility_level) { + case mbf_compatibility: v = 203; break; // e6y: Bug in MBF compatibility mode fixed + case prboom_2_compatibility: v = 210; break; + case prboom_3_compatibility: v = 211; break; + case prboom_4_compatibility: v = 212; break; + case prboom_5_compatibility: v = 213; break; + case prboom_6_compatibility: + v = 214; + longtics = 1; + break; + } + *demo_p++ = v; + } + + // signature + *demo_p++ = 0x1d; + *demo_p++ = 'M'; + *demo_p++ = 'B'; + *demo_p++ = 'F'; + *demo_p++ = 0xe6; + *demo_p++ = '\0'; + + /* killough 2/22/98: save compatibility flag in new demos + * cph - FIXME? MBF demos will always be not in compat. mode */ + *demo_p++ = 0; + + *demo_p++ = gameskill; + *demo_p++ = gameepisode; + *demo_p++ = gamemap; + *demo_p++ = deathmatch; + *demo_p++ = consoleplayer; + + demo_p = G_WriteOptions(demo_p); // killough 3/1/98: Save game options + + for (i=0 ; i boom_compatibility_compatibility) { + byte v, c; /* Nominally, version and compatibility bits */ + switch (compatibility_level) { + case boom_compatibility_compatibility: v = 202, c = 1; break; + case boom_201_compatibility: v = 201; c = 0; break; + case boom_202_compatibility: v = 202, c = 0; break; + default: I_Error("G_BeginRecording: Boom compatibility level unrecognised?"); + } + *demo_p++ = v; + + // signature + *demo_p++ = 0x1d; + *demo_p++ = 'B'; + *demo_p++ = 'o'; + *demo_p++ = 'o'; + *demo_p++ = 'm'; + *demo_p++ = 0xe6; + + /* CPhipps - save compatibility level in demos */ + *demo_p++ = c; + + *demo_p++ = gameskill; + *demo_p++ = gameepisode; + *demo_p++ = gamemap; + *demo_p++ = deathmatch; + *demo_p++ = consoleplayer; + + demo_p = G_WriteOptions(demo_p); // killough 3/1/98: Save game options + + for (i=0 ; i=0) + return lev; + } + } + if (ver < 107) return doom_1666_compatibility; + if (gamemode == retail) return ultdoom_compatibility; + if (gamemission >= pack_tnt) return finaldoom_compatibility; + return doom2_19_compatibility; +} + +//e6y: Check for overrun +static boolean CheckForOverrun(const byte *start_p, const byte *current_p, size_t maxsize, size_t size, boolean failonerror) +{ + size_t pos = current_p - start_p; + if (pos + size > maxsize) + { + if (failonerror) + I_Error("G_ReadDemoHeader: wrong demo header\n"); + else + return true; + } + return false; +} + +static const byte* G_ReadDemoHeader(const byte *demo_p, size_t size, boolean failonerror) +{ + skill_t skill; + int i, episode, map; + + // e6y + // The local variable should be used instead of demobuffer, + // because demobuffer can be uninitialized + const byte *header_p = demo_p; + + const byte *option_p = NULL; /* killough 11/98 */ + + basetic = gametic; // killough 9/29/98 + + // killough 2/22/98, 2/28/98: autodetect old demos and act accordingly. + // Old demos turn on demo_compatibility => compatibility; new demos load + // compatibility flag, and other flags as well, as a part of the demo. + + //e6y: check for overrun + if (CheckForOverrun(header_p, demo_p, size, 1, failonerror)) + return NULL; + + demover = *demo_p++; + longtics = 0; + + // e6y + // Handling of unrecognized demo formats + // Versions up to 1.2 use a 7-byte header - first byte is a skill level. + // Versions after 1.2 use a 13-byte header - first byte is a demoversion. + // BOOM's demoversion starts from 200 + if (!((demover >= 0 && demover <= 4) || + (demover >= 104 && demover <= 111) || + (demover >= 200 && demover <= 214))) + { + I_Error("G_ReadDemoHeader: Unknown demo format %d.", demover); + } + + if (demover < 200) // Autodetect old demos + { + if (demover >= 111) longtics = 1; + + // killough 3/2/98: force these variables to be 0 in demo_compatibility + + variable_friction = 0; + + weapon_recoil = 0; + + allow_pushers = 0; + + monster_infighting = 1; // killough 7/19/98 + +#ifdef DOGS + dogs = 0; // killough 7/19/98 + dog_jumping = 0; // killough 10/98 +#endif + + monster_backing = 0; // killough 9/8/98 + + monster_avoid_hazards = 0; // killough 9/9/98 + + monster_friction = 0; // killough 10/98 + help_friends = 0; // killough 9/9/98 + monkeys = 0; + + // killough 3/6/98: rearrange to fix savegame bugs (moved fastparm, + // respawnparm, nomonsters flags to G_LoadOptions()/G_SaveOptions()) + + if ((skill=demover) >= 100) // For demos from versions >= 1.4 + { + //e6y: check for overrun + if (CheckForOverrun(header_p, demo_p, size, 8, failonerror)) + return NULL; + + compatibility_level = G_GetOriginalDoomCompatLevel(demover); + skill = *demo_p++; + episode = *demo_p++; + map = *demo_p++; + deathmatch = *demo_p++; + respawnparm = *demo_p++; + fastparm = *demo_p++; + nomonsters = *demo_p++; + consoleplayer = *demo_p++; + } + else + { + //e6y: check for overrun + if (CheckForOverrun(header_p, demo_p, size, 2, failonerror)) + return NULL; + + compatibility_level = doom_12_compatibility; + episode = *demo_p++; + map = *demo_p++; + deathmatch = respawnparm = fastparm = + nomonsters = consoleplayer = 0; + } + G_Compatibility(); + } + else // new versions of demos + { + demo_p += 6; // skip signature; + switch (demover) { + case 200: /* BOOM */ + case 201: + //e6y: check for overrun + if (CheckForOverrun(header_p, demo_p, size, 1, failonerror)) + return NULL; + + if (!*demo_p++) + compatibility_level = boom_201_compatibility; + else + compatibility_level = boom_compatibility_compatibility; + break; + case 202: + //e6y: check for overrun + if (CheckForOverrun(header_p, demo_p, size, 1, failonerror)) + return NULL; + + if (!*demo_p++) + compatibility_level = boom_202_compatibility; + else + compatibility_level = boom_compatibility_compatibility; + break; + case 203: + /* LxDoom or MBF - determine from signature + * cph - load compatibility level */ + switch (*(header_p + 2)) { + case 'B': /* LxDoom */ + /* cph - DEMOSYNC - LxDoom demos recorded in compatibility modes support dropped */ + compatibility_level = lxdoom_1_compatibility; + break; + case 'M': + compatibility_level = mbf_compatibility; + demo_p++; + break; + } + break; + case 210: + compatibility_level = prboom_2_compatibility; + demo_p++; + break; + case 211: + compatibility_level = prboom_3_compatibility; + demo_p++; + break; + case 212: + compatibility_level = prboom_4_compatibility; + demo_p++; + break; + case 213: + compatibility_level = prboom_5_compatibility; + demo_p++; + break; + case 214: + compatibility_level = prboom_6_compatibility; + longtics = 1; + demo_p++; + break; + } + //e6y: check for overrun + if (CheckForOverrun(header_p, demo_p, size, 5, failonerror)) + return NULL; + + skill = *demo_p++; + episode = *demo_p++; + map = *demo_p++; + deathmatch = *demo_p++; + consoleplayer = *demo_p++; + + /* killough 11/98: save option pointer for below */ + if (mbf_features) + option_p = demo_p; + + //e6y: check for overrun + if (CheckForOverrun(header_p, demo_p, size, GAME_OPTION_SIZE, failonerror)) + return NULL; + + demo_p = G_ReadOptions(demo_p); // killough 3/1/98: Read game options + + if (demover == 200) // killough 6/3/98: partially fix v2.00 demos + demo_p += 256-GAME_OPTION_SIZE; + } + + if (sizeof(comp_lev_str)/sizeof(comp_lev_str[0]) != MAX_COMPATIBILITY_LEVEL) + I_Error("G_ReadDemoHeader: compatibility level strings incomplete"); + lprintf(LO_INFO, "G_DoPlayDemo: playing demo with %s compatibility\n", + comp_lev_str[compatibility_level]); + + if (demo_compatibility) // only 4 players can exist in old demos + { + //e6y: check for overrun + if (CheckForOverrun(header_p, demo_p, size, 4, failonerror)) + return NULL; + + for (i=0; i<4; i++) // intentionally hard-coded 4 -- killough + playeringame[i] = *demo_p++; + for (;i < MAXPLAYERS; i++) + playeringame[i] = 0; + } + else + { + //e6y: check for overrun + if (CheckForOverrun(header_p, demo_p, size, MAXPLAYERS, failonerror)) + return NULL; + + for (i=0 ; i < MAXPLAYERS; i++) + playeringame[i] = *demo_p++; + demo_p += MIN_MAXPLAYERS - MAXPLAYERS; + } + + if (playeringame[1]) + { + netgame = true; + netdemo = true; + } + + if (gameaction != ga_loadgame) { /* killough 12/98: support -loadgame */ + G_InitNew(skill, episode, map); + } + + for (i=0; imessage=... and so I've added this dprintf. +// +// killough 3/6/98: Made limit static to allow z_zone functions to call +// this function, without calling realloc(), which seems to cause problems. + +#define MAX_MESSAGE_SIZE 1024 + +// CPhipps - renamed to doom_printf to avoid name collision with glibc +void doom_printf(const char *s, ...) +{ + static char msg[MAX_MESSAGE_SIZE]; + va_list v; + va_start(v,s); +#ifdef HAVE_VSNPRINTF + vsnprintf(msg,sizeof(msg),s,v); /* print message in buffer */ +#else + vsprintf(msg,s,v); +#endif + va_end(v); + players[consoleplayer].message = msg; // set new message +} diff --git a/src/g_game.h b/src/g_game.h new file mode 100644 index 0000000..274f20e --- /dev/null +++ b/src/g_game.h @@ -0,0 +1,178 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: Main game control interface. + *-----------------------------------------------------------------------------*/ + +#ifndef __G_GAME__ +#define __G_GAME__ + +#include "doomdef.h" +#include "d_event.h" +#include "d_ticcmd.h" + +// +// GAME +// + +// killough 5/2/98: number of bytes reserved for saving options +#define GAME_OPTION_SIZE 64 + +boolean G_Responder(event_t *ev); +boolean G_CheckDemoStatus(void); +void G_DeathMatchSpawnPlayer(int playernum); +void G_InitNew(skill_t skill, int episode, int map); +void G_DeferedInitNew(skill_t skill, int episode, int map); +void G_DeferedPlayDemo(const char *demo); // CPhipps - const +void G_LoadGame(int slot, boolean is_command); // killough 5/15/98 +void G_ForcedLoadGame(void); // killough 5/15/98: forced loadgames +void G_DoLoadGame(void); +void G_SaveGame(int slot, char *description); // Called by M_Responder. +void G_BeginRecording(void); +// CPhipps - const on these string params +void G_RecordDemo(const char *name); // Only called by startup code. +void G_ExitLevel(void); +void G_SecretExitLevel(void); +void G_WorldDone(void); +void G_EndGame(void); /* cph - make m_menu.c call a G_* function for this */ +void G_Ticker(void); +void G_ReloadDefaults(void); // killough 3/1/98: loads game defaults +void G_SaveGameName(char *, size_t, int, boolean); /* killough 3/22/98: sets savegame filename */ +void G_SetFastParms(int); // killough 4/10/98: sets -fast parameters +void G_DoNewGame(void); +void G_DoReborn(int playernum); +void G_DoPlayDemo(void); +void G_DoCompleted(void); +void G_ReadDemoTiccmd(ticcmd_t *cmd); +void G_WriteDemoTiccmd(ticcmd_t *cmd); +void G_DoWorldDone(void); +void G_Compatibility(void); +const byte *G_ReadOptions(const byte *demo_p); /* killough 3/1/98 - cph: const byte* */ +byte *G_WriteOptions(byte *demo_p); // killough 3/1/98 +void G_PlayerReborn(int player); +void G_RestartLevel(void); // CPhipps - menu involked level restart +void G_DoVictory(void); +void G_BuildTiccmd (ticcmd_t* cmd); // CPhipps - move decl to header +void G_ChangedPlayerColour(int pn, int cl); // CPhipps - On-the-fly player colour changing +void G_MakeSpecialEvent(buttoncode_t bc, ...); /* cph - new event stuff */ + +// killough 1/18/98: Doom-style printf; killough 4/25/98: add gcc attributes +// CPhipps - renames to doom_printf to avoid name collision with glibc +void doom_printf(const char *, ...) __attribute__((format(printf,1,2))); + +// killough 5/2/98: moved from m_misc.c: + +extern int key_right; +extern int key_left; +extern int key_up; +extern int key_down; +extern int key_menu_right; // phares 3/7/98 +extern int key_menu_left; // | +extern int key_menu_up; // V +extern int key_menu_down; +extern int key_menu_backspace; // ^ +extern int key_menu_escape; // | +extern int key_menu_enter; // phares 3/7/98 +extern int key_strafeleft; +extern int key_straferight; + +extern int key_fire; +extern int key_use; +extern int key_strafe; +extern int key_speed; +extern int key_escape; // phares +extern int key_savegame; // | +extern int key_loadgame; // V +extern int key_autorun; +extern int key_reverse; +extern int key_zoomin; +extern int key_zoomout; +extern int key_chat; +extern int key_backspace; +extern int key_enter; +extern int key_help; +extern int key_soundvolume; +extern int key_hud; +extern int key_quicksave; +extern int key_endgame; +extern int key_messages; +extern int key_quickload; +extern int key_quit; +extern int key_gamma; +extern int key_spy; +extern int key_pause; +extern int key_setup; +extern int key_forward; +extern int key_leftturn; +extern int key_rightturn; +extern int key_backward; +extern int key_weapontoggle; +extern int key_weapon1; +extern int key_weapon2; +extern int key_weapon3; +extern int key_weapon4; +extern int key_weapon5; +extern int key_weapon6; +extern int key_weapon7; +extern int key_weapon8; +extern int key_weapon9; +extern int destination_keys[MAXPLAYERS]; +extern int key_map_right; +extern int key_map_left; +extern int key_map_up; +extern int key_map_down; +extern int key_map_zoomin; +extern int key_map_zoomout; +extern int key_map; +extern int key_map_gobig; +extern int key_map_follow; +extern int key_map_mark; // ^ +extern int key_map_clear; // | +extern int key_map_grid; // phares +extern int key_map_rotate; // cph - map rotation +extern int key_map_overlay;// cph - map overlay +extern int key_screenshot; // killough 2/22/98 -- add key for screenshot +extern int autorun; // always running? // phares + +extern int defaultskill; //jff 3/24/98 default skill +extern boolean haswolflevels; //jff 4/18/98 wolf levels present + +extern int bodyquesize; // killough 2/8/98: adustable corpse limit + +// killough 5/2/98: moved from d_deh.c: +// Par times (new item with BOOM) - from g_game.c +extern int pars[4][10]; // hardcoded array size +extern int cpars[32]; // hardcoded array size +// CPhipps - Make savedesciption visible in wider scope +#define SAVEDESCLEN 32 +extern char savedescription[SAVEDESCLEN]; // Description to save in savegame + +/* cph - compatibility level strings */ +extern const char * comp_lev_str[]; + +#endif diff --git a/src/hu_lib.c b/src/hu_lib.c new file mode 100644 index 0000000..93c6a62 --- /dev/null +++ b/src/hu_lib.c @@ -0,0 +1,767 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: heads-up text and input code + * + *----------------------------------------------------------------------------- + */ + +#include "doomdef.h" +#include "doomstat.h" +#include "v_video.h" +#include "m_swap.h" +#include "hu_lib.h" +#include "hu_stuff.h" +#include "r_main.h" +#include "r_draw.h" + +// boolean : whether the screen is always erased +#define noterased viewwindowx + +extern int key_backspace; // phares +extern int key_enter; // phares + +// +// not used currently +// code to initialize HUlib would go here if needed +// +static void HUlib_init(void) +{ +} + +//////////////////////////////////////////////////////// +// +// Basic text line widget +// +//////////////////////////////////////////////////////// + +// +// HUlib_clearTextLine() +// +// Blank the internal text line in a hu_textline_t widget +// +// Passed a hu_textline_t, returns nothing +// +void HUlib_clearTextLine(hu_textline_t* t) +{ + t->linelen = // killough 1/23 98: support multiple lines + t->len = 0; + t->l[0] = 0; + t->needsupdate = true; +} + +// +// HUlib_initTextLine() +// +// Initialize a hu_textline_t widget. Set the position, font, start char +// of the font, and color range to be used. +// +// Passed a hu_textline_t, and the values used to initialize +// Returns nothing +// +void HUlib_initTextLine(hu_textline_t* t, int x, int y, + const patchnum_t* f, int sc, int cm ) + //jff 2/16/98 add color range parameter +{ + t->x = x; + t->y = y; + t->f = f; + t->sc = sc; + t->cm = cm; + HUlib_clearTextLine(t); +} + +// +// HUlib_addCharToTextLine() +// +// Adds a character at the end of the text line in a hu_textline_t widget +// +// Passed the hu_textline_t and the char to add +// Returns false if already at length limit, true if the character added +// +boolean HUlib_addCharToTextLine +( hu_textline_t* t, + char ch ) +{ + // killough 1/23/98 -- support multiple lines + if (t->linelen == HU_MAXLINELENGTH) + return false; + else + { + t->linelen++; + if (ch == '\n') + t->linelen=0; + + t->l[t->len++] = ch; + t->l[t->len] = 0; + t->needsupdate = 4; + return true; + } + +} + +// +// HUlib_delCharFromTextLine() +// +// Deletes a character at the end of the text line in a hu_textline_t widget +// +// Passed the hu_textline_t +// Returns false if already empty, true if the character deleted +// +static boolean HUlib_delCharFromTextLine(hu_textline_t* t) +{ + if (!t->len) return false; + else + { + t->l[--t->len] = 0; + t->needsupdate = 4; + return true; + } +} + +// +// HUlib_drawTextLine() +// +// Draws a hu_textline_t widget +// +// Passed the hu_textline_t and flag whether to draw a cursor +// Returns nothing +// +void HUlib_drawTextLine +( hu_textline_t* l, + boolean drawcursor ) +{ + + int i; + int w; + int x; + unsigned char c; + int oc = l->cm; //jff 2/17/98 remember default color + int y = l->y; // killough 1/18/98 -- support multiple lines + + // draw the new stuff + x = l->x; + for (i=0;ilen;i++) + { + c = toupper(l->l[i]); //jff insure were not getting a cheap toupper conv. + + if (c=='\n') // killough 1/18/98 -- support multiple lines + x=0,y+=8; + else if (c=='\t') // killough 1/23/98 -- support tab stops + x=x-x%80+80; + else if (c=='\x1b') //jff 2/17/98 escape code for color change + { //jff 3/26/98 changed to actual escape char + if (++ilen) + if (l->l[i]>='0' && l->l[i]<='9') + l->cm = l->l[i]-'0'; + } + else if (c != ' ' && c >= l->sc && c <= 127) + { + w = l->f[c - l->sc].width; + if (x+w > BASE_WIDTH) + break; + // killough 1/18/98 -- support multiple lines: + // CPhipps - patch drawing updated + V_DrawNumPatch(x, y, FG, l->f[c - l->sc].lumpnum, l->cm, VPT_TRANS | VPT_STRETCH); + x += w; + } + else + { + x += 4; + if (x >= BASE_WIDTH) + break; + } + } + l->cm = oc; //jff 2/17/98 restore original color + + // draw the cursor if requested + if (drawcursor && x + l->f['_' - l->sc].width <= BASE_WIDTH) + { + // killough 1/18/98 -- support multiple lines + // CPhipps - patch drawing updated + V_DrawNumPatch(x, y, FG, l->f['_' - l->sc].lumpnum, CR_DEFAULT, VPT_NONE | VPT_STRETCH); + } +} + +// +// HUlib_eraseTextLine() +// +// Erases a hu_textline_t widget when screen border is behind text +// Sorta called by HU_Erase and just better darn get things straight +// +// Passed the hu_textline_t +// Returns nothing +// +void HUlib_eraseTextLine(hu_textline_t* l) +{ + int lh; + int y; + + // Only erases when NOT in automap and the screen is reduced, + // and the text must either need updating or refreshing + // (because of a recent change back from the automap) + + if (!(automapmode & am_active) && viewwindowx && l->needsupdate) + { + lh = l->f[0].height + 1; + for (y=l->y; yy+lh ; y++) + { + if (y < viewwindowy || y >= viewwindowy + viewheight) + R_VideoErase(0, y, SCREENWIDTH); // erase entire line + else + { + // erase left border + R_VideoErase(0, y, viewwindowx); + // erase right border + R_VideoErase(viewwindowx + viewwidth, y, viewwindowx); + } + } + } + + if (l->needsupdate) l->needsupdate--; +} + +//////////////////////////////////////////////////////// +// +// Player message widget (up to 4 lines of text) +// +//////////////////////////////////////////////////////// + +// +// HUlib_initSText() +// +// Initialize a hu_stext_t widget. Set the position, number of lines, font, +// start char of the font, and color range to be used, and whether enabled. +// +// Passed a hu_stext_t, and the values used to initialize +// Returns nothing +// +void HUlib_initSText +( hu_stext_t* s, + int x, + int y, + int h, + const patchnum_t* font, + int startchar, + int cm, //jff 2/16/98 add color range parameter + boolean* on ) +{ + + int i; + + s->h = h; + s->on = on; + s->laston = true; + s->cl = 0; + for (i=0;il[i], + x, + y - i*(font[0].height+1), + font, + startchar, + cm + ); +} + +// +// HUlib_addLineToSText() +// +// Adds a blank line to a hu_stext_t widget +// +// Passed a hu_stext_t +// Returns nothing +// +static void HUlib_addLineToSText(hu_stext_t* s) +{ + + int i; + + // add a clear line + if (++s->cl == s->h) + s->cl = 0; + HUlib_clearTextLine(&s->l[s->cl]); + + // everything needs updating + for (i=0 ; ih ; i++) + s->l[i].needsupdate = 4; + +} + +// +// HUlib_addMessageToSText() +// +// Adds a message line with prefix to a hu_stext_t widget +// +// Passed a hu_stext_t, the prefix string, and a message string +// Returns nothing +// +void HUlib_addMessageToSText(hu_stext_t* s, const char* prefix, const char* msg) +{ + HUlib_addLineToSText(s); + if (prefix) + while (*prefix) + HUlib_addCharToTextLine(&s->l[s->cl], *(prefix++)); + + while (*msg) + HUlib_addCharToTextLine(&s->l[s->cl], *(msg++)); +} + +// +// HUlib_drawSText() +// +// Displays a hu_stext_t widget +// +// Passed a hu_stext_t +// Returns nothing +// +void HUlib_drawSText(hu_stext_t* s) +{ + int i, idx; + hu_textline_t *l; + + if (!*s->on) + return; // if not on, don't draw + + // draw everything + for (i=0 ; ih ; i++) + { + idx = s->cl - i; + if (idx < 0) + idx += s->h; // handle queue of lines + + l = &s->l[idx]; + + // need a decision made here on whether to skip the draw + HUlib_drawTextLine(l, false); // no cursor, please + } +} + +// +// HUlib_eraseSText() +// +// Erases a hu_stext_t widget, when the screen is not fullsize +// +// Passed a hu_stext_t +// Returns nothing +// +void HUlib_eraseSText(hu_stext_t* s) +{ + int i; + + for (i=0 ; ih ; i++) + { + if (s->laston && !*s->on) + s->l[i].needsupdate = 4; + HUlib_eraseTextLine(&s->l[i]); + } + s->laston = *s->on; +} + +//////////////////////////////////////////////////////// +// +// Scrolling message review widget +// +// jff added 2/26/98 +// +//////////////////////////////////////////////////////// + +// +// HUlib_initMText() +// +// Initialize a hu_mtext_t widget. Set the position, width, number of lines, +// font, start char of the font, color range, background font, and whether +// enabled. +// +// Passed a hu_mtext_t, and the values used to initialize +// Returns nothing +// +void HUlib_initMText(hu_mtext_t *m, int x, int y, int w, int h, + const patchnum_t* font, int startchar, int cm, + const patchnum_t* bgfont, boolean *on) +{ + int i; + + m->nl = 0; + m->nr = 0; + m->cl = -1; //jff 4/28/98 prepare for pre-increment + m->x = x; + m->y = y; + m->w = w; + m->h = h; + m->bg = bgfont; + m->on = on; + for (i=0;il[i], + x, + y + (hud_list_bgon? i+1 : i)*HU_REFRESHSPACING, + font, + startchar, + cm + ); + } +} + +// +// HUlib_addLineToMText() +// +// Adds a blank line to a hu_mtext_t widget +// +// Passed a hu_mtext_t +// Returns nothing +// +static void HUlib_addLineToMText(hu_mtext_t* m) +{ + // add a clear line + if (++m->cl == hud_msg_lines) + m->cl = 0; + HUlib_clearTextLine(&m->l[m->cl]); + + if (m->nlnl++; + + // needs updating + m->l[m->cl].needsupdate = 4; +} + +// +// HUlib_addMessageToMText() +// +// Adds a message line with prefix to a hu_mtext_t widget +// +// Passed a hu_mtext_t, the prefix string, and a message string +// Returns nothing +// +void HUlib_addMessageToMText(hu_mtext_t* m, const char* prefix, const char* msg) +{ + HUlib_addLineToMText(m); + if (prefix) + while (*prefix) + HUlib_addCharToTextLine(&m->l[m->cl], *(prefix++)); + + while (*msg) + HUlib_addCharToTextLine(&m->l[m->cl], *(msg++)); +} + +// +// HUlib_drawMBg() +// +// Draws a background box which the message display review widget can +// display over +// +// Passed position, width, height, and the background patches +// Returns nothing +// +void HUlib_drawMBg +( int x, + int y, + int w, + int h, + const patchnum_t* bgp +) +{ + int xs = bgp[0].width; + int ys = bgp[0].height; + int i,j; + + // CPhipps - patch drawing updated + // top rows + V_DrawNumPatch(x, y, FG, bgp[0].lumpnum, CR_DEFAULT, VPT_STRETCH); // ul + for (j=x+xs;jon) + return; // if not on, don't draw + + // draw everything + if (hud_list_bgon) + HUlib_drawMBg(m->x,m->y,m->w,m->h,m->bg); + y = m->y + HU_REFRESHSPACING; + for (i=0 ; inl ; i++) + { + idx = m->cl - i; + if (idx < 0) + idx += m->nl; // handle queue of lines + + l = &m->l[idx]; + if (hud_list_bgon) + { + l->x = m->x + 4; + l->y = m->y + (i+1)*HU_REFRESHSPACING; + } + else + { + l->x = m->x; + l->y = m->y + i*HU_REFRESHSPACING; + } + + // need a decision made here on whether to skip the draw + HUlib_drawTextLine(l, false); // no cursor, please + } +} + +// +// HUlib_eraseMBg() +// +// Erases background behind hu_mtext_t widget, when the screen is not fullsize +// +// Passed a hu_mtext_t +// Returns nothing +// +static void HUlib_eraseMBg(hu_mtext_t* m) +{ + int lh; + int y; + + // Only erases when NOT in automap and the screen is reduced, + // and the text must either need updating or refreshing + // (because of a recent change back from the automap) + + if (!(automapmode & am_active) && viewwindowx) + { + lh = m->l[0].f[0].height + 1; + for (y=m->y; yy+lh*(hud_msg_lines+2) ; y++) + { + if (y < viewwindowy || y >= viewwindowy + viewheight) + R_VideoErase(0, y, SCREENWIDTH); // erase entire line + else + { + // erase left border + R_VideoErase(0, y, viewwindowx); + // erase right border + R_VideoErase(viewwindowx + viewwidth, y, viewwindowx); + + } + } + } +} + +// +// HUlib_eraseMText() +// +// Erases a hu_mtext_t widget, when the screen is not fullsize +// +// Passed a hu_mtext_t +// Returns nothing +// +void HUlib_eraseMText(hu_mtext_t* m) +{ + int i; + + if (hud_list_bgon) + HUlib_eraseMBg(m); + + for (i=0 ; i< m->nl ; i++) + { + m->l[i].needsupdate = 4; + HUlib_eraseTextLine(&m->l[i]); + } +} + +//////////////////////////////////////////////////////// +// +// Interactive text entry widget +// +//////////////////////////////////////////////////////// + +// +// HUlib_initIText() +// +// Initialize a hu_itext_t widget. Set the position, font, +// start char of the font, color range, and whether enabled. +// +// Passed a hu_itext_t, and the values used to initialize +// Returns nothing +// +void HUlib_initIText +( hu_itext_t* it, + int x, + int y, + const patchnum_t* font, + int startchar, + int cm, //jff 2/16/98 add color range parameter + boolean* on ) +{ + it->lm = 0; // default left margin is start of text + it->on = on; + it->laston = true; + HUlib_initTextLine(&it->l, x, y, font, startchar, cm); +} + +// The following deletion routines adhere to the left margin restriction + +// +// HUlib_delCharFromIText() +// +// Deletes a character at the end of the text line in a hu_itext_t widget +// +// Passed the hu_itext_t +// Returns nothing +// +static void HUlib_delCharFromIText(hu_itext_t* it) +{ + if (it->l.len != it->lm) + HUlib_delCharFromTextLine(&it->l); +} + +// +// HUlib_eraseLineFromIText() +// +// Deletes all characters from a hu_itext_t widget +// +// Passed the hu_itext_t +// Returns nothing +// +static void HUlib_eraseLineFromIText(hu_itext_t* it) +{ + while (it->lm != it->l.len) + HUlib_delCharFromTextLine(&it->l); +} + +// +// HUlib_resetIText() +// +// Deletes all characters from a hu_itext_t widget +// Resets left margin as well +// +// Passed the hu_itext_t +// Returns nothing +// +void HUlib_resetIText(hu_itext_t* it) +{ + it->lm = 0; + HUlib_clearTextLine(&it->l); +} + +// +// HUlib_addPrefixToIText() +// +// Adds a prefix string passed to a hu_itext_t widget +// Sets left margin to length of string added +// +// Passed the hu_itext_t and the prefix string +// Returns nothing +// +void HUlib_addPrefixToIText +( hu_itext_t* it, + char* str ) +{ + while (*str) + HUlib_addCharToTextLine(&it->l, *(str++)); + it->lm = it->l.len; +} + +// +// HUlib_keyInIText() +// +// Wrapper function for handling general keyed input. +// +// Passed the hu_itext_t and the char input +// Returns true if it ate the key +// +boolean HUlib_keyInIText +( hu_itext_t* it, + unsigned char ch ) +{ + + if (ch >= ' ' && ch <= '_') + HUlib_addCharToTextLine(&it->l, (char) ch); + else if (ch == key_backspace) // phares + HUlib_delCharFromIText(it); + else if (ch != key_enter) // phares + return false; // did not eat key + + return true; // ate the key +} + +// +// HUlib_drawIText() +// +// Displays a hu_itext_t widget +// +// Passed the hu_itext_t +// Returns nothing +// +void HUlib_drawIText(hu_itext_t* it) +{ + hu_textline_t *l = &it->l; + + if (!*it->on) + return; + HUlib_drawTextLine(l, true); // draw the line w/ cursor +} + +// +// HUlib_eraseIText() +// +// Erases a hu_itext_t widget when the screen is not fullsize +// +// Passed the hu_itext_t +// Returns nothing +// +void HUlib_eraseIText(hu_itext_t* it) +{ + if (it->laston && !*it->on) + it->l.needsupdate = 4; + HUlib_eraseTextLine(&it->l); + it->laston = *it->on; +} diff --git a/src/hu_lib.h b/src/hu_lib.h new file mode 100644 index 0000000..db17572 --- /dev/null +++ b/src/hu_lib.h @@ -0,0 +1,247 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: none + * + *-----------------------------------------------------------------------------*/ + +#ifndef __HULIB__ +#define __HULIB__ + +// We are referring to patches. +#include "r_defs.h" +#include "v_video.h" //jff 2/16/52 include color range defs + + +/* background and foreground screen numbers + * different from other modules. */ +#define BG 1 +#define FG 0 + +/* font stuff + * #define HU_CHARERASE KEYD_BACKSPACE / not used / phares + */ + +#define HU_MAXLINES 4 +#define HU_MAXLINELENGTH 80 +#define HU_REFRESHSPACING 8 /*jff 2/26/98 space lines in text refresh widget*/ +/*jff 2/26/98 maximum number of messages allowed in refresh list */ +#define HU_MAXMESSAGES 16 + +/* + * Typedefs of widgets + */ + +/* Text Line widget + * (parent of Scrolling Text and Input Text widgets) */ +typedef struct +{ + // left-justified position of scrolling text window + int x; + int y; + + const patchnum_t* f; // font + int sc; // start character + //const char *cr; //jff 2/16/52 output color range + // Proff - Made this an int again. Needed for OpenGL + int cm; //jff 2/16/52 output color range + + // killough 1/23/98: Support multiple lines: + #define MAXLINES 25 + + int linelen; + char l[HU_MAXLINELENGTH*MAXLINES+1]; // line of text + int len; // current line length + + // whether this line needs to be udpated + int needsupdate; + +} hu_textline_t; + + + +// Scrolling Text window widget +// (child of Text Line widget) +typedef struct +{ + hu_textline_t l[HU_MAXLINES]; // text lines to draw + int h; // height in lines + int cl; // current line number + + // pointer to boolean stating whether to update window + boolean* on; + boolean laston; // last value of *->on. + +} hu_stext_t; + +//jff 2/26/98 new widget to display last hud_msg_lines of messages +// Message refresh window widget +typedef struct +{ + hu_textline_t l[HU_MAXMESSAGES]; // text lines to draw + int nl; // height in lines + int nr; // total height in rows + int cl; // current line number + + int x,y,w,h; // window position and size + const patchnum_t *bg; // patches for background + + // pointer to boolean stating whether to update window + boolean* on; + boolean laston; // last value of *->on. + +} hu_mtext_t; + + + +// Input Text Line widget +// (child of Text Line widget) +typedef struct +{ + hu_textline_t l; // text line to input on + + // left margin past which I am not to delete characters + int lm; + + // pointer to boolean stating whether to update window + boolean* on; + boolean laston; // last value of *->on; + +} hu_itext_t; + + +// +// Widget creation, access, and update routines +// + +// +// textline code +// + +// clear a line of text +void HUlib_clearTextLine(hu_textline_t *t); + +void HUlib_initTextLine +( + hu_textline_t *t, + int x, + int y, + const patchnum_t *f, + int sc, + int cm //jff 2/16/98 add color range parameter +); + +// returns success +boolean HUlib_addCharToTextLine(hu_textline_t *t, char ch); + +// draws tline +void HUlib_drawTextLine(hu_textline_t *l, boolean drawcursor); + +// erases text line +void HUlib_eraseTextLine(hu_textline_t *l); + + +// +// Scrolling Text window widget routines +// + +// initialize an stext widget +void HUlib_initSText +( hu_stext_t* s, + int x, + int y, + int h, + const patchnum_t* font, + int startchar, + int cm, //jff 2/16/98 add color range parameter + boolean* on ); + +// add a text message to an stext widget +void HUlib_addMessageToSText(hu_stext_t* s, const char* prefix, const char* msg); + +// draws stext +void HUlib_drawSText(hu_stext_t* s); + +// erases all stext lines +void HUlib_eraseSText(hu_stext_t* s); + +//jff 2/26/98 message refresh widget +// initialize refresh text widget +void HUlib_initMText(hu_mtext_t *m, int x, int y, int w, int h, const patchnum_t* font, + int startchar, int cm, const patchnum_t* bgfont, boolean *on); + +//jff 2/26/98 message refresh widget +// add a text message to refresh text widget +void HUlib_addMessageToMText(hu_mtext_t* m, const char* prefix, const char* msg); + +//jff 2/26/98 new routine to display a background on which +// the list of last hud_msg_lines are displayed +void HUlib_drawMBg +( int x, + int y, + int w, + int h, + const patchnum_t* bgp +); + +//jff 2/26/98 message refresh widget +// draws mtext +void HUlib_drawMText(hu_mtext_t* m); + +//jff 4/28/98 erases behind message list +void HUlib_eraseMText(hu_mtext_t* m); + +// Input Text Line widget routines +void HUlib_initIText +( hu_itext_t* it, + int x, + int y, + const patchnum_t* font, + int startchar, + int cm, //jff 2/16/98 add color range parameter + boolean* on ); + +// resets line and left margin +void HUlib_resetIText(hu_itext_t* it); + +// left of left-margin +void HUlib_addPrefixToIText +( hu_itext_t* it, + char* str ); + +// whether eaten +boolean HUlib_keyInIText +( hu_itext_t* it, + unsigned char ch ); + +void HUlib_drawIText(hu_itext_t* it); + +// erases all itext lines +void HUlib_eraseIText(hu_itext_t* it); + +#endif diff --git a/src/hu_stuff.c b/src/hu_stuff.c new file mode 100644 index 0000000..976bc2e --- /dev/null +++ b/src/hu_stuff.c @@ -0,0 +1,1593 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: Heads-up displays + * + *----------------------------------------------------------------------------- + */ + +// killough 5/3/98: remove unnecessary headers + +#include "doomstat.h" +#include "hu_stuff.h" +#include "hu_lib.h" +#include "st_stuff.h" /* jff 2/16/98 need loc of status bar */ +#include "w_wad.h" +#include "s_sound.h" +#include "dstrings.h" +#include "sounds.h" +#include "d_deh.h" /* Ty 03/27/98 - externalization of mapnamesx arrays */ +#include "g_game.h" +#include "r_main.h" + +// global heads up display controls + +int hud_active; //jff 2/17/98 controls heads-up display mode +int hud_displayed; //jff 2/23/98 turns heads-up display on/off +int hud_nosecrets; //jff 2/18/98 allows secrets line to be disabled in HUD +int hud_distributed; //jff 3/4/98 display HUD in different places on screen +int hud_graph_keys=1; //jff 3/7/98 display HUD keys as graphics + +// +// Locally used constants, shortcuts. +// +// Ty 03/28/98 - +// These four shortcuts modifed to reflect char ** of mapnamesx[] +#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_TITLEHEIGHT 1 +#define HU_TITLEX 0 +//jff 2/16/98 change 167 to ST_Y-1 +// CPhipps - changed to ST_TY +// proff - changed to 200-ST_HEIGHT for stretching +#define HU_TITLEY ((200-ST_HEIGHT) - 1 - hu_font[0].height) + +//jff 2/16/98 add coord text widget coordinates +// proff - changed to SCREENWIDTH to 320 for stretching +#define HU_COORDX (320 - 13*hu_font2['A'-HU_FONTSTART].width) +//jff 3/3/98 split coord widget into three lines in upper right of screen +#define HU_COORDX_Y (1 + 0*hu_font['A'-HU_FONTSTART].height) +#define HU_COORDY_Y (2 + 1*hu_font['A'-HU_FONTSTART].height) +#define HU_COORDZ_Y (3 + 2*hu_font['A'-HU_FONTSTART].height) + +//jff 2/16/98 add ammo, health, armor widgets, 2/22/98 less gap +#define HU_GAPY 8 +#define HU_HUDHEIGHT (6*HU_GAPY) +#define HU_HUDX 2 +#define HU_HUDY (200-HU_HUDHEIGHT-1) +#define HU_MONSECX (HU_HUDX) +#define HU_MONSECY (HU_HUDY+0*HU_GAPY) +#define HU_KEYSX (HU_HUDX) +//jff 3/7/98 add offset for graphic key widget +#define HU_KEYSGX (HU_HUDX+4*hu_font2['A'-HU_FONTSTART].width) +#define HU_KEYSY (HU_HUDY+1*HU_GAPY) +#define HU_WEAPX (HU_HUDX) +#define HU_WEAPY (HU_HUDY+2*HU_GAPY) +#define HU_AMMOX (HU_HUDX) +#define HU_AMMOY (HU_HUDY+3*HU_GAPY) +#define HU_HEALTHX (HU_HUDX) +#define HU_HEALTHY (HU_HUDY+4*HU_GAPY) +#define HU_ARMORX (HU_HUDX) +#define HU_ARMORY (HU_HUDY+5*HU_GAPY) + +//jff 3/4/98 distributed HUD positions +#define HU_HUDX_LL 2 +#define HU_HUDY_LL (200-2*HU_GAPY-1) +// proff/nicolas 09/20/98: Changed for high-res +#define HU_HUDX_LR (320-120) +#define HU_HUDY_LR (200-2*HU_GAPY-1) +// proff/nicolas 09/20/98: Changed for high-res +#define HU_HUDX_UR (320-96) +#define HU_HUDY_UR 2 +#define HU_MONSECX_D (HU_HUDX_LL) +#define HU_MONSECY_D (HU_HUDY_LL+0*HU_GAPY) +#define HU_KEYSX_D (HU_HUDX_LL) +#define HU_KEYSGX_D (HU_HUDX_LL+4*hu_font2['A'-HU_FONTSTART].width) +#define HU_KEYSY_D (HU_HUDY_LL+1*HU_GAPY) +#define HU_WEAPX_D (HU_HUDX_LR) +#define HU_WEAPY_D (HU_HUDY_LR+0*HU_GAPY) +#define HU_AMMOX_D (HU_HUDX_LR) +#define HU_AMMOY_D (HU_HUDY_LR+1*HU_GAPY) +#define HU_HEALTHX_D (HU_HUDX_UR) +#define HU_HEALTHY_D (HU_HUDY_UR+0*HU_GAPY) +#define HU_ARMORX_D (HU_HUDX_UR) +#define HU_ARMORY_D (HU_HUDY_UR+1*HU_GAPY) + +//#define HU_INPUTTOGGLE 't' // not used // phares +#define HU_INPUTX HU_MSGX +#define HU_INPUTY (HU_MSGY + HU_MSGHEIGHT*(hu_font[0].height) +1) +#define HU_INPUTWIDTH 64 +#define HU_INPUTHEIGHT 1 + +#define key_alt KEYD_RALT +#define key_shift KEYD_RSHIFT + +const char* chat_macros[] = +// Ty 03/27/98 - *not* externalized +// CPhipps - const char* +{ + HUSTR_CHATMACRO0, + HUSTR_CHATMACRO1, + HUSTR_CHATMACRO2, + HUSTR_CHATMACRO3, + HUSTR_CHATMACRO4, + HUSTR_CHATMACRO5, + HUSTR_CHATMACRO6, + HUSTR_CHATMACRO7, + HUSTR_CHATMACRO8, + HUSTR_CHATMACRO9 +}; + +const char* player_names[] = +// Ty 03/27/98 - *not* externalized +// CPhipps - const char* +{ + HUSTR_PLRGREEN, + HUSTR_PLRINDIGO, + HUSTR_PLRBROWN, + HUSTR_PLRRED +}; + +//jff 3/17/98 translate player colmap to text color ranges +int plyrcoltran[MAXPLAYERS]={CR_GREEN,CR_GRAY,CR_BROWN,CR_RED}; + +char chat_char; // remove later. +static player_t* plr; + +// font sets +patchnum_t hu_font[HU_FONTSIZE]; +patchnum_t hu_font2[HU_FONTSIZE]; +patchnum_t hu_fontk[HU_FONTSIZE];//jff 3/7/98 added for graphic key indicators +patchnum_t hu_msgbg[9]; //jff 2/26/98 add patches for message background + +// widgets +static hu_textline_t w_title; +static hu_stext_t w_message; +static hu_itext_t w_chat; +static hu_itext_t w_inputbuffer[MAXPLAYERS]; +static hu_textline_t w_coordx; //jff 2/16/98 new coord widget for automap +static hu_textline_t w_coordy; //jff 3/3/98 split coord widgets automap +static hu_textline_t w_coordz; //jff 3/3/98 split coord widgets automap +static hu_textline_t w_ammo; //jff 2/16/98 new ammo widget for hud +static hu_textline_t w_health; //jff 2/16/98 new health widget for hud +static hu_textline_t w_armor; //jff 2/16/98 new armor widget for hud +static hu_textline_t w_weapon; //jff 2/16/98 new weapon widget for hud +static hu_textline_t w_keys; //jff 2/16/98 new keys widget for hud +static hu_textline_t w_gkeys; //jff 3/7/98 graphic keys widget for hud +static hu_textline_t w_monsec; //jff 2/16/98 new kill/secret widget for hud +static hu_mtext_t w_rtext; //jff 2/26/98 text message refresh widget + +static boolean always_off = false; +static char chat_dest[MAXPLAYERS]; +boolean chat_on; +static boolean message_on; +static boolean message_list; //2/26/98 enable showing list of messages +boolean message_dontfuckwithme; +static boolean message_nottobefuckedwith; +static int message_counter; +extern int showMessages; +extern boolean automapactive; +static boolean headsupactive = false; + +//jff 2/16/98 hud supported automap colors added +int hudcolor_titl; // color range of automap level title +int hudcolor_xyco; // color range of new coords on automap +//jff 2/16/98 hud text colors, controls added +int hudcolor_mesg; // color range of scrolling messages +int hudcolor_chat; // color range of chat lines +int hud_msg_lines; // number of message lines in window +//jff 2/26/98 hud text colors, controls added +int hudcolor_list; // list of messages color +int hud_list_bgon; // enable for solid window background for message list + +//jff 2/16/98 initialization strings for ammo, health, armor widgets +static char hud_coordstrx[32]; +static char hud_coordstry[32]; +static char hud_coordstrz[32]; +static char hud_ammostr[80]; +static char hud_healthstr[80]; +static char hud_armorstr[80]; +static char hud_weapstr[80]; +static char hud_keysstr[80]; +static char hud_gkeysstr[80]; //jff 3/7/98 add support for graphic key display +static char hud_monsecstr[80]; + +// +// Builtin map names. +// The actual names can be found in DStrings.h. +// +// Ty 03/27/98 - externalized map name arrays - now in d_deh.c +// and converted to arrays of pointers to char * +// See modified HUTITLEx macros +extern char **mapnames[]; +extern char **mapnames2[]; +extern char **mapnamesp[]; +extern char **mapnamest[]; + +extern int map_point_coordinates; + +// key tables +// jff 5/10/98 french support removed, +// as it was not being used and couldn't be easily tested +// +const char* shiftxform; + +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 +}; + +// +// HU_Init() +// +// Initialize the heads-up display, text that overwrites the primary display +// +// Passed nothing, returns nothing +// +void HU_Init(void) +{ + + int i; + int j; + char buffer[9]; + + shiftxform = english_shiftxform; + + // load the heads-up font + j = HU_FONTSTART; + for (i=0;i122) + { + sprintf(buffer, "STBR%.3d",j); + R_SetPatchNum(&hu_font2[i], buffer); + R_SetPatchNum(&hu_font[i], buffer); + } + else + hu_font[i] = hu_font[0]; //jff 2/16/98 account for gap + } + + // CPhipps - load patches for message background + for (i=0; i<9; i++) { + sprintf(buffer, "BOX%c%c", "UCL"[i/3], "LCR"[i%3]); + R_SetPatchNum(&hu_msgbg[i], buffer); + } + + // CPhipps - load patches for keys and double keys + for (i=0; i<6; i++) { + sprintf(buffer, "STKEYS%d", i); + R_SetPatchNum(&hu_fontk[i], buffer); + } +} + +// +// HU_Stop() +// +// Make the heads-up displays inactive +// +// Passed nothing, returns nothing +// +static void HU_Stop(void) +{ + headsupactive = false; +} + +// +// HU_Start(void) +// +// Create and initialize the heads-up widgets, software machines to +// maintain, update, and display information over the primary display +// +// This routine must be called after any change to the heads up configuration +// in order for the changes to take effect in the actual displays +// +// Passed nothing, returns nothing +// +void HU_Start(void) +{ + + int i; + const char* s; /* cph - const */ + + if (headsupactive) // stop before starting + HU_Stop(); + + plr = &players[displayplayer]; // killough 3/7/98 + message_on = false; + message_dontfuckwithme = false; + message_nottobefuckedwith = false; + chat_on = false; + + // create the message widget + // messages to player in upper-left of screen + HUlib_initSText + ( + &w_message, + HU_MSGX, + HU_MSGY, + HU_MSGHEIGHT, + hu_font, + HU_FONTSTART, + hudcolor_mesg, + &message_on + ); + + //jff 2/16/98 added some HUD widgets + // create the map title widget - map title display in lower left of automap + HUlib_initTextLine + ( + &w_title, + HU_TITLEX, + HU_TITLEY, + hu_font, + HU_FONTSTART, + hudcolor_titl + ); + + // create the hud health widget + // bargraph and number for amount of health, + // lower left or upper right of screen + HUlib_initTextLine + ( + &w_health, + hud_distributed? HU_HEALTHX_D : HU_HEALTHX, //3/4/98 distribute + hud_distributed? HU_HEALTHY_D : HU_HEALTHY, + hu_font2, + HU_FONTSTART, + CR_GREEN + ); + + // create the hud armor widget + // bargraph and number for amount of armor, + // lower left or upper right of screen + HUlib_initTextLine + ( + &w_armor, + hud_distributed? HU_ARMORX_D : HU_ARMORX, //3/4/98 distribute + hud_distributed? HU_ARMORY_D : HU_ARMORY, + hu_font2, + HU_FONTSTART, + CR_GREEN + ); + + // create the hud ammo widget + // bargraph and number for amount of ammo for current weapon, + // lower left or lower right of screen + HUlib_initTextLine + ( + &w_ammo, + hud_distributed? HU_AMMOX_D : HU_AMMOX, //3/4/98 distribute + hud_distributed? HU_AMMOY_D : HU_AMMOY, + hu_font2, + HU_FONTSTART, + CR_GOLD + ); + + // create the hud weapons widget + // list of numbers of weapons possessed + // lower left or lower right of screen + HUlib_initTextLine + ( + &w_weapon, + hud_distributed? HU_WEAPX_D : HU_WEAPX, //3/4/98 distribute + hud_distributed? HU_WEAPY_D : HU_WEAPY, + hu_font2, + HU_FONTSTART, + CR_GRAY + ); + + // create the hud keys widget + // display of key letters possessed + // lower left of screen + HUlib_initTextLine + ( + &w_keys, + hud_distributed? HU_KEYSX_D : HU_KEYSX, //3/4/98 distribute + hud_distributed? HU_KEYSY_D : HU_KEYSY, + hu_font2, + HU_FONTSTART, + CR_GRAY + ); + + // create the hud graphic keys widget + // display of key graphics possessed + // lower left of screen + HUlib_initTextLine + ( + &w_gkeys, + hud_distributed? HU_KEYSGX_D : HU_KEYSGX, //3/4/98 distribute + hud_distributed? HU_KEYSY_D : HU_KEYSY, + hu_fontk, + HU_FONTSTART, + CR_RED + ); + + // create the hud monster/secret widget + // totals and current values for kills, items, secrets + // lower left of screen + HUlib_initTextLine + ( + &w_monsec, + hud_distributed? HU_MONSECX_D : HU_MONSECX, //3/4/98 distribute + hud_distributed? HU_MONSECY_D : HU_MONSECY, + hu_font2, + HU_FONTSTART, + CR_GRAY + ); + + // create the hud text refresh widget + // scrolling display of last hud_msg_lines messages received + if (hud_msg_lines>HU_MAXMESSAGES) + hud_msg_lines=HU_MAXMESSAGES; + //jff 4/21/98 if setup has disabled message list while active, turn it off + message_list = hud_msg_lines > 1; //jff 8/8/98 initialize both ways + //jff 2/26/98 add the text refresh widget initialization + HUlib_initMText + ( + &w_rtext, + 0, + 0, + 320, +// SCREENWIDTH, + (hud_msg_lines+2)*HU_REFRESHSPACING, + hu_font, + HU_FONTSTART, + hudcolor_list, + hu_msgbg, + &message_list + ); + + // initialize the automap's level title widget + if (gamestate == GS_LEVEL) /* cph - stop SEGV here when not in level */ + switch (gamemode) + { + case shareware: + case registered: + case retail: + s = HU_TITLE; + break; + + case commercial: + default: // Ty 08/27/98 - modified to check mission for TNT/Plutonia + s = (gamemission==pack_tnt) ? HU_TITLET : + (gamemission==pack_plut) ? HU_TITLEP : HU_TITLE2; + break; + } else s = ""; + while (*s) + HUlib_addCharToTextLine(&w_title, *(s++)); + + // create the automaps coordinate widget + // jff 3/3/98 split coord widget into three lines: x,y,z + // jff 2/16/98 added + HUlib_initTextLine + ( + &w_coordx, + HU_COORDX, + HU_COORDX_Y, + hu_font, + HU_FONTSTART, + hudcolor_xyco + ); + HUlib_initTextLine + ( + &w_coordy, + HU_COORDX, + HU_COORDY_Y, + hu_font, + HU_FONTSTART, + hudcolor_xyco + ); + HUlib_initTextLine + ( + &w_coordz, + HU_COORDX, + HU_COORDZ_Y, + hu_font, + HU_FONTSTART, + hudcolor_xyco + ); + + // initialize the automaps coordinate widget + //jff 3/3/98 split coordstr widget into 3 parts + if (map_point_coordinates) + { + sprintf(hud_coordstrx,"X: %-5d",0); //jff 2/22/98 added z + s = hud_coordstrx; + while (*s) + HUlib_addCharToTextLine(&w_coordx, *(s++)); + sprintf(hud_coordstry,"Y: %-5d",0); //jff 3/3/98 split x,y,z + s = hud_coordstry; + while (*s) + HUlib_addCharToTextLine(&w_coordy, *(s++)); + sprintf(hud_coordstrz,"Z: %-5d",0); //jff 3/3/98 split x,y,z + s = hud_coordstrz; + while (*s) + HUlib_addCharToTextLine(&w_coordz, *(s++)); + } + + //jff 2/16/98 initialize ammo widget + strcpy(hud_ammostr,"AMM "); + s = hud_ammostr; + while (*s) + HUlib_addCharToTextLine(&w_ammo, *(s++)); + + //jff 2/16/98 initialize health widget + strcpy(hud_healthstr,"HEL "); + s = hud_healthstr; + while (*s) + HUlib_addCharToTextLine(&w_health, *(s++)); + + //jff 2/16/98 initialize armor widget + strcpy(hud_armorstr,"ARM "); + s = hud_armorstr; + while (*s) + HUlib_addCharToTextLine(&w_armor, *(s++)); + + //jff 2/17/98 initialize weapons widget + strcpy(hud_weapstr,"WEA "); + s = hud_weapstr; + while (*s) + HUlib_addCharToTextLine(&w_weapon, *(s++)); + + //jff 2/17/98 initialize keys widget + if (!deathmatch) //jff 3/17/98 show frags in deathmatch mode + strcpy(hud_keysstr,"KEY "); + else + strcpy(hud_keysstr,"FRG "); + s = hud_keysstr; + while (*s) + HUlib_addCharToTextLine(&w_keys, *(s++)); + + //jff 2/17/98 initialize graphic keys widget + strcpy(hud_gkeysstr," "); + s = hud_gkeysstr; + while (*s) + HUlib_addCharToTextLine(&w_gkeys, *(s++)); + + //jff 2/17/98 initialize kills/items/secret widget + strcpy(hud_monsecstr,"STS "); + s = hud_monsecstr; + while (*s) + HUlib_addCharToTextLine(&w_monsec, *(s++)); + + // create the chat widget + HUlib_initIText + ( + &w_chat, + HU_INPUTX, + HU_INPUTY, + hu_font, + HU_FONTSTART, + hudcolor_chat, + &chat_on + ); + + // create the inputbuffer widgets, one per player + for (i=0 ; imo->x)>>FRACBITS); + HUlib_clearTextLine(&w_coordx); + s = hud_coordstrx; + while (*s) + HUlib_addCharToTextLine(&w_coordx, *(s++)); + HUlib_drawTextLine(&w_coordx, false); + + //jff 3/3/98 split coord display into x,y,z lines + // y-coord + sprintf(hud_coordstry,"Y: %-5d", (plr->mo->y)>>FRACBITS); + HUlib_clearTextLine(&w_coordy); + s = hud_coordstry; + while (*s) + HUlib_addCharToTextLine(&w_coordy, *(s++)); + HUlib_drawTextLine(&w_coordy, false); + + //jff 3/3/98 split coord display into x,y,z lines + //jff 2/22/98 added z + // z-coord + sprintf(hud_coordstrz,"Z: %-5d", (plr->mo->z)>>FRACBITS); + HUlib_clearTextLine(&w_coordz); + s = hud_coordstrz; + while (*s) + HUlib_addCharToTextLine(&w_coordz, *(s++)); + HUlib_drawTextLine(&w_coordz, false); + } + } + + // draw the weapon/health/ammo/armor/kills/keys displays if optioned + //jff 2/17/98 allow new hud stuff to be turned off + // killough 2/21/98: really allow new hud stuff to be turned off COMPLETELY + if + ( + hud_active>0 && // hud optioned on + hud_displayed && // hud on from fullscreen key + viewheight==SCREENHEIGHT && // fullscreen mode is active + !(automapmode & am_active) // automap is not active + ) + { + doit = !(gametic&1); //jff 3/4/98 speed update up for slow systems + if (doit) //jff 8/7/98 update every time, avoid lag in update + { + HU_MoveHud(); // insure HUD display coords are correct + + // do the hud ammo display + // clear the widgets internal line + HUlib_clearTextLine(&w_ammo); + strcpy(hud_ammostr,"AMM "); + if (weaponinfo[plr->readyweapon].ammo == am_noammo) + { // special case for weapon with no ammo selected - blank bargraph + N/A + strcat(hud_ammostr,"\x7f\x7f\x7f\x7f\x7f\x7f\x7f N/A"); + w_ammo.cm = CR_GRAY; + } + else + { + int ammo = plr->ammo[weaponinfo[plr->readyweapon].ammo]; + int fullammo = plr->maxammo[weaponinfo[plr->readyweapon].ammo]; + int ammopct = (100*ammo)/fullammo; + int ammobars = ammopct/4; + + // build the numeric amount init string + sprintf(ammostr,"%d/%d",ammo,fullammo); + // build the bargraph string + // full bargraph chars + for (i=4;i<4+ammobars/4;) + hud_ammostr[i++] = 123; + // plus one last character with 0,1,2,3 bars + switch(ammobars%4) + { + case 0: + break; + case 1: + hud_ammostr[i++] = 126; + break; + case 2: + hud_ammostr[i++] = 125; + break; + case 3: + hud_ammostr[i++] = 124; + break; + } + // pad string with blank bar characters + while(i<4+7) + hud_ammostr[i++] = 127; + hud_ammostr[i] = '\0'; + strcat(hud_ammostr,ammostr); + + // set the display color from the percentage of total ammo held + if (ammopcthealth; + int healthbars = health>100? 25 : health/4; + + // clear the widgets internal line + HUlib_clearTextLine(&w_health); + + // build the numeric amount init string + sprintf(healthstr,"%3d",health); + // build the bargraph string + // full bargraph chars + for (i=4;i<4+healthbars/4;) + hud_healthstr[i++] = 123; + // plus one last character with 0,1,2,3 bars + switch(healthbars%4) + { + case 0: + break; + case 1: + hud_healthstr[i++] = 126; + break; + case 2: + hud_healthstr[i++] = 125; + break; + case 3: + hud_healthstr[i++] = 124; + break; + } + // pad string with blank bar characters + while(i<4+7) + hud_healthstr[i++] = 127; + hud_healthstr[i] = '\0'; + strcat(hud_healthstr,healthstr); + + // set the display color from the amount of health posessed + if (healtharmorpoints; + int armorbars = armor>100? 25 : armor/4; + + // clear the widgets internal line + HUlib_clearTextLine(&w_armor); + // build the numeric amount init string + sprintf(armorstr,"%3d",armor); + // build the bargraph string + // full bargraph chars + for (i=4;i<4+armorbars/4;) + hud_armorstr[i++] = 123; + // plus one last character with 0,1,2,3 bars + switch(armorbars%4) + { + case 0: + break; + case 1: + hud_armorstr[i++] = 126; + break; + case 2: + hud_armorstr[i++] = 125; + break; + case 3: + hud_armorstr[i++] = 124; + break; + } + // pad string with blank bar characters + while(i<4+7) + hud_armorstr[i++] = 127; + hud_armorstr[i] = '\0'; + strcat(hud_armorstr,armorstr); + + // set the display color from the amount of armor posessed + if (armor=wp_plasma && w!=wp_chainsaw) + ok=0; + break; + case retail: + case registered: + if (w>=wp_supershotgun) + ok=0; + break; + default: + case commercial: + break; + } + if (!ok) continue; + + ammo = plr->ammo[weaponinfo[w].ammo]; + fullammo = plr->maxammo[weaponinfo[w].ammo]; + ammopct=0; + + // skip weapons not currently posessed + if (!plr->weaponowned[w]) + continue; + + ammopct = fullammo? (100*ammo)/fullammo : 100; + + // display each weapon number in a color related to the ammo for it + hud_weapstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + if (weaponinfo[w].ammo==am_noammo) //jff 3/14/98 show berserk on HUD + hud_weapstr[i++] = plr->powers[pw_strength]? '0'+CR_GREEN : '0'+CR_GRAY; + else if (ammopct1) + { + int k; + + hud_keysstr[4] = '\0'; //jff 3/7/98 make sure deleted keys go away + //jff add case for graphic key display + if (!deathmatch && hud_graph_keys) + { + i=0; + hud_gkeysstr[i] = '\0'; //jff 3/7/98 init graphic keys widget string + // build text string whose characters call out graphic keys from fontk + for (k=0;k<6;k++) + { + // skip keys not possessed + if (!plr->cards[k]) + continue; + + hud_gkeysstr[i++] = '!'+k; // key number plus '!' is char for key + hud_gkeysstr[i++] = ' '; // spacing + hud_gkeysstr[i++] = ' '; + } + hud_gkeysstr[i]='\0'; + } + else // not possible in current code, unless deathmatching, + { + i=4; + hud_keysstr[i] = '\0'; //jff 3/7/98 make sure deleted keys go away + + // if deathmatch, build string showing top four frag counts + if (deathmatch) //jff 3/17/98 show frags, not keys, in deathmatch + { + int top1=-999,top2=-999,top3=-999,top4=-999; + int idx1=-1,idx2=-1,idx3=-1,idx4=-1; + int fragcount,m; + char numbuf[32]; + + // scan thru players + for (k=0;ktop1) + { + top4=top3; top3=top2; top2 = top1; top1=fragcount; + idx4=idx3; idx3=idx2; idx2 = idx1; idx1=k; + } + else if (fragcount>top2) + { + top4=top3; top3=top2; top2=fragcount; + idx4=idx3; idx3=idx2; idx2=k; + } + else if (fragcount>top3) + { + top4=top3; top3=fragcount; + idx4=idx3; idx3=k; + } + else if (fragcount>top4) + { + top4=fragcount; + idx4=k; + } + } + // if the biggest number exists, put it in the init string + if (idx1>-1) + { + sprintf(numbuf,"%5d",top1); + // make frag count in player's color via escape code + hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + hud_keysstr[i++] = '0'+plyrcoltran[idx1&3]; + s = numbuf; + while (*s) + hud_keysstr[i++] = *(s++); + } + // if the second biggest number exists, put it in the init string + if (idx2>-1) + { + sprintf(numbuf,"%5d",top2); + // make frag count in player's color via escape code + hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + hud_keysstr[i++] = '0'+plyrcoltran[idx2&3]; + s = numbuf; + while (*s) + hud_keysstr[i++] = *(s++); + } + // if the third biggest number exists, put it in the init string + if (idx3>-1) + { + sprintf(numbuf,"%5d",top3); + // make frag count in player's color via escape code + hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + hud_keysstr[i++] = '0'+plyrcoltran[idx3&3]; + s = numbuf; + while (*s) + hud_keysstr[i++] = *(s++); + } + // if the fourth biggest number exists, put it in the init string + if (idx4>-1) + { + sprintf(numbuf,"%5d",top4); + // make frag count in player's color via escape code + hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + hud_keysstr[i++] = '0'+plyrcoltran[idx4&3]; + s = numbuf; + while (*s) + hud_keysstr[i++] = *(s++); + } + hud_keysstr[i] = '\0'; + } //jff 3/17/98 end of deathmatch clause + else // build alphabetical key display (not used currently) + { + // scan the keys + for (k=0;k<6;k++) + { + // skip any not possessed by the displayed player's stats + if (!plr->cards[k]) + continue; + + // use color escapes to make text in key's color + hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths + switch(k) + { + case 0: + hud_keysstr[i++] = '0'+CR_BLUE; + hud_keysstr[i++] = 'B'; + hud_keysstr[i++] = 'C'; + hud_keysstr[i++] = ' '; + break; + case 1: + hud_keysstr[i++] = '0'+CR_GOLD; + hud_keysstr[i++] = 'Y'; + hud_keysstr[i++] = 'C'; + hud_keysstr[i++] = ' '; + break; + case 2: + hud_keysstr[i++] = '0'+CR_RED; + hud_keysstr[i++] = 'R'; + hud_keysstr[i++] = 'C'; + hud_keysstr[i++] = ' '; + break; + case 3: + hud_keysstr[i++] = '0'+CR_BLUE; + hud_keysstr[i++] = 'B'; + hud_keysstr[i++] = 'S'; + hud_keysstr[i++] = ' '; + break; + case 4: + hud_keysstr[i++] = '0'+CR_GOLD; + hud_keysstr[i++] = 'Y'; + hud_keysstr[i++] = 'S'; + hud_keysstr[i++] = ' '; + break; + case 5: + hud_keysstr[i++] = '0'+CR_RED; + hud_keysstr[i++] = 'R'; + hud_keysstr[i++] = 'S'; + hud_keysstr[i++] = ' '; + break; + } + hud_keysstr[i]='\0'; + } + } + } + } + // display the keys/frags line each frame + if (hud_active>1) + { + HUlib_clearTextLine(&w_keys); // clear the widget strings + HUlib_clearTextLine(&w_gkeys); + + // transfer the built string (frags or key title) to the widget + s = hud_keysstr; //jff 3/7/98 display key titles/key text or frags + while (*s) + HUlib_addCharToTextLine(&w_keys, *(s++)); + HUlib_drawTextLine(&w_keys, false); + + //jff 3/17/98 show graphic keys in non-DM only + if (!deathmatch) //jff 3/7/98 display graphic keys + { + // transfer the graphic key text to the widget + s = hud_gkeysstr; + while (*s) + HUlib_addCharToTextLine(&w_gkeys, *(s++)); + // display the widget + HUlib_drawTextLine(&w_gkeys, false); + } + } + + // display the hud kills/items/secret display if optioned + if (!hud_nosecrets) + { + if (hud_active>1 && doit) + { + // clear the internal widget text buffer + HUlib_clearTextLine(&w_monsec); + //jff 3/26/98 use ESC not '\' for paths + // build the init string with fixed colors + sprintf + ( + hud_monsecstr, + "STS \x1b\x36K \x1b\x33%d \x1b\x36M \x1b\x33%d \x1b\x37I \x1b\x33%d/%d \x1b\x35S \x1b\x33%d/%d", + plr->killcount,totallive, + plr->itemcount,totalitems, + plr->secretcount,totalsecret + ); + // transfer the init string to the widget + s = hud_monsecstr; + while (*s) + HUlib_addCharToTextLine(&w_monsec, *(s++)); + } + // display the kills/items/secrets each frame, if optioned + if (hud_active>1) + HUlib_drawTextLine(&w_monsec, false); + } + } + + //jff 3/4/98 display last to give priority + HU_Erase(); // jff 4/24/98 Erase current lines before drawing current + // needed when screen not fullsize + + //jff 4/21/98 if setup has disabled message list while active, turn it off + if (hud_msg_lines<=1) + message_list = false; + + // if the message review not enabled, show the standard message widget + if (!message_list) + HUlib_drawSText(&w_message); + + // if the message review is enabled show the scrolling message review + if (hud_msg_lines>1 && message_list) + HUlib_drawMText(&w_rtext); + + // display the interactive buffer for chat entry + HUlib_drawIText(&w_chat); +} + +// +// HU_Erase() +// +// Erase hud display lines that can be trashed by small screen display +// +// Passed nothing, returns nothing +// +void HU_Erase(void) +{ + // erase the message display or the message review display + if (!message_list) + HUlib_eraseSText(&w_message); + else + HUlib_eraseMText(&w_rtext); + + // erase the interactive text buffer for chat entry + HUlib_eraseIText(&w_chat); + + // erase the automap title + HUlib_eraseTextLine(&w_title); +} + +// +// HU_Ticker() +// +// Update the hud displays once per frame +// +// Passed nothing, returns nothing +// +static boolean bsdown; // Is backspace down? +static int bscounter; + +void HU_Ticker(void) +{ + int i, rc; + char c; + + // tick down message counter if message is up + if (message_counter && !--message_counter) + { + message_on = false; + message_nottobefuckedwith = false; + } + if (bsdown && bscounter++ > 9) { + HUlib_keyInIText(&w_chat, (unsigned char)key_backspace); + bscounter = 8; + } + + // if messages on, or "Messages Off" is being displayed + // this allows the notification of turning messages off to be seen + if (showMessages || message_dontfuckwithme) + { + // display message if necessary + if ((plr->message && !message_nottobefuckedwith) + || (plr->message && message_dontfuckwithme)) + { + //post the message to the message widget + HUlib_addMessageToSText(&w_message, 0, plr->message); + //jff 2/26/98 add message to refresh text widget too + HUlib_addMessageToMText(&w_rtext, 0, plr->message); + + // clear the message to avoid posting multiple times + plr->message = 0; + // note a message is displayed + message_on = true; + // start the message persistence counter + message_counter = HU_MSGTIMEOUT; + // transfer "Messages Off" exception to the "being displayed" variable + message_nottobefuckedwith = message_dontfuckwithme; + // clear the flag that "Messages Off" is being posted + message_dontfuckwithme = 0; + } + } + + // check for incoming chat characters + if (netgame) + { + for (i=0; i= 'a' && c <= 'z') + c = (char) shiftxform[(unsigned char) c]; + rc = HUlib_keyInIText(&w_inputbuffer[i], c); + if (rc && c == KEYD_ENTER) + { + if (w_inputbuffer[i].l.len + && (chat_dest[i] == consoleplayer+1 + || chat_dest[i] == HU_BROADCAST)) + { + HUlib_addMessageToSText(&w_message, + player_names[i], + w_inputbuffer[i].l.l); + + message_nottobefuckedwith = true; + message_on = true; + message_counter = HU_MSGTIMEOUT; + if ( gamemode == commercial ) + S_StartSound(0, sfx_radio); + else + S_StartSound(0, sfx_tink); + } + HUlib_resetIText(&w_inputbuffer[i]); + } + } + players[i].cmd.chatchar = 0; + } + } + } +} + +#define QUEUESIZE 128 + +static char chatchars[QUEUESIZE]; +static int head = 0; +static int tail = 0; + +// +// HU_queueChatChar() +// +// Add an incoming character to the circular chat queue +// +// Passed the character to queue, returns nothing +// +static void HU_queueChatChar(char c) +{ + if (((head + 1) & (QUEUESIZE-1)) == tail) + { + plr->message = HUSTR_MSGU; + } + else + { + chatchars[head] = c; + head = (head + 1) & (QUEUESIZE-1); + } +} + +// +// HU_dequeueChatChar() +// +// Remove the earliest added character from the circular chat queue +// +// Passed nothing, returns the character dequeued +// +char HU_dequeueChatChar(void) +{ + char c; + + if (head != tail) + { + c = chatchars[tail]; + tail = (tail + 1) & (QUEUESIZE-1); + } + else + { + c = 0; + } + return c; +} + +// +// HU_Responder() +// +// Responds to input events that affect the heads up displays +// +// Passed the event to respond to, returns true if the event was handled +// +boolean HU_Responder(event_t *ev) +{ + + static char lastmessage[HU_MAXLINELENGTH+1]; + const char* macromessage; // CPhipps - const char* + boolean eatkey = false; + static boolean shiftdown = false; + static boolean altdown = false; + unsigned char c; + int i; + int numplayers; + + static int num_nobrainers = 0; + + numplayers = 0; + for (i=0 ; idata1 == key_shift) + { + shiftdown = ev->type == ev_keydown; + return false; + } + else if (ev->data1 == key_alt) + { + altdown = ev->type == ev_keydown; + return false; + } + else if (ev->data1 == key_backspace) + { + bsdown = ev->type == ev_keydown; + bscounter = 0; + } + + if (ev->type != ev_keydown) + return false; + + if (!chat_on) + { + if (ev->data1 == key_enter) // phares + { +#ifndef INSTRUMENTED // never turn on message review if INSTRUMENTED defined + if (hud_msg_lines>1) // it posts multi-line messages that will trash + { + if (message_list) HU_Erase(); //jff 4/28/98 erase behind messages + message_list = !message_list; //jff 2/26/98 toggle list of messages + } +#endif + if (!message_list) // if not message list, refresh message + { + message_on = true; + message_counter = HU_MSGTIMEOUT; + } + eatkey = true; + }//jff 2/26/98 no chat if message review is displayed + // killough 10/02/98: no chat if demo playback + // no chat in -solo-net mode + else if (!demoplayback && !message_list && netgame && numplayers > 1) + { + if (ev->data1 == key_chat) + { + eatkey = chat_on = true; + HUlib_resetIText(&w_chat); + HU_queueChatChar(HU_BROADCAST); + } + else if (numplayers > 2) + { + for (i=0; idata1 == destination_keys[i]) + { + if (playeringame[i] && i!=consoleplayer) + { + eatkey = chat_on = true; + HUlib_resetIText(&w_chat); + HU_queueChatChar((char)(i+1)); + break; + } + else if (i == consoleplayer) + { + num_nobrainers++; + if (num_nobrainers < 3) + plr->message = HUSTR_TALKTOSELF1; + else if (num_nobrainers < 6) + plr->message = HUSTR_TALKTOSELF2; + else if (num_nobrainers < 9) + plr->message = HUSTR_TALKTOSELF3; + else if (num_nobrainers < 32) + plr->message = HUSTR_TALKTOSELF4; + else + plr->message = HUSTR_TALKTOSELF5; + } + } + } + } + } + }//jff 2/26/98 no chat functions if message review is displayed + else if (!message_list) + { + c = ev->data1; + // send a macro + if (altdown) + { + c = c - '0'; + if (c > 9) + return false; + macromessage = chat_macros[c]; + + // kill last message with a '\n' + HU_queueChatChar((char)key_enter); // DEBUG!!! // phares + + // send the macro message + while (*macromessage) + HU_queueChatChar(*macromessage++); + HU_queueChatChar((char)key_enter); // phares + + // leave chat mode and notify that it was sent + chat_on = false; + strcpy(lastmessage, chat_macros[c]); + plr->message = lastmessage; + eatkey = true; + } + else + { + if (shiftdown || (c >= 'a' && c <= 'z')) + c = shiftxform[c]; + eatkey = HUlib_keyInIText(&w_chat, c); + if (eatkey) + HU_queueChatChar(c); + + if (c == key_enter) // phares + { + chat_on = false; + if (w_chat.l.len) + { + strcpy(lastmessage, w_chat.l.l); + plr->message = lastmessage; + } + } + else if (c == key_escape) // phares + chat_on = false; + } + } + return eatkey; +} diff --git a/src/hu_stuff.h b/src/hu_stuff.h new file mode 100644 index 0000000..e4cbf24 --- /dev/null +++ b/src/hu_stuff.h @@ -0,0 +1,90 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: Head up display + * + *-----------------------------------------------------------------------------*/ + +#ifndef __HU_STUFF_H__ +#define __HU_STUFF_H__ + +#include "d_event.h" + +/* + * Globally visible constants. + */ +#define HU_FONTSTART '!' /* the first font characters */ +#define HU_FONTEND (0x7f) /*jff 2/16/98 '_' the last font characters */ + +/* Calculate # of glyphs in font. */ +#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1) + +#define HU_BROADCAST 5 + +/*#define HU_MSGREFRESH KEYD_ENTER phares */ +#define HU_MSGX 0 +#define HU_MSGY 0 +#define HU_MSGWIDTH 64 /* in characters */ +#define HU_MSGHEIGHT 1 /* in lines */ + +#define HU_MSGTIMEOUT (4*TICRATE) + +/* + * Heads up text + */ +void HU_Init(void); +void HU_Start(void); + +boolean HU_Responder(event_t* ev); + +void HU_Ticker(void); +void HU_Drawer(void); +char HU_dequeueChatChar(void); +void HU_Erase(void); +void HU_MoveHud(void); // jff 3/9/98 avoid glitch in HUD display + +/* killough 5/2/98: moved from m_misc.c: */ + +/* jff 2/16/98 hud supported automap colors added */ +extern int hudcolor_titl; /* color range of automap level title */ +extern int hudcolor_xyco; /* color range of new coords on automap */ +/* jff 2/16/98 hud text colors, controls added */ +extern int hudcolor_mesg; /* color range of scrolling messages */ +extern int hudcolor_chat; /* color range of chat lines */ +/* jff 2/26/98 hud message list color and background enable */ +extern int hudcolor_list; /* color of list of past messages */ +extern int hud_list_bgon; /* solid window background for list of messages */ +extern int hud_msg_lines; /* number of message lines in window up to 16 */ +extern int hud_distributed; /* whether hud is all in lower left or distributed */ +/* jff 2/23/98 hud is currently displayed */ +extern int hud_displayed; /* hud is displayed */ +/* jff 2/18/98 hud/status control */ +extern int hud_active; /* hud mode 0=off, 1=small, 2=full */ +extern int hud_nosecrets; /* status does not list secrets/items/kills */ + +#endif diff --git a/src/i_joy.h b/src/i_joy.h new file mode 100644 index 0000000..29f19cb --- /dev/null +++ b/src/i_joy.h @@ -0,0 +1,47 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Joystick interface. + * + *-----------------------------------------------------------------------------*/ + +extern int joybfire; +extern int joybstrafe; +extern int joybuse; +extern int joybspeed; + +extern int joyleft; +extern int joyright; +extern int joyup; +extern int joydown; + +extern int usejoystick; + +void I_InitJoystick(void); +void I_PollJoystick(void); diff --git a/src/i_main.h b/src/i_main.h new file mode 100644 index 0000000..60b4662 --- /dev/null +++ b/src/i_main.h @@ -0,0 +1,44 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * General system functions. Signal related stuff, exit function + * prototypes, and programmable Doom clock. + * + *----------------------------------------------------------------------------- + */ + +#ifndef __I_MAIN__ +#define __I_MAIN__ + +void I_Init(void); +void I_SafeExit(int rc); + +extern int (*I_GetTime)(void); + +#endif diff --git a/src/i_network.h b/src/i_network.h new file mode 100644 index 0000000..532941f --- /dev/null +++ b/src/i_network.h @@ -0,0 +1,74 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Low level network interface. + *-----------------------------------------------------------------------------*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef USE_SDL_NET + #include "SDL_net.h" + #define UDP_SOCKET UDPsocket + #define UDP_PACKET UDPpacket + #define AF_INET + #define UDP_CHANNEL int + extern UDP_SOCKET udp_socket; +#else + #define UDP_CHANNEL struct sockaddr +#endif + +#ifndef IPPORT_RESERVED + #define IPPORT_RESERVED 1024 +#endif + +void I_InitNetwork(void); +size_t I_GetPacket(packet_header_t* buffer, size_t buflen); +void I_SendPacket(packet_header_t* packet, size_t len); +void I_WaitForPacket(int ms); + +#ifdef USE_SDL_NET +UDP_SOCKET I_Socket(Uint16 port); +int I_ConnectToServer(const char *serv); +UDP_CHANNEL I_RegisterPlayer(IPaddress *ipaddr); +void I_UnRegisterPlayer(UDP_CHANNEL channel); +extern IPaddress sentfrom_addr; +#endif + +#ifdef AF_INET +void I_SendPacketTo(packet_header_t* packet, size_t len, UDP_CHANNEL *to); +void I_SetupSocket(int sock, int port, int family); +void I_PrintAddress(FILE* fp, UDP_CHANNEL *addr); + +extern UDP_CHANNEL sentfrom; +extern int v4socket, v6socket; +#endif + +extern size_t sentbytes, recvdbytes; diff --git a/src/i_sound.h b/src/i_sound.h new file mode 100644 index 0000000..e03ccbf --- /dev/null +++ b/src/i_sound.h @@ -0,0 +1,120 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * System interface, sound. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __I_SOUND__ +#define __I_SOUND__ + +#include "sounds.h" +#include "doomtype.h" + +#define SNDSERV +#undef SNDINTR + +#ifndef SNDSERV +#include "l_soundgen.h" +#endif + +// Init at program start... +void I_InitSound(void); + +// ... shut down and relase at program termination. +void I_ShutdownSound(void); + +// +// SFX I/O +// + +// Initialize channels? +void I_SetChannels(void); + +// Get raw data lump index for sound descriptor. +int I_GetSfxLumpNum (sfxinfo_t *sfxinfo); + +// Starts a sound in a particular sound channel. +int I_StartSound(int id, int channel, int vol, int sep, int pitch, int priority); + +// Stops a sound channel. +void I_StopSound(int handle); + +// Called by S_*() functions +// to see if a channel is still playing. +// Returns 0 if no longer playing, 1 if playing. +boolean I_SoundIsPlaying(int handle); + +// Called by m_menu.c to let the quit sound play and quit right after it stops +boolean I_AnySoundStillPlaying(void); + +// Updates the volume, separation, +// and pitch of a sound channel. +void I_UpdateSoundParams(int handle, int vol, int sep, int pitch); + +// +// MUSIC I/O +// +void I_InitMusic(void); +void I_ShutdownMusic(void); + +void I_UpdateMusic(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(const void *data, size_t len); + +// cournia - tries to load a music file +int I_RegisterMusic( const char* filename, musicinfo_t *music ); + +// 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); + +// Allegro card support jff 1/18/98 +extern int snd_card; +extern int mus_card; +// CPhipps - put these in config file +extern int snd_samplerate; + +#endif diff --git a/src/i_system.h b/src/i_system.h new file mode 100644 index 0000000..727a5ea --- /dev/null +++ b/src/i_system.h @@ -0,0 +1,77 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * System specific interface stuff. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __I_SYSTEM__ +#define __I_SYSTEM__ + +#ifdef __GNUG__ +#pragma interface +#endif + +extern int ms_to_next_tick; +boolean I_StartDisplay(void); +void I_EndDisplay(void); +int I_GetTime_RealTime(void); /* killough */ +#ifndef PRBOOM_SERVER +fixed_t I_GetTimeFrac (void); +#endif +void I_GetTime_SaveMS(void); + +unsigned long I_GetRandomTimeSeed(void); /* cphipps */ + +void I_uSleep(unsigned long usecs); + +/* cphipps - I_GetVersionString + * Returns a version string in the given buffer + */ +const char* I_GetVersionString(char* buf, size_t sz); + +/* cphipps - I_SigString + * Returns a string describing a signal number + */ +const char* I_SigString(char* buf, size_t sz, int signum); + +const char *I_DoomExeDir(void); // killough 2/16/98: path to executable's dir + +boolean HasTrailingSlash(const char* dn); +char* I_FindFile(const char* wfname, const char* ext); + +/* cph 2001/11/18 - wrapper for read(2) which deals with partial reads */ +void I_Read(int fd, void* buf, size_t sz); + +/* cph 2001/11/18 - Move W_Filelength to i_system.c */ +int I_Filelength(int handle); + +void I_SetAffinityMask(void); + +#endif diff --git a/src/i_video.h b/src/i_video.h new file mode 100644 index 0000000..00d1a04 --- /dev/null +++ b/src/i_video.h @@ -0,0 +1,82 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * System specific interface stuff. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __I_VIDEO__ +#define __I_VIDEO__ + +#include "doomtype.h" +#include "v_video.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +void I_PreInitGraphics(void); /* CPhipps - do stuff immediately on start */ +void I_CalculateRes(unsigned int width, unsigned int height); /* calculate resolution */ +void I_SetRes(void); /* set resolution */ +void I_InitGraphics (void); +void I_UpdateVideoMode(void); +void I_ShutdownGraphics(void); + +/* Takes full 8 bit values. */ +void I_SetPalette(int pal); /* CPhipps - pass down palette number */ + +void I_UpdateNoBlit (void); +void I_FinishUpdate (void); + +int I_ScreenShot (const char *fname); + +/* I_StartTic + * 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); + +/* I_StartFrame + * 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); + +extern int use_doublebuffer; /* proff 2001-7-4 - controls wether to use doublebuffering*/ +extern int use_fullscreen; /* proff 21/05/2000 */ +extern int desired_fullscreen; //e6y + +#endif diff --git a/src/info.c b/src/info.c new file mode 100644 index 0000000..2e64614 --- /dev/null +++ b/src/info.c @@ -0,0 +1,4899 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Thing frame/state LUT, + * generated by multigen utilitiy. + * This one is the original DOOM version, preserved. + * BOOM changes include commenting and addition of predefined lumps + * for providing things that aren't in the IWAD without sending a + * separate must-use wad file around with the EXE. + * + *----------------------------------------------------------------------------- + */ + +#include "doomdef.h" +#include "sounds.h" +#include "m_fixed.h" +#include "p_mobj.h" +#include "p_enemy.h" +#include "p_pspr.h" +#include "w_wad.h" + +#ifdef __GNUG__ +#pragma implementation "info.h" +#endif +#include "info.h" + + +// ******************************************************************** +// Sprite names +// ******************************************************************** +// This is the list of sprite 4-character prefixes. They are searched +// through, with a NULL entry terminating the list. In DOOM originally +// this NULL entry was missing, and coincidentally the next thing in +// memory was the dummy state_t[] entry that started with zero bytes. +// killough 1/17/98: add an explicit NULL entry. +// NUMSPRITES is an enum from info.h where all these are listed +// as SPR_xxxx + +const char *sprnames[NUMSPRITES+1] = { + "TROO","SHTG","PUNG","PISG","PISF","SHTF","SHT2","CHGG","CHGF","MISG", + "MISF","SAWG","PLSG","PLSF","BFGG","BFGF","BLUD","PUFF","BAL1","BAL2", + "PLSS","PLSE","MISL","BFS1","BFE1","BFE2","TFOG","IFOG","PLAY","POSS", + "SPOS","VILE","FIRE","FATB","FBXP","SKEL","MANF","FATT","CPOS","SARG", + "HEAD","BAL7","BOSS","BOS2","SKUL","SPID","BSPI","APLS","APBX","CYBR", + "PAIN","SSWV","KEEN","BBRN","BOSF","ARM1","ARM2","BAR1","BEXP","FCAN", + "BON1","BON2","BKEY","RKEY","YKEY","BSKU","RSKU","YSKU","STIM","MEDI", + "SOUL","PINV","PSTR","PINS","MEGA","SUIT","PMAP","PVIS","CLIP","AMMO", + "ROCK","BROK","CELL","CELP","SHEL","SBOX","BPAK","BFUG","MGUN","CSAW", + "LAUN","PLAS","SHOT","SGN2","COLU","SMT2","GOR1","POL2","POL5","POL4", + "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", + "TNT1", // invisible sprite phares 3/9/98 +#ifdef DOGS + "DOGS", /* killough 7/19/98: Marine's best friend :) */ +#endif + NULL +}; + +// ******************************************************************** +// State or "frame" information +// ******************************************************************** +// Each of the states, otherwise known as "frames", is outlined +// here. The data in each element of the array is the way it is +// initialized, with sprite names identified by their enumerator +// value such as SPR_SHTG. These correlate to the above sprite +// array so don't change them around unless you understand what +// you're doing. +// +// The commented name beginning with S_ at the end of each line +// is there to help figure out where the next-frame pointer is +// pointing. These are also additionally identified in info.h +// as enumerated values. From a change-and-recompile point of +// view this is fairly workable, but it adds a lot to the effort +// when trying to change things externally. See also the d_deh.c +// parts where frame rewiring is done for more details and the +// extended way a BEX file can handle this. + +state_t states[NUMSTATES] = { + {SPR_TROO,0,-1,NULL,S_NULL,0,0}, // S_NULL + {SPR_SHTG,4,0,A_Light0,S_NULL,0,0}, // S_LIGHTDONE + {SPR_PUNG,0,1,A_WeaponReady,S_PUNCH,0,0}, // S_PUNCH + {SPR_PUNG,0,1,A_Lower,S_PUNCHDOWN,0,0}, // S_PUNCHDOWN + {SPR_PUNG,0,1,A_Raise,S_PUNCHUP,0,0}, // S_PUNCHUP + {SPR_PUNG,1,4,NULL,S_PUNCH2,0,0}, // S_PUNCH1 + {SPR_PUNG,2,4,A_Punch,S_PUNCH3,0,0}, // S_PUNCH2 + {SPR_PUNG,3,5,NULL,S_PUNCH4,0,0}, // S_PUNCH3 + {SPR_PUNG,2,4,NULL,S_PUNCH5,0,0}, // S_PUNCH4 + {SPR_PUNG,1,5,A_ReFire,S_PUNCH,0,0}, // S_PUNCH5 + {SPR_PISG,0,1,A_WeaponReady,S_PISTOL,0,0},// S_PISTOL + {SPR_PISG,0,1,A_Lower,S_PISTOLDOWN,0,0}, // S_PISTOLDOWN + {SPR_PISG,0,1,A_Raise,S_PISTOLUP,0,0}, // S_PISTOLUP + {SPR_PISG,0,4,NULL,S_PISTOL2,0,0}, // S_PISTOL1 + {SPR_PISG,1,6,A_FirePistol,S_PISTOL3,0,0},// S_PISTOL2 + {SPR_PISG,2,4,NULL,S_PISTOL4,0,0}, // S_PISTOL3 + {SPR_PISG,1,5,A_ReFire,S_PISTOL,0,0}, // S_PISTOL4 + {SPR_PISF,32768,7,A_Light1,S_LIGHTDONE,0,0}, // S_PISTOLFLASH + {SPR_SHTG,0,1,A_WeaponReady,S_SGUN,0,0}, // S_SGUN + {SPR_SHTG,0,1,A_Lower,S_SGUNDOWN,0,0}, // S_SGUNDOWN + {SPR_SHTG,0,1,A_Raise,S_SGUNUP,0,0}, // S_SGUNUP + {SPR_SHTG,0,3,NULL,S_SGUN2,0,0}, // S_SGUN1 + {SPR_SHTG,0,7,A_FireShotgun,S_SGUN3,0,0}, // S_SGUN2 + {SPR_SHTG,1,5,NULL,S_SGUN4,0,0}, // S_SGUN3 + {SPR_SHTG,2,5,NULL,S_SGUN5,0,0}, // S_SGUN4 + {SPR_SHTG,3,4,NULL,S_SGUN6,0,0}, // S_SGUN5 + {SPR_SHTG,2,5,NULL,S_SGUN7,0,0}, // S_SGUN6 + {SPR_SHTG,1,5,NULL,S_SGUN8,0,0}, // S_SGUN7 + {SPR_SHTG,0,3,NULL,S_SGUN9,0,0}, // S_SGUN8 + {SPR_SHTG,0,7,A_ReFire,S_SGUN,0,0}, // S_SGUN9 + {SPR_SHTF,32768,4,A_Light1,S_SGUNFLASH2,0,0}, // S_SGUNFLASH1 + {SPR_SHTF,32769,3,A_Light2,S_LIGHTDONE,0,0}, // S_SGUNFLASH2 + {SPR_SHT2,0,1,A_WeaponReady,S_DSGUN,0,0}, // S_DSGUN + {SPR_SHT2,0,1,A_Lower,S_DSGUNDOWN,0,0}, // S_DSGUNDOWN + {SPR_SHT2,0,1,A_Raise,S_DSGUNUP,0,0}, // S_DSGUNUP + {SPR_SHT2,0,3,NULL,S_DSGUN2,0,0}, // S_DSGUN1 + {SPR_SHT2,0,7,A_FireShotgun2,S_DSGUN3,0,0}, // S_DSGUN2 + {SPR_SHT2,1,7,NULL,S_DSGUN4,0,0}, // S_DSGUN3 + {SPR_SHT2,2,7,A_CheckReload,S_DSGUN5,0,0}, // S_DSGUN4 + {SPR_SHT2,3,7,A_OpenShotgun2,S_DSGUN6,0,0}, // S_DSGUN5 + {SPR_SHT2,4,7,NULL,S_DSGUN7,0,0}, // S_DSGUN6 + {SPR_SHT2,5,7,A_LoadShotgun2,S_DSGUN8,0,0}, // S_DSGUN7 + {SPR_SHT2,6,6,NULL,S_DSGUN9,0,0}, // S_DSGUN8 + {SPR_SHT2,7,6,A_CloseShotgun2,S_DSGUN10,0,0}, // S_DSGUN9 + {SPR_SHT2,0,5,A_ReFire,S_DSGUN,0,0}, // S_DSGUN10 + {SPR_SHT2,1,7,NULL,S_DSNR2,0,0}, // S_DSNR1 + {SPR_SHT2,0,3,NULL,S_DSGUNDOWN,0,0}, // S_DSNR2 + {SPR_SHT2,32776,5,A_Light1,S_DSGUNFLASH2,0,0}, // S_DSGUNFLASH1 + {SPR_SHT2,32777,4,A_Light2,S_LIGHTDONE,0,0}, // S_DSGUNFLASH2 + {SPR_CHGG,0,1,A_WeaponReady,S_CHAIN,0,0}, // S_CHAIN + {SPR_CHGG,0,1,A_Lower,S_CHAINDOWN,0,0}, // S_CHAINDOWN + {SPR_CHGG,0,1,A_Raise,S_CHAINUP,0,0}, // S_CHAINUP + {SPR_CHGG,0,4,A_FireCGun,S_CHAIN2,0,0}, // S_CHAIN1 + {SPR_CHGG,1,4,A_FireCGun,S_CHAIN3,0,0}, // S_CHAIN2 + {SPR_CHGG,1,0,A_ReFire,S_CHAIN,0,0}, // S_CHAIN3 + {SPR_CHGF,32768,5,A_Light1,S_LIGHTDONE,0,0}, // S_CHAINFLASH1 + {SPR_CHGF,32769,5,A_Light2,S_LIGHTDONE,0,0}, // S_CHAINFLASH2 + {SPR_MISG,0,1,A_WeaponReady,S_MISSILE,0,0}, // S_MISSILE + {SPR_MISG,0,1,A_Lower,S_MISSILEDOWN,0,0}, // S_MISSILEDOWN + {SPR_MISG,0,1,A_Raise,S_MISSILEUP,0,0}, // S_MISSILEUP + {SPR_MISG,1,8,A_GunFlash,S_MISSILE2,0,0}, // S_MISSILE1 + {SPR_MISG,1,12,A_FireMissile,S_MISSILE3,0,0}, // S_MISSILE2 + {SPR_MISG,1,0,A_ReFire,S_MISSILE,0,0}, // S_MISSILE3 + {SPR_MISF,32768,3,A_Light1,S_MISSILEFLASH2,0,0}, // S_MISSILEFLASH1 + {SPR_MISF,32769,4,NULL,S_MISSILEFLASH3,0,0}, // S_MISSILEFLASH2 + {SPR_MISF,32770,4,A_Light2,S_MISSILEFLASH4,0,0}, // S_MISSILEFLASH3 + {SPR_MISF,32771,4,A_Light2,S_LIGHTDONE,0,0}, // S_MISSILEFLASH4 + {SPR_SAWG,2,4,A_WeaponReady,S_SAWB,0,0}, // S_SAW + {SPR_SAWG,3,4,A_WeaponReady,S_SAW,0,0}, // S_SAWB + {SPR_SAWG,2,1,A_Lower,S_SAWDOWN,0,0}, // S_SAWDOWN + {SPR_SAWG,2,1,A_Raise,S_SAWUP,0,0}, // S_SAWUP + {SPR_SAWG,0,4,A_Saw,S_SAW2,0,0}, // S_SAW1 + {SPR_SAWG,1,4,A_Saw,S_SAW3,0,0}, // S_SAW2 + {SPR_SAWG,1,0,A_ReFire,S_SAW,0,0}, // S_SAW3 + {SPR_PLSG,0,1,A_WeaponReady,S_PLASMA,0,0}, // S_PLASMA + {SPR_PLSG,0,1,A_Lower,S_PLASMADOWN,0,0}, // S_PLASMADOWN + {SPR_PLSG,0,1,A_Raise,S_PLASMAUP,0,0}, // S_PLASMAUP + {SPR_PLSG,0,3,A_FirePlasma,S_PLASMA2,0,0}, // S_PLASMA1 + {SPR_PLSG,1,20,A_ReFire,S_PLASMA,0,0}, // S_PLASMA2 + {SPR_PLSF,32768,4,A_Light1,S_LIGHTDONE,0,0}, // S_PLASMAFLASH1 + {SPR_PLSF,32769,4,A_Light1,S_LIGHTDONE,0,0}, // S_PLASMAFLASH2 + {SPR_BFGG,0,1,A_WeaponReady,S_BFG,0,0}, // S_BFG + {SPR_BFGG,0,1,A_Lower,S_BFGDOWN,0,0}, // S_BFGDOWN + {SPR_BFGG,0,1,A_Raise,S_BFGUP,0,0}, // S_BFGUP + {SPR_BFGG,0,20,A_BFGsound,S_BFG2,0,0}, // S_BFG1 + {SPR_BFGG,1,10,A_GunFlash,S_BFG3,0,0}, // S_BFG2 + {SPR_BFGG,1,10,A_FireBFG,S_BFG4,0,0}, // S_BFG3 + {SPR_BFGG,1,20,A_ReFire,S_BFG,0,0}, // S_BFG4 + {SPR_BFGF,32768,11,A_Light1,S_BFGFLASH2,0,0}, // S_BFGFLASH1 + {SPR_BFGF,32769,6,A_Light2,S_LIGHTDONE,0,0}, // S_BFGFLASH2 + {SPR_BLUD,2,8,NULL,S_BLOOD2,0,0}, // S_BLOOD1 + {SPR_BLUD,1,8,NULL,S_BLOOD3,0,0}, // S_BLOOD2 + {SPR_BLUD,0,8,NULL,S_NULL,0,0}, // S_BLOOD3 + {SPR_PUFF,32768,4,NULL,S_PUFF2,0,0}, // S_PUFF1 + {SPR_PUFF,1,4,NULL,S_PUFF3,0,0}, // S_PUFF2 + {SPR_PUFF,2,4,NULL,S_PUFF4,0,0}, // S_PUFF3 + {SPR_PUFF,3,4,NULL,S_NULL,0,0}, // S_PUFF4 + {SPR_BAL1,32768,4,NULL,S_TBALL2,0,0}, // S_TBALL1 + {SPR_BAL1,32769,4,NULL,S_TBALL1,0,0}, // S_TBALL2 + {SPR_BAL1,32770,6,NULL,S_TBALLX2,0,0}, // S_TBALLX1 + {SPR_BAL1,32771,6,NULL,S_TBALLX3,0,0}, // S_TBALLX2 + {SPR_BAL1,32772,6,NULL,S_NULL,0,0}, // S_TBALLX3 + {SPR_BAL2,32768,4,NULL,S_RBALL2,0,0}, // S_RBALL1 + {SPR_BAL2,32769,4,NULL,S_RBALL1,0,0}, // S_RBALL2 + {SPR_BAL2,32770,6,NULL,S_RBALLX2,0,0}, // S_RBALLX1 + {SPR_BAL2,32771,6,NULL,S_RBALLX3,0,0}, // S_RBALLX2 + {SPR_BAL2,32772,6,NULL,S_NULL,0,0}, // S_RBALLX3 + {SPR_PLSS,32768,6,NULL,S_PLASBALL2,0,0}, // S_PLASBALL + {SPR_PLSS,32769,6,NULL,S_PLASBALL,0,0}, // S_PLASBALL2 + {SPR_PLSE,32768,4,NULL,S_PLASEXP2,0,0}, // S_PLASEXP + {SPR_PLSE,32769,4,NULL,S_PLASEXP3,0,0}, // S_PLASEXP2 + {SPR_PLSE,32770,4,NULL,S_PLASEXP4,0,0}, // S_PLASEXP3 + {SPR_PLSE,32771,4,NULL,S_PLASEXP5,0,0}, // S_PLASEXP4 + {SPR_PLSE,32772,4,NULL,S_NULL,0,0}, // S_PLASEXP5 + {SPR_MISL,32768,1,NULL,S_ROCKET,0,0}, // S_ROCKET + {SPR_BFS1,32768,4,NULL,S_BFGSHOT2,0,0}, // S_BFGSHOT + {SPR_BFS1,32769,4,NULL,S_BFGSHOT,0,0}, // S_BFGSHOT2 + {SPR_BFE1,32768,8,NULL,S_BFGLAND2,0,0}, // S_BFGLAND + {SPR_BFE1,32769,8,NULL,S_BFGLAND3,0,0}, // S_BFGLAND2 + {SPR_BFE1,32770,8,A_BFGSpray,S_BFGLAND4,0,0}, // S_BFGLAND3 + {SPR_BFE1,32771,8,NULL,S_BFGLAND5,0,0}, // S_BFGLAND4 + {SPR_BFE1,32772,8,NULL,S_BFGLAND6,0,0}, // S_BFGLAND5 + {SPR_BFE1,32773,8,NULL,S_NULL,0,0}, // S_BFGLAND6 + {SPR_BFE2,32768,8,NULL,S_BFGEXP2,0,0}, // S_BFGEXP + {SPR_BFE2,32769,8,NULL,S_BFGEXP3,0,0}, // S_BFGEXP2 + {SPR_BFE2,32770,8,NULL,S_BFGEXP4,0,0}, // S_BFGEXP3 + {SPR_BFE2,32771,8,NULL,S_NULL,0,0}, // S_BFGEXP4 + {SPR_MISL,32769,8,A_Explode,S_EXPLODE2,0,0}, // S_EXPLODE1 + {SPR_MISL,32770,6,NULL,S_EXPLODE3,0,0}, // S_EXPLODE2 + {SPR_MISL,32771,4,NULL,S_NULL,0,0}, // S_EXPLODE3 + {SPR_TFOG,32768,6,NULL,S_TFOG01,0,0}, // S_TFOG + {SPR_TFOG,32769,6,NULL,S_TFOG02,0,0}, // S_TFOG01 + {SPR_TFOG,32768,6,NULL,S_TFOG2,0,0}, // S_TFOG02 + {SPR_TFOG,32769,6,NULL,S_TFOG3,0,0}, // S_TFOG2 + {SPR_TFOG,32770,6,NULL,S_TFOG4,0,0}, // S_TFOG3 + {SPR_TFOG,32771,6,NULL,S_TFOG5,0,0}, // S_TFOG4 + {SPR_TFOG,32772,6,NULL,S_TFOG6,0,0}, // S_TFOG5 + {SPR_TFOG,32773,6,NULL,S_TFOG7,0,0}, // S_TFOG6 + {SPR_TFOG,32774,6,NULL,S_TFOG8,0,0}, // S_TFOG7 + {SPR_TFOG,32775,6,NULL,S_TFOG9,0,0}, // S_TFOG8 + {SPR_TFOG,32776,6,NULL,S_TFOG10,0,0}, // S_TFOG9 + {SPR_TFOG,32777,6,NULL,S_NULL,0,0}, // S_TFOG10 + {SPR_IFOG,32768,6,NULL,S_IFOG01,0,0}, // S_IFOG + {SPR_IFOG,32769,6,NULL,S_IFOG02,0,0}, // S_IFOG01 + {SPR_IFOG,32768,6,NULL,S_IFOG2,0,0}, // S_IFOG02 + {SPR_IFOG,32769,6,NULL,S_IFOG3,0,0}, // S_IFOG2 + {SPR_IFOG,32770,6,NULL,S_IFOG4,0,0}, // S_IFOG3 + {SPR_IFOG,32771,6,NULL,S_IFOG5,0,0}, // S_IFOG4 + {SPR_IFOG,32772,6,NULL,S_NULL,0,0}, // S_IFOG5 + {SPR_PLAY,0,-1,NULL,S_NULL,0,0}, // S_PLAY + {SPR_PLAY,0,4,NULL,S_PLAY_RUN2,0,0}, // S_PLAY_RUN1 + {SPR_PLAY,1,4,NULL,S_PLAY_RUN3,0,0}, // S_PLAY_RUN2 + {SPR_PLAY,2,4,NULL,S_PLAY_RUN4,0,0}, // S_PLAY_RUN3 + {SPR_PLAY,3,4,NULL,S_PLAY_RUN1,0,0}, // S_PLAY_RUN4 + {SPR_PLAY,4,12,NULL,S_PLAY,0,0}, // S_PLAY_ATK1 + {SPR_PLAY,32773,6,NULL,S_PLAY_ATK1,0,0}, // S_PLAY_ATK2 + {SPR_PLAY,6,4,NULL,S_PLAY_PAIN2,0,0}, // S_PLAY_PAIN + {SPR_PLAY,6,4,A_Pain,S_PLAY,0,0}, // S_PLAY_PAIN2 + {SPR_PLAY,7,10,NULL,S_PLAY_DIE2,0,0}, // S_PLAY_DIE1 + {SPR_PLAY,8,10,A_PlayerScream,S_PLAY_DIE3,0,0}, // S_PLAY_DIE2 + {SPR_PLAY,9,10,A_Fall,S_PLAY_DIE4,0,0}, // S_PLAY_DIE3 + {SPR_PLAY,10,10,NULL,S_PLAY_DIE5,0,0}, // S_PLAY_DIE4 + {SPR_PLAY,11,10,NULL,S_PLAY_DIE6,0,0}, // S_PLAY_DIE5 + {SPR_PLAY,12,10,NULL,S_PLAY_DIE7,0,0}, // S_PLAY_DIE6 + {SPR_PLAY,13,-1,NULL,S_NULL,0,0}, // S_PLAY_DIE7 + {SPR_PLAY,14,5,NULL,S_PLAY_XDIE2,0,0}, // S_PLAY_XDIE1 + {SPR_PLAY,15,5,A_XScream,S_PLAY_XDIE3,0,0}, // S_PLAY_XDIE2 + {SPR_PLAY,16,5,A_Fall,S_PLAY_XDIE4,0,0}, // S_PLAY_XDIE3 + {SPR_PLAY,17,5,NULL,S_PLAY_XDIE5,0,0}, // S_PLAY_XDIE4 + {SPR_PLAY,18,5,NULL,S_PLAY_XDIE6,0,0}, // S_PLAY_XDIE5 + {SPR_PLAY,19,5,NULL,S_PLAY_XDIE7,0,0}, // S_PLAY_XDIE6 + {SPR_PLAY,20,5,NULL,S_PLAY_XDIE8,0,0}, // S_PLAY_XDIE7 + {SPR_PLAY,21,5,NULL,S_PLAY_XDIE9,0,0}, // S_PLAY_XDIE8 + {SPR_PLAY,22,-1,NULL,S_NULL,0,0}, // S_PLAY_XDIE9 + {SPR_POSS,0,10,A_Look,S_POSS_STND2,0,0}, // S_POSS_STND + {SPR_POSS,1,10,A_Look,S_POSS_STND,0,0}, // S_POSS_STND2 + {SPR_POSS,0,4,A_Chase,S_POSS_RUN2,0,0}, // S_POSS_RUN1 + {SPR_POSS,0,4,A_Chase,S_POSS_RUN3,0,0}, // S_POSS_RUN2 + {SPR_POSS,1,4,A_Chase,S_POSS_RUN4,0,0}, // S_POSS_RUN3 + {SPR_POSS,1,4,A_Chase,S_POSS_RUN5,0,0}, // S_POSS_RUN4 + {SPR_POSS,2,4,A_Chase,S_POSS_RUN6,0,0}, // S_POSS_RUN5 + {SPR_POSS,2,4,A_Chase,S_POSS_RUN7,0,0}, // S_POSS_RUN6 + {SPR_POSS,3,4,A_Chase,S_POSS_RUN8,0,0}, // S_POSS_RUN7 + {SPR_POSS,3,4,A_Chase,S_POSS_RUN1,0,0}, // S_POSS_RUN8 + {SPR_POSS,4,10,A_FaceTarget,S_POSS_ATK2,0,0}, // S_POSS_ATK1 + {SPR_POSS,5,8,A_PosAttack,S_POSS_ATK3,0,0}, // S_POSS_ATK2 + {SPR_POSS,4,8,NULL,S_POSS_RUN1,0,0}, // S_POSS_ATK3 + {SPR_POSS,6,3,NULL,S_POSS_PAIN2,0,0}, // S_POSS_PAIN + {SPR_POSS,6,3,A_Pain,S_POSS_RUN1,0,0}, // S_POSS_PAIN2 + {SPR_POSS,7,5,NULL,S_POSS_DIE2,0,0}, // S_POSS_DIE1 + {SPR_POSS,8,5,A_Scream,S_POSS_DIE3,0,0}, // S_POSS_DIE2 + {SPR_POSS,9,5,A_Fall,S_POSS_DIE4,0,0}, // S_POSS_DIE3 + {SPR_POSS,10,5,NULL,S_POSS_DIE5,0,0}, // S_POSS_DIE4 + {SPR_POSS,11,-1,NULL,S_NULL,0,0}, // S_POSS_DIE5 + {SPR_POSS,12,5,NULL,S_POSS_XDIE2,0,0}, // S_POSS_XDIE1 + {SPR_POSS,13,5,A_XScream,S_POSS_XDIE3,0,0}, // S_POSS_XDIE2 + {SPR_POSS,14,5,A_Fall,S_POSS_XDIE4,0,0}, // S_POSS_XDIE3 + {SPR_POSS,15,5,NULL,S_POSS_XDIE5,0,0}, // S_POSS_XDIE4 + {SPR_POSS,16,5,NULL,S_POSS_XDIE6,0,0}, // S_POSS_XDIE5 + {SPR_POSS,17,5,NULL,S_POSS_XDIE7,0,0}, // S_POSS_XDIE6 + {SPR_POSS,18,5,NULL,S_POSS_XDIE8,0,0}, // S_POSS_XDIE7 + {SPR_POSS,19,5,NULL,S_POSS_XDIE9,0,0}, // S_POSS_XDIE8 + {SPR_POSS,20,-1,NULL,S_NULL,0,0}, // S_POSS_XDIE9 + {SPR_POSS,10,5,NULL,S_POSS_RAISE2,0,0}, // S_POSS_RAISE1 + {SPR_POSS,9,5,NULL,S_POSS_RAISE3,0,0}, // S_POSS_RAISE2 + {SPR_POSS,8,5,NULL,S_POSS_RAISE4,0,0}, // S_POSS_RAISE3 + {SPR_POSS,7,5,NULL,S_POSS_RUN1,0,0}, // S_POSS_RAISE4 + {SPR_SPOS,0,10,A_Look,S_SPOS_STND2,0,0}, // S_SPOS_STND + {SPR_SPOS,1,10,A_Look,S_SPOS_STND,0,0}, // S_SPOS_STND2 + {SPR_SPOS,0,3,A_Chase,S_SPOS_RUN2,0,0}, // S_SPOS_RUN1 + {SPR_SPOS,0,3,A_Chase,S_SPOS_RUN3,0,0}, // S_SPOS_RUN2 + {SPR_SPOS,1,3,A_Chase,S_SPOS_RUN4,0,0}, // S_SPOS_RUN3 + {SPR_SPOS,1,3,A_Chase,S_SPOS_RUN5,0,0}, // S_SPOS_RUN4 + {SPR_SPOS,2,3,A_Chase,S_SPOS_RUN6,0,0}, // S_SPOS_RUN5 + {SPR_SPOS,2,3,A_Chase,S_SPOS_RUN7,0,0}, // S_SPOS_RUN6 + {SPR_SPOS,3,3,A_Chase,S_SPOS_RUN8,0,0}, // S_SPOS_RUN7 + {SPR_SPOS,3,3,A_Chase,S_SPOS_RUN1,0,0}, // S_SPOS_RUN8 + {SPR_SPOS,4,10,A_FaceTarget,S_SPOS_ATK2,0,0}, // S_SPOS_ATK1 + {SPR_SPOS,32773,10,A_SPosAttack,S_SPOS_ATK3,0,0}, // S_SPOS_ATK2 + {SPR_SPOS,4,10,NULL,S_SPOS_RUN1,0,0}, // S_SPOS_ATK3 + {SPR_SPOS,6,3,NULL,S_SPOS_PAIN2,0,0}, // S_SPOS_PAIN + {SPR_SPOS,6,3,A_Pain,S_SPOS_RUN1,0,0}, // S_SPOS_PAIN2 + {SPR_SPOS,7,5,NULL,S_SPOS_DIE2,0,0}, // S_SPOS_DIE1 + {SPR_SPOS,8,5,A_Scream,S_SPOS_DIE3,0,0}, // S_SPOS_DIE2 + {SPR_SPOS,9,5,A_Fall,S_SPOS_DIE4,0,0}, // S_SPOS_DIE3 + {SPR_SPOS,10,5,NULL,S_SPOS_DIE5,0,0}, // S_SPOS_DIE4 + {SPR_SPOS,11,-1,NULL,S_NULL,0,0}, // S_SPOS_DIE5 + {SPR_SPOS,12,5,NULL,S_SPOS_XDIE2,0,0}, // S_SPOS_XDIE1 + {SPR_SPOS,13,5,A_XScream,S_SPOS_XDIE3,0,0}, // S_SPOS_XDIE2 + {SPR_SPOS,14,5,A_Fall,S_SPOS_XDIE4,0,0}, // S_SPOS_XDIE3 + {SPR_SPOS,15,5,NULL,S_SPOS_XDIE5,0,0}, // S_SPOS_XDIE4 + {SPR_SPOS,16,5,NULL,S_SPOS_XDIE6,0,0}, // S_SPOS_XDIE5 + {SPR_SPOS,17,5,NULL,S_SPOS_XDIE7,0,0}, // S_SPOS_XDIE6 + {SPR_SPOS,18,5,NULL,S_SPOS_XDIE8,0,0}, // S_SPOS_XDIE7 + {SPR_SPOS,19,5,NULL,S_SPOS_XDIE9,0,0}, // S_SPOS_XDIE8 + {SPR_SPOS,20,-1,NULL,S_NULL,0,0}, // S_SPOS_XDIE9 + {SPR_SPOS,11,5,NULL,S_SPOS_RAISE2,0,0}, // S_SPOS_RAISE1 + {SPR_SPOS,10,5,NULL,S_SPOS_RAISE3,0,0}, // S_SPOS_RAISE2 + {SPR_SPOS,9,5,NULL,S_SPOS_RAISE4,0,0}, // S_SPOS_RAISE3 + {SPR_SPOS,8,5,NULL,S_SPOS_RAISE5,0,0}, // S_SPOS_RAISE4 + {SPR_SPOS,7,5,NULL,S_SPOS_RUN1,0,0}, // S_SPOS_RAISE5 + {SPR_VILE,0,10,A_Look,S_VILE_STND2,0,0}, // S_VILE_STND + {SPR_VILE,1,10,A_Look,S_VILE_STND,0,0}, // S_VILE_STND2 + {SPR_VILE,0,2,A_VileChase,S_VILE_RUN2,0,0}, // S_VILE_RUN1 + {SPR_VILE,0,2,A_VileChase,S_VILE_RUN3,0,0}, // S_VILE_RUN2 + {SPR_VILE,1,2,A_VileChase,S_VILE_RUN4,0,0}, // S_VILE_RUN3 + {SPR_VILE,1,2,A_VileChase,S_VILE_RUN5,0,0}, // S_VILE_RUN4 + {SPR_VILE,2,2,A_VileChase,S_VILE_RUN6,0,0}, // S_VILE_RUN5 + {SPR_VILE,2,2,A_VileChase,S_VILE_RUN7,0,0}, // S_VILE_RUN6 + {SPR_VILE,3,2,A_VileChase,S_VILE_RUN8,0,0}, // S_VILE_RUN7 + {SPR_VILE,3,2,A_VileChase,S_VILE_RUN9,0,0}, // S_VILE_RUN8 + {SPR_VILE,4,2,A_VileChase,S_VILE_RUN10,0,0}, // S_VILE_RUN9 + {SPR_VILE,4,2,A_VileChase,S_VILE_RUN11,0,0}, // S_VILE_RUN10 + {SPR_VILE,5,2,A_VileChase,S_VILE_RUN12,0,0}, // S_VILE_RUN11 + {SPR_VILE,5,2,A_VileChase,S_VILE_RUN1,0,0}, // S_VILE_RUN12 + {SPR_VILE,32774,0,A_VileStart,S_VILE_ATK2,0,0}, // S_VILE_ATK1 + {SPR_VILE,32774,10,A_FaceTarget,S_VILE_ATK3,0,0}, // S_VILE_ATK2 + {SPR_VILE,32775,8,A_VileTarget,S_VILE_ATK4,0,0}, // S_VILE_ATK3 + {SPR_VILE,32776,8,A_FaceTarget,S_VILE_ATK5,0,0}, // S_VILE_ATK4 + {SPR_VILE,32777,8,A_FaceTarget,S_VILE_ATK6,0,0}, // S_VILE_ATK5 + {SPR_VILE,32778,8,A_FaceTarget,S_VILE_ATK7,0,0}, // S_VILE_ATK6 + {SPR_VILE,32779,8,A_FaceTarget,S_VILE_ATK8,0,0}, // S_VILE_ATK7 + {SPR_VILE,32780,8,A_FaceTarget,S_VILE_ATK9,0,0}, // S_VILE_ATK8 + {SPR_VILE,32781,8,A_FaceTarget,S_VILE_ATK10,0,0}, // S_VILE_ATK9 + {SPR_VILE,32782,8,A_VileAttack,S_VILE_ATK11,0,0}, // S_VILE_ATK10 + {SPR_VILE,32783,20,NULL,S_VILE_RUN1,0,0}, // S_VILE_ATK11 + {SPR_VILE,32794,10,NULL,S_VILE_HEAL2,0,0}, // S_VILE_HEAL1 + {SPR_VILE,32795,10,NULL,S_VILE_HEAL3,0,0}, // S_VILE_HEAL2 + {SPR_VILE,32796,10,NULL,S_VILE_RUN1,0,0}, // S_VILE_HEAL3 + {SPR_VILE,16,5,NULL,S_VILE_PAIN2,0,0}, // S_VILE_PAIN + {SPR_VILE,16,5,A_Pain,S_VILE_RUN1,0,0}, // S_VILE_PAIN2 + {SPR_VILE,16,7,NULL,S_VILE_DIE2,0,0}, // S_VILE_DIE1 + {SPR_VILE,17,7,A_Scream,S_VILE_DIE3,0,0}, // S_VILE_DIE2 + {SPR_VILE,18,7,A_Fall,S_VILE_DIE4,0,0}, // S_VILE_DIE3 + {SPR_VILE,19,7,NULL,S_VILE_DIE5,0,0}, // S_VILE_DIE4 + {SPR_VILE,20,7,NULL,S_VILE_DIE6,0,0}, // S_VILE_DIE5 + {SPR_VILE,21,7,NULL,S_VILE_DIE7,0,0}, // S_VILE_DIE6 + {SPR_VILE,22,7,NULL,S_VILE_DIE8,0,0}, // S_VILE_DIE7 + {SPR_VILE,23,5,NULL,S_VILE_DIE9,0,0}, // S_VILE_DIE8 + {SPR_VILE,24,5,NULL,S_VILE_DIE10,0,0}, // S_VILE_DIE9 + {SPR_VILE,25,-1,NULL,S_NULL,0,0}, // S_VILE_DIE10 + {SPR_FIRE,32768,2,A_StartFire,S_FIRE2,0,0}, // S_FIRE1 + {SPR_FIRE,32769,2,A_Fire,S_FIRE3,0,0}, // S_FIRE2 + {SPR_FIRE,32768,2,A_Fire,S_FIRE4,0,0}, // S_FIRE3 + {SPR_FIRE,32769,2,A_Fire,S_FIRE5,0,0}, // S_FIRE4 + {SPR_FIRE,32770,2,A_FireCrackle,S_FIRE6,0,0}, // S_FIRE5 + {SPR_FIRE,32769,2,A_Fire,S_FIRE7,0,0}, // S_FIRE6 + {SPR_FIRE,32770,2,A_Fire,S_FIRE8,0,0}, // S_FIRE7 + {SPR_FIRE,32769,2,A_Fire,S_FIRE9,0,0}, // S_FIRE8 + {SPR_FIRE,32770,2,A_Fire,S_FIRE10,0,0}, // S_FIRE9 + {SPR_FIRE,32771,2,A_Fire,S_FIRE11,0,0}, // S_FIRE10 + {SPR_FIRE,32770,2,A_Fire,S_FIRE12,0,0}, // S_FIRE11 + {SPR_FIRE,32771,2,A_Fire,S_FIRE13,0,0}, // S_FIRE12 + {SPR_FIRE,32770,2,A_Fire,S_FIRE14,0,0}, // S_FIRE13 + {SPR_FIRE,32771,2,A_Fire,S_FIRE15,0,0}, // S_FIRE14 + {SPR_FIRE,32772,2,A_Fire,S_FIRE16,0,0}, // S_FIRE15 + {SPR_FIRE,32771,2,A_Fire,S_FIRE17,0,0}, // S_FIRE16 + {SPR_FIRE,32772,2,A_Fire,S_FIRE18,0,0}, // S_FIRE17 + {SPR_FIRE,32771,2,A_Fire,S_FIRE19,0,0}, // S_FIRE18 + {SPR_FIRE,32772,2,A_FireCrackle,S_FIRE20,0,0}, // S_FIRE19 + {SPR_FIRE,32773,2,A_Fire,S_FIRE21,0,0}, // S_FIRE20 + {SPR_FIRE,32772,2,A_Fire,S_FIRE22,0,0}, // S_FIRE21 + {SPR_FIRE,32773,2,A_Fire,S_FIRE23,0,0}, // S_FIRE22 + {SPR_FIRE,32772,2,A_Fire,S_FIRE24,0,0}, // S_FIRE23 + {SPR_FIRE,32773,2,A_Fire,S_FIRE25,0,0}, // S_FIRE24 + {SPR_FIRE,32774,2,A_Fire,S_FIRE26,0,0}, // S_FIRE25 + {SPR_FIRE,32775,2,A_Fire,S_FIRE27,0,0}, // S_FIRE26 + {SPR_FIRE,32774,2,A_Fire,S_FIRE28,0,0}, // S_FIRE27 + {SPR_FIRE,32775,2,A_Fire,S_FIRE29,0,0}, // S_FIRE28 + {SPR_FIRE,32774,2,A_Fire,S_FIRE30,0,0}, // S_FIRE29 + {SPR_FIRE,32775,2,A_Fire,S_NULL,0,0}, // S_FIRE30 + {SPR_PUFF,1,4,NULL,S_SMOKE2,0,0}, // S_SMOKE1 + {SPR_PUFF,2,4,NULL,S_SMOKE3,0,0}, // S_SMOKE2 + {SPR_PUFF,1,4,NULL,S_SMOKE4,0,0}, // S_SMOKE3 + {SPR_PUFF,2,4,NULL,S_SMOKE5,0,0}, // S_SMOKE4 + {SPR_PUFF,3,4,NULL,S_NULL,0,0}, // S_SMOKE5 + {SPR_FATB,32768,2,A_Tracer,S_TRACER2,0,0}, // S_TRACER + {SPR_FATB,32769,2,A_Tracer,S_TRACER,0,0}, // S_TRACER2 + {SPR_FBXP,32768,8,NULL,S_TRACEEXP2,0,0}, // S_TRACEEXP1 + {SPR_FBXP,32769,6,NULL,S_TRACEEXP3,0,0}, // S_TRACEEXP2 + {SPR_FBXP,32770,4,NULL,S_NULL,0,0}, // S_TRACEEXP3 + {SPR_SKEL,0,10,A_Look,S_SKEL_STND2,0,0}, // S_SKEL_STND + {SPR_SKEL,1,10,A_Look,S_SKEL_STND,0,0}, // S_SKEL_STND2 + {SPR_SKEL,0,2,A_Chase,S_SKEL_RUN2,0,0}, // S_SKEL_RUN1 + {SPR_SKEL,0,2,A_Chase,S_SKEL_RUN3,0,0}, // S_SKEL_RUN2 + {SPR_SKEL,1,2,A_Chase,S_SKEL_RUN4,0,0}, // S_SKEL_RUN3 + {SPR_SKEL,1,2,A_Chase,S_SKEL_RUN5,0,0}, // S_SKEL_RUN4 + {SPR_SKEL,2,2,A_Chase,S_SKEL_RUN6,0,0}, // S_SKEL_RUN5 + {SPR_SKEL,2,2,A_Chase,S_SKEL_RUN7,0,0}, // S_SKEL_RUN6 + {SPR_SKEL,3,2,A_Chase,S_SKEL_RUN8,0,0}, // S_SKEL_RUN7 + {SPR_SKEL,3,2,A_Chase,S_SKEL_RUN9,0,0}, // S_SKEL_RUN8 + {SPR_SKEL,4,2,A_Chase,S_SKEL_RUN10,0,0}, // S_SKEL_RUN9 + {SPR_SKEL,4,2,A_Chase,S_SKEL_RUN11,0,0}, // S_SKEL_RUN10 + {SPR_SKEL,5,2,A_Chase,S_SKEL_RUN12,0,0}, // S_SKEL_RUN11 + {SPR_SKEL,5,2,A_Chase,S_SKEL_RUN1,0,0}, // S_SKEL_RUN12 + {SPR_SKEL,6,0,A_FaceTarget,S_SKEL_FIST2,0,0}, // S_SKEL_FIST1 + {SPR_SKEL,6,6,A_SkelWhoosh,S_SKEL_FIST3,0,0}, // S_SKEL_FIST2 + {SPR_SKEL,7,6,A_FaceTarget,S_SKEL_FIST4,0,0}, // S_SKEL_FIST3 + {SPR_SKEL,8,6,A_SkelFist,S_SKEL_RUN1,0,0}, // S_SKEL_FIST4 + {SPR_SKEL,32777,0,A_FaceTarget,S_SKEL_MISS2,0,0}, // S_SKEL_MISS1 + {SPR_SKEL,32777,10,A_FaceTarget,S_SKEL_MISS3,0,0}, // S_SKEL_MISS2 + {SPR_SKEL,10,10,A_SkelMissile,S_SKEL_MISS4,0,0}, // S_SKEL_MISS3 + {SPR_SKEL,10,10,A_FaceTarget,S_SKEL_RUN1,0,0}, // S_SKEL_MISS4 + {SPR_SKEL,11,5,NULL,S_SKEL_PAIN2,0,0}, // S_SKEL_PAIN + {SPR_SKEL,11,5,A_Pain,S_SKEL_RUN1,0,0}, // S_SKEL_PAIN2 + {SPR_SKEL,11,7,NULL,S_SKEL_DIE2,0,0}, // S_SKEL_DIE1 + {SPR_SKEL,12,7,NULL,S_SKEL_DIE3,0,0}, // S_SKEL_DIE2 + {SPR_SKEL,13,7,A_Scream,S_SKEL_DIE4,0,0}, // S_SKEL_DIE3 + {SPR_SKEL,14,7,A_Fall,S_SKEL_DIE5,0,0}, // S_SKEL_DIE4 + {SPR_SKEL,15,7,NULL,S_SKEL_DIE6,0,0}, // S_SKEL_DIE5 + {SPR_SKEL,16,-1,NULL,S_NULL,0,0}, // S_SKEL_DIE6 + {SPR_SKEL,16,5,NULL,S_SKEL_RAISE2,0,0}, // S_SKEL_RAISE1 + {SPR_SKEL,15,5,NULL,S_SKEL_RAISE3,0,0}, // S_SKEL_RAISE2 + {SPR_SKEL,14,5,NULL,S_SKEL_RAISE4,0,0}, // S_SKEL_RAISE3 + {SPR_SKEL,13,5,NULL,S_SKEL_RAISE5,0,0}, // S_SKEL_RAISE4 + {SPR_SKEL,12,5,NULL,S_SKEL_RAISE6,0,0}, // S_SKEL_RAISE5 + {SPR_SKEL,11,5,NULL,S_SKEL_RUN1,0,0}, // S_SKEL_RAISE6 + {SPR_MANF,32768,4,NULL,S_FATSHOT2,0,0}, // S_FATSHOT1 + {SPR_MANF,32769,4,NULL,S_FATSHOT1,0,0}, // S_FATSHOT2 + {SPR_MISL,32769,8,NULL,S_FATSHOTX2,0,0}, // S_FATSHOTX1 + {SPR_MISL,32770,6,NULL,S_FATSHOTX3,0,0}, // S_FATSHOTX2 + {SPR_MISL,32771,4,NULL,S_NULL,0,0}, // S_FATSHOTX3 + {SPR_FATT,0,15,A_Look,S_FATT_STND2,0,0}, // S_FATT_STND + {SPR_FATT,1,15,A_Look,S_FATT_STND,0,0}, // S_FATT_STND2 + {SPR_FATT,0,4,A_Chase,S_FATT_RUN2,0,0}, // S_FATT_RUN1 + {SPR_FATT,0,4,A_Chase,S_FATT_RUN3,0,0}, // S_FATT_RUN2 + {SPR_FATT,1,4,A_Chase,S_FATT_RUN4,0,0}, // S_FATT_RUN3 + {SPR_FATT,1,4,A_Chase,S_FATT_RUN5,0,0}, // S_FATT_RUN4 + {SPR_FATT,2,4,A_Chase,S_FATT_RUN6,0,0}, // S_FATT_RUN5 + {SPR_FATT,2,4,A_Chase,S_FATT_RUN7,0,0}, // S_FATT_RUN6 + {SPR_FATT,3,4,A_Chase,S_FATT_RUN8,0,0}, // S_FATT_RUN7 + {SPR_FATT,3,4,A_Chase,S_FATT_RUN9,0,0}, // S_FATT_RUN8 + {SPR_FATT,4,4,A_Chase,S_FATT_RUN10,0,0}, // S_FATT_RUN9 + {SPR_FATT,4,4,A_Chase,S_FATT_RUN11,0,0}, // S_FATT_RUN10 + {SPR_FATT,5,4,A_Chase,S_FATT_RUN12,0,0}, // S_FATT_RUN11 + {SPR_FATT,5,4,A_Chase,S_FATT_RUN1,0,0}, // S_FATT_RUN12 + {SPR_FATT,6,20,A_FatRaise,S_FATT_ATK2,0,0}, // S_FATT_ATK1 + {SPR_FATT,32775,10,A_FatAttack1,S_FATT_ATK3,0,0}, // S_FATT_ATK2 + {SPR_FATT,8,5,A_FaceTarget,S_FATT_ATK4,0,0}, // S_FATT_ATK3 + {SPR_FATT,6,5,A_FaceTarget,S_FATT_ATK5,0,0}, // S_FATT_ATK4 + {SPR_FATT,32775,10,A_FatAttack2,S_FATT_ATK6,0,0}, // S_FATT_ATK5 + {SPR_FATT,8,5,A_FaceTarget,S_FATT_ATK7,0,0}, // S_FATT_ATK6 + {SPR_FATT,6,5,A_FaceTarget,S_FATT_ATK8,0,0}, // S_FATT_ATK7 + {SPR_FATT,32775,10,A_FatAttack3,S_FATT_ATK9,0,0}, // S_FATT_ATK8 + {SPR_FATT,8,5,A_FaceTarget,S_FATT_ATK10,0,0}, // S_FATT_ATK9 + {SPR_FATT,6,5,A_FaceTarget,S_FATT_RUN1,0,0}, // S_FATT_ATK10 + {SPR_FATT,9,3,NULL,S_FATT_PAIN2,0,0}, // S_FATT_PAIN + {SPR_FATT,9,3,A_Pain,S_FATT_RUN1,0,0}, // S_FATT_PAIN2 + {SPR_FATT,10,6,NULL,S_FATT_DIE2,0,0}, // S_FATT_DIE1 + {SPR_FATT,11,6,A_Scream,S_FATT_DIE3,0,0}, // S_FATT_DIE2 + {SPR_FATT,12,6,A_Fall,S_FATT_DIE4,0,0}, // S_FATT_DIE3 + {SPR_FATT,13,6,NULL,S_FATT_DIE5,0,0}, // S_FATT_DIE4 + {SPR_FATT,14,6,NULL,S_FATT_DIE6,0,0}, // S_FATT_DIE5 + {SPR_FATT,15,6,NULL,S_FATT_DIE7,0,0}, // S_FATT_DIE6 + {SPR_FATT,16,6,NULL,S_FATT_DIE8,0,0}, // S_FATT_DIE7 + {SPR_FATT,17,6,NULL,S_FATT_DIE9,0,0}, // S_FATT_DIE8 + {SPR_FATT,18,6,NULL,S_FATT_DIE10,0,0}, // S_FATT_DIE9 + {SPR_FATT,19,-1,A_BossDeath,S_NULL,0,0}, // S_FATT_DIE10 + {SPR_FATT,17,5,NULL,S_FATT_RAISE2,0,0}, // S_FATT_RAISE1 + {SPR_FATT,16,5,NULL,S_FATT_RAISE3,0,0}, // S_FATT_RAISE2 + {SPR_FATT,15,5,NULL,S_FATT_RAISE4,0,0}, // S_FATT_RAISE3 + {SPR_FATT,14,5,NULL,S_FATT_RAISE5,0,0}, // S_FATT_RAISE4 + {SPR_FATT,13,5,NULL,S_FATT_RAISE6,0,0}, // S_FATT_RAISE5 + {SPR_FATT,12,5,NULL,S_FATT_RAISE7,0,0}, // S_FATT_RAISE6 + {SPR_FATT,11,5,NULL,S_FATT_RAISE8,0,0}, // S_FATT_RAISE7 + {SPR_FATT,10,5,NULL,S_FATT_RUN1,0,0}, // S_FATT_RAISE8 + {SPR_CPOS,0,10,A_Look,S_CPOS_STND2,0,0}, // S_CPOS_STND + {SPR_CPOS,1,10,A_Look,S_CPOS_STND,0,0}, // S_CPOS_STND2 + {SPR_CPOS,0,3,A_Chase,S_CPOS_RUN2,0,0}, // S_CPOS_RUN1 + {SPR_CPOS,0,3,A_Chase,S_CPOS_RUN3,0,0}, // S_CPOS_RUN2 + {SPR_CPOS,1,3,A_Chase,S_CPOS_RUN4,0,0}, // S_CPOS_RUN3 + {SPR_CPOS,1,3,A_Chase,S_CPOS_RUN5,0,0}, // S_CPOS_RUN4 + {SPR_CPOS,2,3,A_Chase,S_CPOS_RUN6,0,0}, // S_CPOS_RUN5 + {SPR_CPOS,2,3,A_Chase,S_CPOS_RUN7,0,0}, // S_CPOS_RUN6 + {SPR_CPOS,3,3,A_Chase,S_CPOS_RUN8,0,0}, // S_CPOS_RUN7 + {SPR_CPOS,3,3,A_Chase,S_CPOS_RUN1,0,0}, // S_CPOS_RUN8 + {SPR_CPOS,4,10,A_FaceTarget,S_CPOS_ATK2,0,0}, // S_CPOS_ATK1 + {SPR_CPOS,32773,4,A_CPosAttack,S_CPOS_ATK3,0,0}, // S_CPOS_ATK2 + {SPR_CPOS,32772,4,A_CPosAttack,S_CPOS_ATK4,0,0}, // S_CPOS_ATK3 + {SPR_CPOS,5,1,A_CPosRefire,S_CPOS_ATK2,0,0}, // S_CPOS_ATK4 + {SPR_CPOS,6,3,NULL,S_CPOS_PAIN2,0,0}, // S_CPOS_PAIN + {SPR_CPOS,6,3,A_Pain,S_CPOS_RUN1,0,0}, // S_CPOS_PAIN2 + {SPR_CPOS,7,5,NULL,S_CPOS_DIE2,0,0}, // S_CPOS_DIE1 + {SPR_CPOS,8,5,A_Scream,S_CPOS_DIE3,0,0}, // S_CPOS_DIE2 + {SPR_CPOS,9,5,A_Fall,S_CPOS_DIE4,0,0}, // S_CPOS_DIE3 + {SPR_CPOS,10,5,NULL,S_CPOS_DIE5,0,0}, // S_CPOS_DIE4 + {SPR_CPOS,11,5,NULL,S_CPOS_DIE6,0,0}, // S_CPOS_DIE5 + {SPR_CPOS,12,5,NULL,S_CPOS_DIE7,0,0}, // S_CPOS_DIE6 + {SPR_CPOS,13,-1,NULL,S_NULL,0,0}, // S_CPOS_DIE7 + {SPR_CPOS,14,5,NULL,S_CPOS_XDIE2,0,0}, // S_CPOS_XDIE1 + {SPR_CPOS,15,5,A_XScream,S_CPOS_XDIE3,0,0}, // S_CPOS_XDIE2 + {SPR_CPOS,16,5,A_Fall,S_CPOS_XDIE4,0,0}, // S_CPOS_XDIE3 + {SPR_CPOS,17,5,NULL,S_CPOS_XDIE5,0,0}, // S_CPOS_XDIE4 + {SPR_CPOS,18,5,NULL,S_CPOS_XDIE6,0,0}, // S_CPOS_XDIE5 + {SPR_CPOS,19,-1,NULL,S_NULL,0,0}, // S_CPOS_XDIE6 + {SPR_CPOS,13,5,NULL,S_CPOS_RAISE2,0,0}, // S_CPOS_RAISE1 + {SPR_CPOS,12,5,NULL,S_CPOS_RAISE3,0,0}, // S_CPOS_RAISE2 + {SPR_CPOS,11,5,NULL,S_CPOS_RAISE4,0,0}, // S_CPOS_RAISE3 + {SPR_CPOS,10,5,NULL,S_CPOS_RAISE5,0,0}, // S_CPOS_RAISE4 + {SPR_CPOS,9,5,NULL,S_CPOS_RAISE6,0,0}, // S_CPOS_RAISE5 + {SPR_CPOS,8,5,NULL,S_CPOS_RAISE7,0,0}, // S_CPOS_RAISE6 + {SPR_CPOS,7,5,NULL,S_CPOS_RUN1,0,0}, // S_CPOS_RAISE7 + {SPR_TROO,0,10,A_Look,S_TROO_STND2,0,0}, // S_TROO_STND + {SPR_TROO,1,10,A_Look,S_TROO_STND,0,0}, // S_TROO_STND2 + {SPR_TROO,0,3,A_Chase,S_TROO_RUN2,0,0}, // S_TROO_RUN1 + {SPR_TROO,0,3,A_Chase,S_TROO_RUN3,0,0}, // S_TROO_RUN2 + {SPR_TROO,1,3,A_Chase,S_TROO_RUN4,0,0}, // S_TROO_RUN3 + {SPR_TROO,1,3,A_Chase,S_TROO_RUN5,0,0}, // S_TROO_RUN4 + {SPR_TROO,2,3,A_Chase,S_TROO_RUN6,0,0}, // S_TROO_RUN5 + {SPR_TROO,2,3,A_Chase,S_TROO_RUN7,0,0}, // S_TROO_RUN6 + {SPR_TROO,3,3,A_Chase,S_TROO_RUN8,0,0}, // S_TROO_RUN7 + {SPR_TROO,3,3,A_Chase,S_TROO_RUN1,0,0}, // S_TROO_RUN8 + {SPR_TROO,4,8,A_FaceTarget,S_TROO_ATK2,0,0}, // S_TROO_ATK1 + {SPR_TROO,5,8,A_FaceTarget,S_TROO_ATK3,0,0}, // S_TROO_ATK2 + {SPR_TROO,6,6,A_TroopAttack,S_TROO_RUN1,0,0}, // S_TROO_ATK3 + {SPR_TROO,7,2,NULL,S_TROO_PAIN2,0,0}, // S_TROO_PAIN + {SPR_TROO,7,2,A_Pain,S_TROO_RUN1,0,0}, // S_TROO_PAIN2 + {SPR_TROO,8,8,NULL,S_TROO_DIE2,0,0}, // S_TROO_DIE1 + {SPR_TROO,9,8,A_Scream,S_TROO_DIE3,0,0}, // S_TROO_DIE2 + {SPR_TROO,10,6,NULL,S_TROO_DIE4,0,0}, // S_TROO_DIE3 + {SPR_TROO,11,6,A_Fall,S_TROO_DIE5,0,0}, // S_TROO_DIE4 + {SPR_TROO,12,-1,NULL,S_NULL,0,0}, // S_TROO_DIE5 + {SPR_TROO,13,5,NULL,S_TROO_XDIE2,0,0}, // S_TROO_XDIE1 + {SPR_TROO,14,5,A_XScream,S_TROO_XDIE3,0,0}, // S_TROO_XDIE2 + {SPR_TROO,15,5,NULL,S_TROO_XDIE4,0,0}, // S_TROO_XDIE3 + {SPR_TROO,16,5,A_Fall,S_TROO_XDIE5,0,0}, // S_TROO_XDIE4 + {SPR_TROO,17,5,NULL,S_TROO_XDIE6,0,0}, // S_TROO_XDIE5 + {SPR_TROO,18,5,NULL,S_TROO_XDIE7,0,0}, // S_TROO_XDIE6 + {SPR_TROO,19,5,NULL,S_TROO_XDIE8,0,0}, // S_TROO_XDIE7 + {SPR_TROO,20,-1,NULL,S_NULL,0,0}, // S_TROO_XDIE8 + {SPR_TROO,12,8,NULL,S_TROO_RAISE2,0,0}, // S_TROO_RAISE1 + {SPR_TROO,11,8,NULL,S_TROO_RAISE3,0,0}, // S_TROO_RAISE2 + {SPR_TROO,10,6,NULL,S_TROO_RAISE4,0,0}, // S_TROO_RAISE3 + {SPR_TROO,9,6,NULL,S_TROO_RAISE5,0,0}, // S_TROO_RAISE4 + {SPR_TROO,8,6,NULL,S_TROO_RUN1,0,0}, // S_TROO_RAISE5 + {SPR_SARG,0,10,A_Look,S_SARG_STND2,0,0}, // S_SARG_STND + {SPR_SARG,1,10,A_Look,S_SARG_STND,0,0}, // S_SARG_STND2 + {SPR_SARG,0,2,A_Chase,S_SARG_RUN2,0,0}, // S_SARG_RUN1 + {SPR_SARG,0,2,A_Chase,S_SARG_RUN3,0,0}, // S_SARG_RUN2 + {SPR_SARG,1,2,A_Chase,S_SARG_RUN4,0,0}, // S_SARG_RUN3 + {SPR_SARG,1,2,A_Chase,S_SARG_RUN5,0,0}, // S_SARG_RUN4 + {SPR_SARG,2,2,A_Chase,S_SARG_RUN6,0,0}, // S_SARG_RUN5 + {SPR_SARG,2,2,A_Chase,S_SARG_RUN7,0,0}, // S_SARG_RUN6 + {SPR_SARG,3,2,A_Chase,S_SARG_RUN8,0,0}, // S_SARG_RUN7 + {SPR_SARG,3,2,A_Chase,S_SARG_RUN1,0,0}, // S_SARG_RUN8 + {SPR_SARG,4,8,A_FaceTarget,S_SARG_ATK2,0,0}, // S_SARG_ATK1 + {SPR_SARG,5,8,A_FaceTarget,S_SARG_ATK3,0,0}, // S_SARG_ATK2 + {SPR_SARG,6,8,A_SargAttack,S_SARG_RUN1,0,0}, // S_SARG_ATK3 + {SPR_SARG,7,2,NULL,S_SARG_PAIN2,0,0}, // S_SARG_PAIN + {SPR_SARG,7,2,A_Pain,S_SARG_RUN1,0,0}, // S_SARG_PAIN2 + {SPR_SARG,8,8,NULL,S_SARG_DIE2,0,0}, // S_SARG_DIE1 + {SPR_SARG,9,8,A_Scream,S_SARG_DIE3,0,0}, // S_SARG_DIE2 + {SPR_SARG,10,4,NULL,S_SARG_DIE4,0,0}, // S_SARG_DIE3 + {SPR_SARG,11,4,A_Fall,S_SARG_DIE5,0,0}, // S_SARG_DIE4 + {SPR_SARG,12,4,NULL,S_SARG_DIE6,0,0}, // S_SARG_DIE5 + {SPR_SARG,13,-1,NULL,S_NULL,0,0}, // S_SARG_DIE6 + {SPR_SARG,13,5,NULL,S_SARG_RAISE2,0,0}, // S_SARG_RAISE1 + {SPR_SARG,12,5,NULL,S_SARG_RAISE3,0,0}, // S_SARG_RAISE2 + {SPR_SARG,11,5,NULL,S_SARG_RAISE4,0,0}, // S_SARG_RAISE3 + {SPR_SARG,10,5,NULL,S_SARG_RAISE5,0,0}, // S_SARG_RAISE4 + {SPR_SARG,9,5,NULL,S_SARG_RAISE6,0,0}, // S_SARG_RAISE5 + {SPR_SARG,8,5,NULL,S_SARG_RUN1,0,0}, // S_SARG_RAISE6 + {SPR_HEAD,0,10,A_Look,S_HEAD_STND,0,0}, // S_HEAD_STND + {SPR_HEAD,0,3,A_Chase,S_HEAD_RUN1,0,0}, // S_HEAD_RUN1 + {SPR_HEAD,1,5,A_FaceTarget,S_HEAD_ATK2,0,0}, // S_HEAD_ATK1 + {SPR_HEAD,2,5,A_FaceTarget,S_HEAD_ATK3,0,0}, // S_HEAD_ATK2 + {SPR_HEAD,32771,5,A_HeadAttack,S_HEAD_RUN1,0,0}, // S_HEAD_ATK3 + {SPR_HEAD,4,3,NULL,S_HEAD_PAIN2,0,0}, // S_HEAD_PAIN + {SPR_HEAD,4,3,A_Pain,S_HEAD_PAIN3,0,0}, // S_HEAD_PAIN2 + {SPR_HEAD,5,6,NULL,S_HEAD_RUN1,0,0}, // S_HEAD_PAIN3 + {SPR_HEAD,6,8,NULL,S_HEAD_DIE2,0,0}, // S_HEAD_DIE1 + {SPR_HEAD,7,8,A_Scream,S_HEAD_DIE3,0,0}, // S_HEAD_DIE2 + {SPR_HEAD,8,8,NULL,S_HEAD_DIE4,0,0}, // S_HEAD_DIE3 + {SPR_HEAD,9,8,NULL,S_HEAD_DIE5,0,0}, // S_HEAD_DIE4 + {SPR_HEAD,10,8,A_Fall,S_HEAD_DIE6,0,0}, // S_HEAD_DIE5 + {SPR_HEAD,11,-1,NULL,S_NULL,0,0}, // S_HEAD_DIE6 + {SPR_HEAD,11,8,NULL,S_HEAD_RAISE2,0,0}, // S_HEAD_RAISE1 + {SPR_HEAD,10,8,NULL,S_HEAD_RAISE3,0,0}, // S_HEAD_RAISE2 + {SPR_HEAD,9,8,NULL,S_HEAD_RAISE4,0,0}, // S_HEAD_RAISE3 + {SPR_HEAD,8,8,NULL,S_HEAD_RAISE5,0,0}, // S_HEAD_RAISE4 + {SPR_HEAD,7,8,NULL,S_HEAD_RAISE6,0,0}, // S_HEAD_RAISE5 + {SPR_HEAD,6,8,NULL,S_HEAD_RUN1,0,0}, // S_HEAD_RAISE6 + {SPR_BAL7,32768,4,NULL,S_BRBALL2,0,0}, // S_BRBALL1 + {SPR_BAL7,32769,4,NULL,S_BRBALL1,0,0}, // S_BRBALL2 + {SPR_BAL7,32770,6,NULL,S_BRBALLX2,0,0}, // S_BRBALLX1 + {SPR_BAL7,32771,6,NULL,S_BRBALLX3,0,0}, // S_BRBALLX2 + {SPR_BAL7,32772,6,NULL,S_NULL,0,0}, // S_BRBALLX3 + {SPR_BOSS,0,10,A_Look,S_BOSS_STND2,0,0}, // S_BOSS_STND + {SPR_BOSS,1,10,A_Look,S_BOSS_STND,0,0}, // S_BOSS_STND2 + {SPR_BOSS,0,3,A_Chase,S_BOSS_RUN2,0,0}, // S_BOSS_RUN1 + {SPR_BOSS,0,3,A_Chase,S_BOSS_RUN3,0,0}, // S_BOSS_RUN2 + {SPR_BOSS,1,3,A_Chase,S_BOSS_RUN4,0,0}, // S_BOSS_RUN3 + {SPR_BOSS,1,3,A_Chase,S_BOSS_RUN5,0,0}, // S_BOSS_RUN4 + {SPR_BOSS,2,3,A_Chase,S_BOSS_RUN6,0,0}, // S_BOSS_RUN5 + {SPR_BOSS,2,3,A_Chase,S_BOSS_RUN7,0,0}, // S_BOSS_RUN6 + {SPR_BOSS,3,3,A_Chase,S_BOSS_RUN8,0,0}, // S_BOSS_RUN7 + {SPR_BOSS,3,3,A_Chase,S_BOSS_RUN1,0,0}, // S_BOSS_RUN8 + {SPR_BOSS,4,8,A_FaceTarget,S_BOSS_ATK2,0,0}, // S_BOSS_ATK1 + {SPR_BOSS,5,8,A_FaceTarget,S_BOSS_ATK3,0,0}, // S_BOSS_ATK2 + {SPR_BOSS,6,8,A_BruisAttack,S_BOSS_RUN1,0,0}, // S_BOSS_ATK3 + {SPR_BOSS,7,2,NULL,S_BOSS_PAIN2,0,0}, // S_BOSS_PAIN + {SPR_BOSS,7,2,A_Pain,S_BOSS_RUN1,0,0}, // S_BOSS_PAIN2 + {SPR_BOSS,8,8,NULL,S_BOSS_DIE2,0,0}, // S_BOSS_DIE1 + {SPR_BOSS,9,8,A_Scream,S_BOSS_DIE3,0,0}, // S_BOSS_DIE2 + {SPR_BOSS,10,8,NULL,S_BOSS_DIE4,0,0}, // S_BOSS_DIE3 + {SPR_BOSS,11,8,A_Fall,S_BOSS_DIE5,0,0}, // S_BOSS_DIE4 + {SPR_BOSS,12,8,NULL,S_BOSS_DIE6,0,0}, // S_BOSS_DIE5 + {SPR_BOSS,13,8,NULL,S_BOSS_DIE7,0,0}, // S_BOSS_DIE6 + {SPR_BOSS,14,-1,A_BossDeath,S_NULL,0,0}, // S_BOSS_DIE7 + {SPR_BOSS,14,8,NULL,S_BOSS_RAISE2,0,0}, // S_BOSS_RAISE1 + {SPR_BOSS,13,8,NULL,S_BOSS_RAISE3,0,0}, // S_BOSS_RAISE2 + {SPR_BOSS,12,8,NULL,S_BOSS_RAISE4,0,0}, // S_BOSS_RAISE3 + {SPR_BOSS,11,8,NULL,S_BOSS_RAISE5,0,0}, // S_BOSS_RAISE4 + {SPR_BOSS,10,8,NULL,S_BOSS_RAISE6,0,0}, // S_BOSS_RAISE5 + {SPR_BOSS,9,8,NULL,S_BOSS_RAISE7,0,0}, // S_BOSS_RAISE6 + {SPR_BOSS,8,8,NULL,S_BOSS_RUN1,0,0}, // S_BOSS_RAISE7 + {SPR_BOS2,0,10,A_Look,S_BOS2_STND2,0,0}, // S_BOS2_STND + {SPR_BOS2,1,10,A_Look,S_BOS2_STND,0,0}, // S_BOS2_STND2 + {SPR_BOS2,0,3,A_Chase,S_BOS2_RUN2,0,0}, // S_BOS2_RUN1 + {SPR_BOS2,0,3,A_Chase,S_BOS2_RUN3,0,0}, // S_BOS2_RUN2 + {SPR_BOS2,1,3,A_Chase,S_BOS2_RUN4,0,0}, // S_BOS2_RUN3 + {SPR_BOS2,1,3,A_Chase,S_BOS2_RUN5,0,0}, // S_BOS2_RUN4 + {SPR_BOS2,2,3,A_Chase,S_BOS2_RUN6,0,0}, // S_BOS2_RUN5 + {SPR_BOS2,2,3,A_Chase,S_BOS2_RUN7,0,0}, // S_BOS2_RUN6 + {SPR_BOS2,3,3,A_Chase,S_BOS2_RUN8,0,0}, // S_BOS2_RUN7 + {SPR_BOS2,3,3,A_Chase,S_BOS2_RUN1,0,0}, // S_BOS2_RUN8 + {SPR_BOS2,4,8,A_FaceTarget,S_BOS2_ATK2,0,0}, // S_BOS2_ATK1 + {SPR_BOS2,5,8,A_FaceTarget,S_BOS2_ATK3,0,0}, // S_BOS2_ATK2 + {SPR_BOS2,6,8,A_BruisAttack,S_BOS2_RUN1,0,0}, // S_BOS2_ATK3 + {SPR_BOS2,7,2,NULL,S_BOS2_PAIN2,0,0}, // S_BOS2_PAIN + {SPR_BOS2,7,2,A_Pain,S_BOS2_RUN1,0,0}, // S_BOS2_PAIN2 + {SPR_BOS2,8,8,NULL,S_BOS2_DIE2,0,0}, // S_BOS2_DIE1 + {SPR_BOS2,9,8,A_Scream,S_BOS2_DIE3,0,0}, // S_BOS2_DIE2 + {SPR_BOS2,10,8,NULL,S_BOS2_DIE4,0,0}, // S_BOS2_DIE3 + {SPR_BOS2,11,8,A_Fall,S_BOS2_DIE5,0,0}, // S_BOS2_DIE4 + {SPR_BOS2,12,8,NULL,S_BOS2_DIE6,0,0}, // S_BOS2_DIE5 + {SPR_BOS2,13,8,NULL,S_BOS2_DIE7,0,0}, // S_BOS2_DIE6 + {SPR_BOS2,14,-1,NULL,S_NULL,0,0}, // S_BOS2_DIE7 + {SPR_BOS2,14,8,NULL,S_BOS2_RAISE2,0,0}, // S_BOS2_RAISE1 + {SPR_BOS2,13,8,NULL,S_BOS2_RAISE3,0,0}, // S_BOS2_RAISE2 + {SPR_BOS2,12,8,NULL,S_BOS2_RAISE4,0,0}, // S_BOS2_RAISE3 + {SPR_BOS2,11,8,NULL,S_BOS2_RAISE5,0,0}, // S_BOS2_RAISE4 + {SPR_BOS2,10,8,NULL,S_BOS2_RAISE6,0,0}, // S_BOS2_RAISE5 + {SPR_BOS2,9,8,NULL,S_BOS2_RAISE7,0,0}, // S_BOS2_RAISE6 + {SPR_BOS2,8,8,NULL,S_BOS2_RUN1,0,0}, // S_BOS2_RAISE7 + {SPR_SKUL,32768,10,A_Look,S_SKULL_STND2,0,0}, // S_SKULL_STND + {SPR_SKUL,32769,10,A_Look,S_SKULL_STND,0,0}, // S_SKULL_STND2 + {SPR_SKUL,32768,6,A_Chase,S_SKULL_RUN2,0,0}, // S_SKULL_RUN1 + {SPR_SKUL,32769,6,A_Chase,S_SKULL_RUN1,0,0}, // S_SKULL_RUN2 + {SPR_SKUL,32770,10,A_FaceTarget,S_SKULL_ATK2,0,0}, // S_SKULL_ATK1 + {SPR_SKUL,32771,4,A_SkullAttack,S_SKULL_ATK3,0,0}, // S_SKULL_ATK2 + {SPR_SKUL,32770,4,NULL,S_SKULL_ATK4,0,0}, // S_SKULL_ATK3 + {SPR_SKUL,32771,4,NULL,S_SKULL_ATK3,0,0}, // S_SKULL_ATK4 + {SPR_SKUL,32772,3,NULL,S_SKULL_PAIN2,0,0}, // S_SKULL_PAIN + {SPR_SKUL,32772,3,A_Pain,S_SKULL_RUN1,0,0}, // S_SKULL_PAIN2 + {SPR_SKUL,32773,6,NULL,S_SKULL_DIE2,0,0}, // S_SKULL_DIE1 + {SPR_SKUL,32774,6,A_Scream,S_SKULL_DIE3,0,0}, // S_SKULL_DIE2 + {SPR_SKUL,32775,6,NULL,S_SKULL_DIE4,0,0}, // S_SKULL_DIE3 + {SPR_SKUL,32776,6,A_Fall,S_SKULL_DIE5,0,0}, // S_SKULL_DIE4 + {SPR_SKUL,9,6,NULL,S_SKULL_DIE6,0,0}, // S_SKULL_DIE5 + {SPR_SKUL,10,6,NULL,S_NULL,0,0}, // S_SKULL_DIE6 + {SPR_SPID,0,10,A_Look,S_SPID_STND2,0,0}, // S_SPID_STND + {SPR_SPID,1,10,A_Look,S_SPID_STND,0,0}, // S_SPID_STND2 + {SPR_SPID,0,3,A_Metal,S_SPID_RUN2,0,0}, // S_SPID_RUN1 + {SPR_SPID,0,3,A_Chase,S_SPID_RUN3,0,0}, // S_SPID_RUN2 + {SPR_SPID,1,3,A_Chase,S_SPID_RUN4,0,0}, // S_SPID_RUN3 + {SPR_SPID,1,3,A_Chase,S_SPID_RUN5,0,0}, // S_SPID_RUN4 + {SPR_SPID,2,3,A_Metal,S_SPID_RUN6,0,0}, // S_SPID_RUN5 + {SPR_SPID,2,3,A_Chase,S_SPID_RUN7,0,0}, // S_SPID_RUN6 + {SPR_SPID,3,3,A_Chase,S_SPID_RUN8,0,0}, // S_SPID_RUN7 + {SPR_SPID,3,3,A_Chase,S_SPID_RUN9,0,0}, // S_SPID_RUN8 + {SPR_SPID,4,3,A_Metal,S_SPID_RUN10,0,0}, // S_SPID_RUN9 + {SPR_SPID,4,3,A_Chase,S_SPID_RUN11,0,0}, // S_SPID_RUN10 + {SPR_SPID,5,3,A_Chase,S_SPID_RUN12,0,0}, // S_SPID_RUN11 + {SPR_SPID,5,3,A_Chase,S_SPID_RUN1,0,0}, // S_SPID_RUN12 + {SPR_SPID,32768,20,A_FaceTarget,S_SPID_ATK2,0,0}, // S_SPID_ATK1 + {SPR_SPID,32774,4,A_SPosAttack,S_SPID_ATK3,0,0}, // S_SPID_ATK2 + {SPR_SPID,32775,4,A_SPosAttack,S_SPID_ATK4,0,0}, // S_SPID_ATK3 + {SPR_SPID,32775,1,A_SpidRefire,S_SPID_ATK2,0,0}, // S_SPID_ATK4 + {SPR_SPID,8,3,NULL,S_SPID_PAIN2,0,0}, // S_SPID_PAIN + {SPR_SPID,8,3,A_Pain,S_SPID_RUN1,0,0}, // S_SPID_PAIN2 + {SPR_SPID,9,20,A_Scream,S_SPID_DIE2,0,0}, // S_SPID_DIE1 + {SPR_SPID,10,10,A_Fall,S_SPID_DIE3,0,0}, // S_SPID_DIE2 + {SPR_SPID,11,10,NULL,S_SPID_DIE4,0,0}, // S_SPID_DIE3 + {SPR_SPID,12,10,NULL,S_SPID_DIE5,0,0}, // S_SPID_DIE4 + {SPR_SPID,13,10,NULL,S_SPID_DIE6,0,0}, // S_SPID_DIE5 + {SPR_SPID,14,10,NULL,S_SPID_DIE7,0,0}, // S_SPID_DIE6 + {SPR_SPID,15,10,NULL,S_SPID_DIE8,0,0}, // S_SPID_DIE7 + {SPR_SPID,16,10,NULL,S_SPID_DIE9,0,0}, // S_SPID_DIE8 + {SPR_SPID,17,10,NULL,S_SPID_DIE10,0,0}, // S_SPID_DIE9 + {SPR_SPID,18,30,NULL,S_SPID_DIE11,0,0}, // S_SPID_DIE10 + {SPR_SPID,18,-1,A_BossDeath,S_NULL,0,0}, // S_SPID_DIE11 + {SPR_BSPI,0,10,A_Look,S_BSPI_STND2,0,0}, // S_BSPI_STND + {SPR_BSPI,1,10,A_Look,S_BSPI_STND,0,0}, // S_BSPI_STND2 + {SPR_BSPI,0,20,NULL,S_BSPI_RUN1,0,0}, // S_BSPI_SIGHT + {SPR_BSPI,0,3,A_BabyMetal,S_BSPI_RUN2,0,0}, // S_BSPI_RUN1 + {SPR_BSPI,0,3,A_Chase,S_BSPI_RUN3,0,0}, // S_BSPI_RUN2 + {SPR_BSPI,1,3,A_Chase,S_BSPI_RUN4,0,0}, // S_BSPI_RUN3 + {SPR_BSPI,1,3,A_Chase,S_BSPI_RUN5,0,0}, // S_BSPI_RUN4 + {SPR_BSPI,2,3,A_Chase,S_BSPI_RUN6,0,0}, // S_BSPI_RUN5 + {SPR_BSPI,2,3,A_Chase,S_BSPI_RUN7,0,0}, // S_BSPI_RUN6 + {SPR_BSPI,3,3,A_BabyMetal,S_BSPI_RUN8,0,0}, // S_BSPI_RUN7 + {SPR_BSPI,3,3,A_Chase,S_BSPI_RUN9,0,0}, // S_BSPI_RUN8 + {SPR_BSPI,4,3,A_Chase,S_BSPI_RUN10,0,0}, // S_BSPI_RUN9 + {SPR_BSPI,4,3,A_Chase,S_BSPI_RUN11,0,0}, // S_BSPI_RUN10 + {SPR_BSPI,5,3,A_Chase,S_BSPI_RUN12,0,0}, // S_BSPI_RUN11 + {SPR_BSPI,5,3,A_Chase,S_BSPI_RUN1,0,0}, // S_BSPI_RUN12 + {SPR_BSPI,32768,20,A_FaceTarget,S_BSPI_ATK2,0,0}, // S_BSPI_ATK1 + {SPR_BSPI,32774,4,A_BspiAttack,S_BSPI_ATK3,0,0}, // S_BSPI_ATK2 + {SPR_BSPI,32775,4,NULL,S_BSPI_ATK4,0,0}, // S_BSPI_ATK3 + {SPR_BSPI,32775,1,A_SpidRefire,S_BSPI_ATK2,0,0}, // S_BSPI_ATK4 + {SPR_BSPI,8,3,NULL,S_BSPI_PAIN2,0,0}, // S_BSPI_PAIN + {SPR_BSPI,8,3,A_Pain,S_BSPI_RUN1,0,0}, // S_BSPI_PAIN2 + {SPR_BSPI,9,20,A_Scream,S_BSPI_DIE2,0,0}, // S_BSPI_DIE1 + {SPR_BSPI,10,7,A_Fall,S_BSPI_DIE3,0,0}, // S_BSPI_DIE2 + {SPR_BSPI,11,7,NULL,S_BSPI_DIE4,0,0}, // S_BSPI_DIE3 + {SPR_BSPI,12,7,NULL,S_BSPI_DIE5,0,0}, // S_BSPI_DIE4 + {SPR_BSPI,13,7,NULL,S_BSPI_DIE6,0,0}, // S_BSPI_DIE5 + {SPR_BSPI,14,7,NULL,S_BSPI_DIE7,0,0}, // S_BSPI_DIE6 + {SPR_BSPI,15,-1,A_BossDeath,S_NULL,0,0}, // S_BSPI_DIE7 + {SPR_BSPI,15,5,NULL,S_BSPI_RAISE2,0,0}, // S_BSPI_RAISE1 + {SPR_BSPI,14,5,NULL,S_BSPI_RAISE3,0,0}, // S_BSPI_RAISE2 + {SPR_BSPI,13,5,NULL,S_BSPI_RAISE4,0,0}, // S_BSPI_RAISE3 + {SPR_BSPI,12,5,NULL,S_BSPI_RAISE5,0,0}, // S_BSPI_RAISE4 + {SPR_BSPI,11,5,NULL,S_BSPI_RAISE6,0,0}, // S_BSPI_RAISE5 + {SPR_BSPI,10,5,NULL,S_BSPI_RAISE7,0,0}, // S_BSPI_RAISE6 + {SPR_BSPI,9,5,NULL,S_BSPI_RUN1,0,0}, // S_BSPI_RAISE7 + {SPR_APLS,32768,5,NULL,S_ARACH_PLAZ2,0,0}, // S_ARACH_PLAZ + {SPR_APLS,32769,5,NULL,S_ARACH_PLAZ,0,0}, // S_ARACH_PLAZ2 + {SPR_APBX,32768,5,NULL,S_ARACH_PLEX2,0,0}, // S_ARACH_PLEX + {SPR_APBX,32769,5,NULL,S_ARACH_PLEX3,0,0}, // S_ARACH_PLEX2 + {SPR_APBX,32770,5,NULL,S_ARACH_PLEX4,0,0}, // S_ARACH_PLEX3 + {SPR_APBX,32771,5,NULL,S_ARACH_PLEX5,0,0}, // S_ARACH_PLEX4 + {SPR_APBX,32772,5,NULL,S_NULL,0,0}, // S_ARACH_PLEX5 + {SPR_CYBR,0,10,A_Look,S_CYBER_STND2,0,0}, // S_CYBER_STND + {SPR_CYBR,1,10,A_Look,S_CYBER_STND,0,0}, // S_CYBER_STND2 + {SPR_CYBR,0,3,A_Hoof,S_CYBER_RUN2,0,0}, // S_CYBER_RUN1 + {SPR_CYBR,0,3,A_Chase,S_CYBER_RUN3,0,0}, // S_CYBER_RUN2 + {SPR_CYBR,1,3,A_Chase,S_CYBER_RUN4,0,0}, // S_CYBER_RUN3 + {SPR_CYBR,1,3,A_Chase,S_CYBER_RUN5,0,0}, // S_CYBER_RUN4 + {SPR_CYBR,2,3,A_Chase,S_CYBER_RUN6,0,0}, // S_CYBER_RUN5 + {SPR_CYBR,2,3,A_Chase,S_CYBER_RUN7,0,0}, // S_CYBER_RUN6 + {SPR_CYBR,3,3,A_Metal,S_CYBER_RUN8,0,0}, // S_CYBER_RUN7 + {SPR_CYBR,3,3,A_Chase,S_CYBER_RUN1,0,0}, // S_CYBER_RUN8 + {SPR_CYBR,4,6,A_FaceTarget,S_CYBER_ATK2,0,0}, // S_CYBER_ATK1 + {SPR_CYBR,5,12,A_CyberAttack,S_CYBER_ATK3,0,0}, // S_CYBER_ATK2 + {SPR_CYBR,4,12,A_FaceTarget,S_CYBER_ATK4,0,0}, // S_CYBER_ATK3 + {SPR_CYBR,5,12,A_CyberAttack,S_CYBER_ATK5,0,0}, // S_CYBER_ATK4 + {SPR_CYBR,4,12,A_FaceTarget,S_CYBER_ATK6,0,0}, // S_CYBER_ATK5 + {SPR_CYBR,5,12,A_CyberAttack,S_CYBER_RUN1,0,0}, // S_CYBER_ATK6 + {SPR_CYBR,6,10,A_Pain,S_CYBER_RUN1,0,0}, // S_CYBER_PAIN + {SPR_CYBR,7,10,NULL,S_CYBER_DIE2,0,0}, // S_CYBER_DIE1 + {SPR_CYBR,8,10,A_Scream,S_CYBER_DIE3,0,0}, // S_CYBER_DIE2 + {SPR_CYBR,9,10,NULL,S_CYBER_DIE4,0,0}, // S_CYBER_DIE3 + {SPR_CYBR,10,10,NULL,S_CYBER_DIE5,0,0}, // S_CYBER_DIE4 + {SPR_CYBR,11,10,NULL,S_CYBER_DIE6,0,0}, // S_CYBER_DIE5 + {SPR_CYBR,12,10,A_Fall,S_CYBER_DIE7,0,0}, // S_CYBER_DIE6 + {SPR_CYBR,13,10,NULL,S_CYBER_DIE8,0,0}, // S_CYBER_DIE7 + {SPR_CYBR,14,10,NULL,S_CYBER_DIE9,0,0}, // S_CYBER_DIE8 + {SPR_CYBR,15,30,NULL,S_CYBER_DIE10,0,0}, // S_CYBER_DIE9 + {SPR_CYBR,15,-1,A_BossDeath,S_NULL,0,0}, // S_CYBER_DIE10 + {SPR_PAIN,0,10,A_Look,S_PAIN_STND,0,0}, // S_PAIN_STND + {SPR_PAIN,0,3,A_Chase,S_PAIN_RUN2,0,0}, // S_PAIN_RUN1 + {SPR_PAIN,0,3,A_Chase,S_PAIN_RUN3,0,0}, // S_PAIN_RUN2 + {SPR_PAIN,1,3,A_Chase,S_PAIN_RUN4,0,0}, // S_PAIN_RUN3 + {SPR_PAIN,1,3,A_Chase,S_PAIN_RUN5,0,0}, // S_PAIN_RUN4 + {SPR_PAIN,2,3,A_Chase,S_PAIN_RUN6,0,0}, // S_PAIN_RUN5 + {SPR_PAIN,2,3,A_Chase,S_PAIN_RUN1,0,0}, // S_PAIN_RUN6 + {SPR_PAIN,3,5,A_FaceTarget,S_PAIN_ATK2,0,0}, // S_PAIN_ATK1 + {SPR_PAIN,4,5,A_FaceTarget,S_PAIN_ATK3,0,0}, // S_PAIN_ATK2 + {SPR_PAIN,32773,5,A_FaceTarget,S_PAIN_ATK4,0,0}, // S_PAIN_ATK3 + {SPR_PAIN,32773,0,A_PainAttack,S_PAIN_RUN1,0,0}, // S_PAIN_ATK4 + {SPR_PAIN,6,6,NULL,S_PAIN_PAIN2,0,0}, // S_PAIN_PAIN + {SPR_PAIN,6,6,A_Pain,S_PAIN_RUN1,0,0}, // S_PAIN_PAIN2 + {SPR_PAIN,32775,8,NULL,S_PAIN_DIE2,0,0}, // S_PAIN_DIE1 + {SPR_PAIN,32776,8,A_Scream,S_PAIN_DIE3,0,0}, // S_PAIN_DIE2 + {SPR_PAIN,32777,8,NULL,S_PAIN_DIE4,0,0}, // S_PAIN_DIE3 + {SPR_PAIN,32778,8,NULL,S_PAIN_DIE5,0,0}, // S_PAIN_DIE4 + {SPR_PAIN,32779,8,A_PainDie,S_PAIN_DIE6,0,0}, // S_PAIN_DIE5 + {SPR_PAIN,32780,8,NULL,S_NULL,0,0}, // S_PAIN_DIE6 + {SPR_PAIN,12,8,NULL,S_PAIN_RAISE2,0,0}, // S_PAIN_RAISE1 + {SPR_PAIN,11,8,NULL,S_PAIN_RAISE3,0,0}, // S_PAIN_RAISE2 + {SPR_PAIN,10,8,NULL,S_PAIN_RAISE4,0,0}, // S_PAIN_RAISE3 + {SPR_PAIN,9,8,NULL,S_PAIN_RAISE5,0,0}, // S_PAIN_RAISE4 + {SPR_PAIN,8,8,NULL,S_PAIN_RAISE6,0,0}, // S_PAIN_RAISE5 + {SPR_PAIN,7,8,NULL,S_PAIN_RUN1,0,0}, // S_PAIN_RAISE6 + {SPR_SSWV,0,10,A_Look,S_SSWV_STND2,0,0}, // S_SSWV_STND + {SPR_SSWV,1,10,A_Look,S_SSWV_STND,0,0}, // S_SSWV_STND2 + {SPR_SSWV,0,3,A_Chase,S_SSWV_RUN2,0,0}, // S_SSWV_RUN1 + {SPR_SSWV,0,3,A_Chase,S_SSWV_RUN3,0,0}, // S_SSWV_RUN2 + {SPR_SSWV,1,3,A_Chase,S_SSWV_RUN4,0,0}, // S_SSWV_RUN3 + {SPR_SSWV,1,3,A_Chase,S_SSWV_RUN5,0,0}, // S_SSWV_RUN4 + {SPR_SSWV,2,3,A_Chase,S_SSWV_RUN6,0,0}, // S_SSWV_RUN5 + {SPR_SSWV,2,3,A_Chase,S_SSWV_RUN7,0,0}, // S_SSWV_RUN6 + {SPR_SSWV,3,3,A_Chase,S_SSWV_RUN8,0,0}, // S_SSWV_RUN7 + {SPR_SSWV,3,3,A_Chase,S_SSWV_RUN1,0,0}, // S_SSWV_RUN8 + {SPR_SSWV,4,10,A_FaceTarget,S_SSWV_ATK2,0,0}, // S_SSWV_ATK1 + {SPR_SSWV,5,10,A_FaceTarget,S_SSWV_ATK3,0,0}, // S_SSWV_ATK2 + {SPR_SSWV,32774,4,A_CPosAttack,S_SSWV_ATK4,0,0}, // S_SSWV_ATK3 + {SPR_SSWV,5,6,A_FaceTarget,S_SSWV_ATK5,0,0}, // S_SSWV_ATK4 + {SPR_SSWV,32774,4,A_CPosAttack,S_SSWV_ATK6,0,0}, // S_SSWV_ATK5 + {SPR_SSWV,5,1,A_CPosRefire,S_SSWV_ATK2,0,0}, // S_SSWV_ATK6 + {SPR_SSWV,7,3,NULL,S_SSWV_PAIN2,0,0}, // S_SSWV_PAIN + {SPR_SSWV,7,3,A_Pain,S_SSWV_RUN1,0,0}, // S_SSWV_PAIN2 + {SPR_SSWV,8,5,NULL,S_SSWV_DIE2,0,0}, // S_SSWV_DIE1 + {SPR_SSWV,9,5,A_Scream,S_SSWV_DIE3,0,0}, // S_SSWV_DIE2 + {SPR_SSWV,10,5,A_Fall,S_SSWV_DIE4,0,0}, // S_SSWV_DIE3 + {SPR_SSWV,11,5,NULL,S_SSWV_DIE5,0,0}, // S_SSWV_DIE4 + {SPR_SSWV,12,-1,NULL,S_NULL,0,0}, // S_SSWV_DIE5 + {SPR_SSWV,13,5,NULL,S_SSWV_XDIE2,0,0}, // S_SSWV_XDIE1 + {SPR_SSWV,14,5,A_XScream,S_SSWV_XDIE3,0,0}, // S_SSWV_XDIE2 + {SPR_SSWV,15,5,A_Fall,S_SSWV_XDIE4,0,0}, // S_SSWV_XDIE3 + {SPR_SSWV,16,5,NULL,S_SSWV_XDIE5,0,0}, // S_SSWV_XDIE4 + {SPR_SSWV,17,5,NULL,S_SSWV_XDIE6,0,0}, // S_SSWV_XDIE5 + {SPR_SSWV,18,5,NULL,S_SSWV_XDIE7,0,0}, // S_SSWV_XDIE6 + {SPR_SSWV,19,5,NULL,S_SSWV_XDIE8,0,0}, // S_SSWV_XDIE7 + {SPR_SSWV,20,5,NULL,S_SSWV_XDIE9,0,0}, // S_SSWV_XDIE8 + {SPR_SSWV,21,-1,NULL,S_NULL,0,0}, // S_SSWV_XDIE9 + {SPR_SSWV,12,5,NULL,S_SSWV_RAISE2,0,0}, // S_SSWV_RAISE1 + {SPR_SSWV,11,5,NULL,S_SSWV_RAISE3,0,0}, // S_SSWV_RAISE2 + {SPR_SSWV,10,5,NULL,S_SSWV_RAISE4,0,0}, // S_SSWV_RAISE3 + {SPR_SSWV,9,5,NULL,S_SSWV_RAISE5,0,0}, // S_SSWV_RAISE4 + {SPR_SSWV,8,5,NULL,S_SSWV_RUN1,0,0}, // S_SSWV_RAISE5 + {SPR_KEEN,0,-1,NULL,S_KEENSTND,0,0}, // S_KEENSTND + {SPR_KEEN,0,6,NULL,S_COMMKEEN2,0,0}, // S_COMMKEEN + {SPR_KEEN,1,6,NULL,S_COMMKEEN3,0,0}, // S_COMMKEEN2 + {SPR_KEEN,2,6,A_Scream,S_COMMKEEN4,0,0}, // S_COMMKEEN3 + {SPR_KEEN,3,6,NULL,S_COMMKEEN5,0,0}, // S_COMMKEEN4 + {SPR_KEEN,4,6,NULL,S_COMMKEEN6,0,0}, // S_COMMKEEN5 + {SPR_KEEN,5,6,NULL,S_COMMKEEN7,0,0}, // S_COMMKEEN6 + {SPR_KEEN,6,6,NULL,S_COMMKEEN8,0,0}, // S_COMMKEEN7 + {SPR_KEEN,7,6,NULL,S_COMMKEEN9,0,0}, // S_COMMKEEN8 + {SPR_KEEN,8,6,NULL,S_COMMKEEN10,0,0}, // S_COMMKEEN9 + {SPR_KEEN,9,6,NULL,S_COMMKEEN11,0,0}, // S_COMMKEEN10 + {SPR_KEEN,10,6,A_KeenDie,S_COMMKEEN12,0,0},// S_COMMKEEN11 + {SPR_KEEN,11,-1,NULL,S_NULL,0,0}, // S_COMMKEEN12 + {SPR_KEEN,12,4,NULL,S_KEENPAIN2,0,0}, // S_KEENPAIN + {SPR_KEEN,12,8,A_Pain,S_KEENSTND,0,0}, // S_KEENPAIN2 + {SPR_BBRN,0,-1,NULL,S_NULL,0,0}, // S_BRAIN + {SPR_BBRN,1,36,A_BrainPain,S_BRAIN,0,0}, // S_BRAIN_PAIN + {SPR_BBRN,0,100,A_BrainScream,S_BRAIN_DIE2,0,0}, // S_BRAIN_DIE1 + {SPR_BBRN,0,10,NULL,S_BRAIN_DIE3,0,0}, // S_BRAIN_DIE2 + {SPR_BBRN,0,10,NULL,S_BRAIN_DIE4,0,0}, // S_BRAIN_DIE3 + {SPR_BBRN,0,-1,A_BrainDie,S_NULL,0,0}, // S_BRAIN_DIE4 + {SPR_SSWV,0,10,A_Look,S_BRAINEYE,0,0}, // S_BRAINEYE + {SPR_SSWV,0,181,A_BrainAwake,S_BRAINEYE1,0,0}, // S_BRAINEYESEE + {SPR_SSWV,0,150,A_BrainSpit,S_BRAINEYE1,0,0}, // S_BRAINEYE1 + {SPR_BOSF,32768,3,A_SpawnSound,S_SPAWN2,0,0}, // S_SPAWN1 + {SPR_BOSF,32769,3,A_SpawnFly,S_SPAWN3,0,0}, // S_SPAWN2 + {SPR_BOSF,32770,3,A_SpawnFly,S_SPAWN4,0,0}, // S_SPAWN3 + {SPR_BOSF,32771,3,A_SpawnFly,S_SPAWN1,0,0}, // S_SPAWN4 + {SPR_FIRE,32768,4,A_Fire,S_SPAWNFIRE2,0,0}, // S_SPAWNFIRE1 + {SPR_FIRE,32769,4,A_Fire,S_SPAWNFIRE3,0,0}, // S_SPAWNFIRE2 + {SPR_FIRE,32770,4,A_Fire,S_SPAWNFIRE4,0,0}, // S_SPAWNFIRE3 + {SPR_FIRE,32771,4,A_Fire,S_SPAWNFIRE5,0,0}, // S_SPAWNFIRE4 + {SPR_FIRE,32772,4,A_Fire,S_SPAWNFIRE6,0,0}, // S_SPAWNFIRE5 + {SPR_FIRE,32773,4,A_Fire,S_SPAWNFIRE7,0,0}, // S_SPAWNFIRE6 + {SPR_FIRE,32774,4,A_Fire,S_SPAWNFIRE8,0,0}, // S_SPAWNFIRE7 + {SPR_FIRE,32775,4,A_Fire,S_NULL,0,0}, // S_SPAWNFIRE8 + {SPR_MISL,32769,10,NULL,S_BRAINEXPLODE2,0,0}, // S_BRAINEXPLODE1 + {SPR_MISL,32770,10,NULL,S_BRAINEXPLODE3,0,0}, // S_BRAINEXPLODE2 + {SPR_MISL,32771,10,A_BrainExplode,S_NULL,0,0}, // S_BRAINEXPLODE3 + {SPR_ARM1,0,6,NULL,S_ARM1A,0,0}, // S_ARM1 + {SPR_ARM1,32769,7,NULL,S_ARM1,0,0}, // S_ARM1A + {SPR_ARM2,0,6,NULL,S_ARM2A,0,0}, // S_ARM2 + {SPR_ARM2,32769,6,NULL,S_ARM2,0,0}, // S_ARM2A + {SPR_BAR1,0,6,NULL,S_BAR2,0,0}, // S_BAR1 + {SPR_BAR1,1,6,NULL,S_BAR1,0,0}, // S_BAR2 + {SPR_BEXP,32768,5,NULL,S_BEXP2,0,0}, // S_BEXP + {SPR_BEXP,32769,5,A_Scream,S_BEXP3,0,0}, // S_BEXP2 + {SPR_BEXP,32770,5,NULL,S_BEXP4,0,0}, // S_BEXP3 + {SPR_BEXP,32771,10,A_Explode,S_BEXP5,0,0}, // S_BEXP4 + {SPR_BEXP,32772,10,NULL,S_NULL,0,0}, // S_BEXP5 + {SPR_FCAN,32768,4,NULL,S_BBAR2,0,0}, // S_BBAR1 + {SPR_FCAN,32769,4,NULL,S_BBAR3,0,0}, // S_BBAR2 + {SPR_FCAN,32770,4,NULL,S_BBAR1,0,0}, // S_BBAR3 + {SPR_BON1,0,6,NULL,S_BON1A,0,0}, // S_BON1 + {SPR_BON1,1,6,NULL,S_BON1B,0,0}, // S_BON1A + {SPR_BON1,2,6,NULL,S_BON1C,0,0}, // S_BON1B + {SPR_BON1,3,6,NULL,S_BON1D,0,0}, // S_BON1C + {SPR_BON1,2,6,NULL,S_BON1E,0,0}, // S_BON1D + {SPR_BON1,1,6,NULL,S_BON1,0,0}, // S_BON1E + {SPR_BON2,0,6,NULL,S_BON2A,0,0}, // S_BON2 + {SPR_BON2,1,6,NULL,S_BON2B,0,0}, // S_BON2A + {SPR_BON2,2,6,NULL,S_BON2C,0,0}, // S_BON2B + {SPR_BON2,3,6,NULL,S_BON2D,0,0}, // S_BON2C + {SPR_BON2,2,6,NULL,S_BON2E,0,0}, // S_BON2D + {SPR_BON2,1,6,NULL,S_BON2,0,0}, // S_BON2E + {SPR_BKEY,0,10,NULL,S_BKEY2,0,0}, // S_BKEY + {SPR_BKEY,32769,10,NULL,S_BKEY,0,0}, // S_BKEY2 + {SPR_RKEY,0,10,NULL,S_RKEY2,0,0}, // S_RKEY + {SPR_RKEY,32769,10,NULL,S_RKEY,0,0}, // S_RKEY2 + {SPR_YKEY,0,10,NULL,S_YKEY2,0,0}, // S_YKEY + {SPR_YKEY,32769,10,NULL,S_YKEY,0,0}, // S_YKEY2 + {SPR_BSKU,0,10,NULL,S_BSKULL2,0,0}, // S_BSKULL + {SPR_BSKU,32769,10,NULL,S_BSKULL,0,0}, // S_BSKULL2 + {SPR_RSKU,0,10,NULL,S_RSKULL2,0,0}, // S_RSKULL + {SPR_RSKU,32769,10,NULL,S_RSKULL,0,0}, // S_RSKULL2 + {SPR_YSKU,0,10,NULL,S_YSKULL2,0,0}, // S_YSKULL + {SPR_YSKU,32769,10,NULL,S_YSKULL,0,0}, // S_YSKULL2 + {SPR_STIM,0,-1,NULL,S_NULL,0,0}, // S_STIM + {SPR_MEDI,0,-1,NULL,S_NULL,0,0}, // S_MEDI + {SPR_SOUL,32768,6,NULL,S_SOUL2,0,0}, // S_SOUL + {SPR_SOUL,32769,6,NULL,S_SOUL3,0,0}, // S_SOUL2 + {SPR_SOUL,32770,6,NULL,S_SOUL4,0,0}, // S_SOUL3 + {SPR_SOUL,32771,6,NULL,S_SOUL5,0,0}, // S_SOUL4 + {SPR_SOUL,32770,6,NULL,S_SOUL6,0,0}, // S_SOUL5 + {SPR_SOUL,32769,6,NULL,S_SOUL,0,0}, // S_SOUL6 + {SPR_PINV,32768,6,NULL,S_PINV2,0,0}, // S_PINV + {SPR_PINV,32769,6,NULL,S_PINV3,0,0}, // S_PINV2 + {SPR_PINV,32770,6,NULL,S_PINV4,0,0}, // S_PINV3 + {SPR_PINV,32771,6,NULL,S_PINV,0,0}, // S_PINV4 + {SPR_PSTR,32768,-1,NULL,S_NULL,0,0}, // S_PSTR + {SPR_PINS,32768,6,NULL,S_PINS2,0,0}, // S_PINS + {SPR_PINS,32769,6,NULL,S_PINS3,0,0}, // S_PINS2 + {SPR_PINS,32770,6,NULL,S_PINS4,0,0}, // S_PINS3 + {SPR_PINS,32771,6,NULL,S_PINS,0,0}, // S_PINS4 + {SPR_MEGA,32768,6,NULL,S_MEGA2,0,0}, // S_MEGA + {SPR_MEGA,32769,6,NULL,S_MEGA3,0,0}, // S_MEGA2 + {SPR_MEGA,32770,6,NULL,S_MEGA4,0,0}, // S_MEGA3 + {SPR_MEGA,32771,6,NULL,S_MEGA,0,0}, // S_MEGA4 + {SPR_SUIT,32768,-1,NULL,S_NULL,0,0}, // S_SUIT + {SPR_PMAP,32768,6,NULL,S_PMAP2,0,0}, // S_PMAP + {SPR_PMAP,32769,6,NULL,S_PMAP3,0,0}, // S_PMAP2 + {SPR_PMAP,32770,6,NULL,S_PMAP4,0,0}, // S_PMAP3 + {SPR_PMAP,32771,6,NULL,S_PMAP5,0,0}, // S_PMAP4 + {SPR_PMAP,32770,6,NULL,S_PMAP6,0,0}, // S_PMAP5 + {SPR_PMAP,32769,6,NULL,S_PMAP,0,0}, // S_PMAP6 + {SPR_PVIS,32768,6,NULL,S_PVIS2,0,0}, // S_PVIS + {SPR_PVIS,1,6,NULL,S_PVIS,0,0}, // S_PVIS2 + {SPR_CLIP,0,-1,NULL,S_NULL,0,0}, // S_CLIP + {SPR_AMMO,0,-1,NULL,S_NULL,0,0}, // S_AMMO + {SPR_ROCK,0,-1,NULL,S_NULL,0,0}, // S_ROCK + {SPR_BROK,0,-1,NULL,S_NULL,0,0}, // S_BROK + {SPR_CELL,0,-1,NULL,S_NULL,0,0}, // S_CELL + {SPR_CELP,0,-1,NULL,S_NULL,0,0}, // S_CELP + {SPR_SHEL,0,-1,NULL,S_NULL,0,0}, // S_SHEL + {SPR_SBOX,0,-1,NULL,S_NULL,0,0}, // S_SBOX + {SPR_BPAK,0,-1,NULL,S_NULL,0,0}, // S_BPAK + {SPR_BFUG,0,-1,NULL,S_NULL,0,0}, // S_BFUG + {SPR_MGUN,0,-1,NULL,S_NULL,0,0}, // S_MGUN + {SPR_CSAW,0,-1,NULL,S_NULL,0,0}, // S_CSAW + {SPR_LAUN,0,-1,NULL,S_NULL,0,0}, // S_LAUN + {SPR_PLAS,0,-1,NULL,S_NULL,0,0}, // S_PLAS + {SPR_SHOT,0,-1,NULL,S_NULL,0,0}, // S_SHOT + {SPR_SGN2,0,-1,NULL,S_NULL,0,0}, // S_SHOT2 + {SPR_COLU,32768,-1,NULL,S_NULL,0,0}, // S_COLU + {SPR_SMT2,0,-1,NULL,S_NULL,0,0}, // S_STALAG + {SPR_GOR1,0,10,NULL,S_BLOODYTWITCH2,0,0}, // S_BLOODYTWITCH + {SPR_GOR1,1,15,NULL,S_BLOODYTWITCH3,0,0}, // S_BLOODYTWITCH2 + {SPR_GOR1,2,8,NULL,S_BLOODYTWITCH4,0,0}, // S_BLOODYTWITCH3 + {SPR_GOR1,1,6,NULL,S_BLOODYTWITCH,0,0}, // S_BLOODYTWITCH4 + {SPR_PLAY,13,-1,NULL,S_NULL,0,0}, // S_DEADTORSO + {SPR_PLAY,18,-1,NULL,S_NULL,0,0}, // S_DEADBOTTOM + {SPR_POL2,0,-1,NULL,S_NULL,0,0}, // S_HEADSONSTICK + {SPR_POL5,0,-1,NULL,S_NULL,0,0}, // S_GIBS + {SPR_POL4,0,-1,NULL,S_NULL,0,0}, // S_HEADONASTICK + {SPR_POL3,32768,6,NULL,S_HEADCANDLES2,0,0}, // S_HEADCANDLES + {SPR_POL3,32769,6,NULL,S_HEADCANDLES,0,0}, // S_HEADCANDLES2 + {SPR_POL1,0,-1,NULL,S_NULL,0,0}, // S_DEADSTICK + {SPR_POL6,0,6,NULL,S_LIVESTICK2,0,0}, // S_LIVESTICK + {SPR_POL6,1,8,NULL,S_LIVESTICK,0,0}, // S_LIVESTICK2 + {SPR_GOR2,0,-1,NULL,S_NULL,0,0}, // S_MEAT2 + {SPR_GOR3,0,-1,NULL,S_NULL,0,0}, // S_MEAT3 + {SPR_GOR4,0,-1,NULL,S_NULL,0,0}, // S_MEAT4 + {SPR_GOR5,0,-1,NULL,S_NULL,0,0}, // S_MEAT5 + {SPR_SMIT,0,-1,NULL,S_NULL,0,0}, // S_STALAGTITE + {SPR_COL1,0,-1,NULL,S_NULL,0,0}, // S_TALLGRNCOL + {SPR_COL2,0,-1,NULL,S_NULL,0,0}, // S_SHRTGRNCOL + {SPR_COL3,0,-1,NULL,S_NULL,0,0}, // S_TALLREDCOL + {SPR_COL4,0,-1,NULL,S_NULL,0,0}, // S_SHRTREDCOL + {SPR_CAND,32768,-1,NULL,S_NULL,0,0}, // S_CANDLESTIK + {SPR_CBRA,32768,-1,NULL,S_NULL,0,0}, // S_CANDELABRA + {SPR_COL6,0,-1,NULL,S_NULL,0,0}, // S_SKULLCOL + {SPR_TRE1,0,-1,NULL,S_NULL,0,0}, // S_TORCHTREE + {SPR_TRE2,0,-1,NULL,S_NULL,0,0}, // S_BIGTREE + {SPR_ELEC,0,-1,NULL,S_NULL,0,0}, // S_TECHPILLAR + {SPR_CEYE,32768,6,NULL,S_EVILEYE2,0,0}, // S_EVILEYE + {SPR_CEYE,32769,6,NULL,S_EVILEYE3,0,0}, // S_EVILEYE2 + {SPR_CEYE,32770,6,NULL,S_EVILEYE4,0,0}, // S_EVILEYE3 + {SPR_CEYE,32769,6,NULL,S_EVILEYE,0,0}, // S_EVILEYE4 + {SPR_FSKU,32768,6,NULL,S_FLOATSKULL2,0,0}, // S_FLOATSKULL + {SPR_FSKU,32769,6,NULL,S_FLOATSKULL3,0,0}, // S_FLOATSKULL2 + {SPR_FSKU,32770,6,NULL,S_FLOATSKULL,0,0}, // S_FLOATSKULL3 + {SPR_COL5,0,14,NULL,S_HEARTCOL2,0,0}, // S_HEARTCOL + {SPR_COL5,1,14,NULL,S_HEARTCOL,0,0}, // S_HEARTCOL2 + {SPR_TBLU,32768,4,NULL,S_BLUETORCH2,0,0}, // S_BLUETORCH + {SPR_TBLU,32769,4,NULL,S_BLUETORCH3,0,0}, // S_BLUETORCH2 + {SPR_TBLU,32770,4,NULL,S_BLUETORCH4,0,0}, // S_BLUETORCH3 + {SPR_TBLU,32771,4,NULL,S_BLUETORCH,0,0}, // S_BLUETORCH4 + {SPR_TGRN,32768,4,NULL,S_GREENTORCH2,0,0}, // S_GREENTORCH + {SPR_TGRN,32769,4,NULL,S_GREENTORCH3,0,0}, // S_GREENTORCH2 + {SPR_TGRN,32770,4,NULL,S_GREENTORCH4,0,0}, // S_GREENTORCH3 + {SPR_TGRN,32771,4,NULL,S_GREENTORCH,0,0}, // S_GREENTORCH4 + {SPR_TRED,32768,4,NULL,S_REDTORCH2,0,0}, // S_REDTORCH + {SPR_TRED,32769,4,NULL,S_REDTORCH3,0,0}, // S_REDTORCH2 + {SPR_TRED,32770,4,NULL,S_REDTORCH4,0,0}, // S_REDTORCH3 + {SPR_TRED,32771,4,NULL,S_REDTORCH,0,0}, // S_REDTORCH4 + {SPR_SMBT,32768,4,NULL,S_BTORCHSHRT2,0,0}, // S_BTORCHSHRT + {SPR_SMBT,32769,4,NULL,S_BTORCHSHRT3,0,0}, // S_BTORCHSHRT2 + {SPR_SMBT,32770,4,NULL,S_BTORCHSHRT4,0,0}, // S_BTORCHSHRT3 + {SPR_SMBT,32771,4,NULL,S_BTORCHSHRT,0,0}, // S_BTORCHSHRT4 + {SPR_SMGT,32768,4,NULL,S_GTORCHSHRT2,0,0}, // S_GTORCHSHRT + {SPR_SMGT,32769,4,NULL,S_GTORCHSHRT3,0,0}, // S_GTORCHSHRT2 + {SPR_SMGT,32770,4,NULL,S_GTORCHSHRT4,0,0}, // S_GTORCHSHRT3 + {SPR_SMGT,32771,4,NULL,S_GTORCHSHRT,0,0}, // S_GTORCHSHRT4 + {SPR_SMRT,32768,4,NULL,S_RTORCHSHRT2,0,0}, // S_RTORCHSHRT + {SPR_SMRT,32769,4,NULL,S_RTORCHSHRT3,0,0}, // S_RTORCHSHRT2 + {SPR_SMRT,32770,4,NULL,S_RTORCHSHRT4,0,0}, // S_RTORCHSHRT3 + {SPR_SMRT,32771,4,NULL,S_RTORCHSHRT,0,0}, // S_RTORCHSHRT4 + {SPR_HDB1,0,-1,NULL,S_NULL,0,0}, // S_HANGNOGUTS + {SPR_HDB2,0,-1,NULL,S_NULL,0,0}, // S_HANGBNOBRAIN + {SPR_HDB3,0,-1,NULL,S_NULL,0,0}, // S_HANGTLOOKDN + {SPR_HDB4,0,-1,NULL,S_NULL,0,0}, // S_HANGTSKULL + {SPR_HDB5,0,-1,NULL,S_NULL,0,0}, // S_HANGTLOOKUP + {SPR_HDB6,0,-1,NULL,S_NULL,0,0}, // S_HANGTNOBRAIN + {SPR_POB1,0,-1,NULL,S_NULL,0,0}, // S_COLONGIBS + {SPR_POB2,0,-1,NULL,S_NULL,0,0}, // S_SMALLPOOL + {SPR_BRS1,0,-1,NULL,S_NULL,0,0}, // S_BRAINSTEM + {SPR_TLMP,32768,4,NULL,S_TECHLAMP2,0,0}, // S_TECHLAMP + {SPR_TLMP,32769,4,NULL,S_TECHLAMP3,0,0}, // S_TECHLAMP2 + {SPR_TLMP,32770,4,NULL,S_TECHLAMP4,0,0}, // S_TECHLAMP3 + {SPR_TLMP,32771,4,NULL,S_TECHLAMP,0,0}, // S_TECHLAMP4 + {SPR_TLP2,32768,4,NULL,S_TECH2LAMP2,0,0}, // S_TECH2LAMP + {SPR_TLP2,32769,4,NULL,S_TECH2LAMP3,0,0}, // S_TECH2LAMP2 + {SPR_TLP2,32770,4,NULL,S_TECH2LAMP4,0,0}, // S_TECH2LAMP3 + {SPR_TLP2,32771,4,NULL,S_TECH2LAMP,0,0}, // S_TECH2LAMP4 + {SPR_TNT1,0,-1,NULL,S_TNT1,0,0}, // S_TNT1 // phares 3/8/98 + + // killough 8/9/98: grenade + {SPR_MISL,32768,1000,A_Die,S_GRENADE}, // S_GRENADE + + // killough 8/10/98: variable damage explosion + {SPR_MISL,32769,4,A_Scream,S_DETONATE2}, // S_DETONATE + {SPR_MISL,32770,6,A_Detonate,S_DETONATE3}, // S_DETONATE2 + {SPR_MISL,32771,10,NULL,S_NULL}, // S_DETONATE3 + +#ifdef DOGS + // killough 7/19/98: Marine's best friend :) + {SPR_DOGS,0,10,A_Look,S_DOGS_STND2}, // S_DOGS_STND + {SPR_DOGS,1,10,A_Look,S_DOGS_STND}, // S_DOGS_STND2 + {SPR_DOGS,0,2,A_Chase,S_DOGS_RUN2}, // S_DOGS_RUN1 + {SPR_DOGS,0,2,A_Chase,S_DOGS_RUN3}, // S_DOGS_RUN2 + {SPR_DOGS,1,2,A_Chase,S_DOGS_RUN4}, // S_DOGS_RUN3 + {SPR_DOGS,1,2,A_Chase,S_DOGS_RUN5}, // S_DOGS_RUN4 + {SPR_DOGS,2,2,A_Chase,S_DOGS_RUN6}, // S_DOGS_RUN5 + {SPR_DOGS,2,2,A_Chase,S_DOGS_RUN7}, // S_DOGS_RUN6 + {SPR_DOGS,3,2,A_Chase,S_DOGS_RUN8}, // S_DOGS_RUN7 + {SPR_DOGS,3,2,A_Chase,S_DOGS_RUN1}, // S_DOGS_RUN8 + {SPR_DOGS,4,8,A_FaceTarget,S_DOGS_ATK2}, // S_DOGS_ATK1 + {SPR_DOGS,5,8,A_FaceTarget,S_DOGS_ATK3}, // S_DOGS_ATK2 + {SPR_DOGS,6,8,A_SargAttack,S_DOGS_RUN1}, // S_DOGS_ATK3 + {SPR_DOGS,7,2,NULL,S_DOGS_PAIN2}, // S_DOGS_PAIN + {SPR_DOGS,7,2,A_Pain,S_DOGS_RUN1}, // S_DOGS_PAIN2 + {SPR_DOGS,8,8,NULL,S_DOGS_DIE2}, // S_DOGS_DIE1 + {SPR_DOGS,9,8,A_Scream,S_DOGS_DIE3}, // S_DOGS_DIE2 + {SPR_DOGS,10,4,NULL,S_DOGS_DIE4}, // S_DOGS_DIE3 + {SPR_DOGS,11,4,A_Fall,S_DOGS_DIE5}, // S_DOGS_DIE4 + {SPR_DOGS,12,4,NULL,S_DOGS_DIE6}, // S_DOGS_DIE5 + {SPR_DOGS,13,-1,NULL,S_NULL}, // S_DOGS_DIE6 + {SPR_DOGS,13,5,NULL,S_DOGS_RAISE2}, // S_DOGS_RAISE1 + {SPR_DOGS,12,5,NULL,S_DOGS_RAISE3}, // S_DOGS_RAISE2 + {SPR_DOGS,11,5,NULL,S_DOGS_RAISE4}, // S_DOGS_RAISE3 + {SPR_DOGS,10,5,NULL,S_DOGS_RAISE5}, // S_DOGS_RAISE4 + {SPR_DOGS,9,5,NULL,S_DOGS_RAISE6}, // S_DOGS_RAISE5 + {SPR_DOGS,8,5,NULL,S_DOGS_RUN1}, // S_DOGS_RAISE6 +#else + // if dogs are disabled, dummy states are required for dehacked compatibility + {0,0,-1,NULL,S_NULL}, // S_DOGS_STND + {0,0,-1,NULL,S_NULL}, // S_DOGS_STND2 + {0,0,-1,NULL,S_NULL}, // S_DOGS_RUN1 + {0,0,-1,NULL,S_NULL}, // S_DOGS_RUN2 + {0,0,-1,NULL,S_NULL}, // S_DOGS_RUN3 + {0,0,-1,NULL,S_NULL}, // S_DOGS_RUN4 + {0,0,-1,NULL,S_NULL}, // S_DOGS_RUN5 + {0,0,-1,NULL,S_NULL}, // S_DOGS_RUN6 + {0,0,-1,NULL,S_NULL}, // S_DOGS_RUN7 + {0,0,-1,NULL,S_NULL}, // S_DOGS_RUN8 + {0,0,-1,NULL,S_NULL}, // S_DOGS_ATK1 + {0,0,-1,NULL,S_NULL}, // S_DOGS_ATK2 + {0,0,-1,NULL,S_NULL}, // S_DOGS_ATK3 + {0,0,-1,NULL,S_NULL}, // S_DOGS_PAIN + {0,0,-1,NULL,S_NULL}, // S_DOGS_PAIN2 + {0,0,-1,NULL,S_NULL}, // S_DOGS_DIE1 + {0,0,-1,NULL,S_NULL}, // S_DOGS_DIE2 + {0,0,-1,NULL,S_NULL}, // S_DOGS_DIE3 + {0,0,-1,NULL,S_NULL}, // S_DOGS_DIE4 + {0,0,-1,NULL,S_NULL}, // S_DOGS_DIE5 + {0,0,-1,NULL,S_NULL}, // S_DOGS_DIE6 + {0,0,-1,NULL,S_NULL}, // S_DOGS_RAISE1 + {0,0,-1,NULL,S_NULL}, // S_DOGS_RAISE2 + {0,0,-1,NULL,S_NULL}, // S_DOGS_RAISE3 + {0,0,-1,NULL,S_NULL}, // S_DOGS_RAISE4 + {0,0,-1,NULL,S_NULL}, // S_DOGS_RAISE5 + {0,0,-1,NULL,S_NULL}, // S_DOGS_RAISE6 +#endif + + // add dummy beta bfg / lost soul frames for dehacked compatibility + // fixes bug #1576151 (part 2) + {0,0,-1,NULL,S_NULL}, // S_OLDBFG1 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG2 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG3 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG4 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG5 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG6 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG7 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG8 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG9 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG10 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG11 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG12 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG13 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG14 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG15 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG16 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG17 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG18 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG19 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG20 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG21 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG22 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG23 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG24 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG25 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG26 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG27 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG28 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG29 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG30 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG31 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG32 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG33 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG34 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG35 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG36 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG37 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG38 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG39 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG40 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG41 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG42 + {0,0,-1,NULL,S_NULL}, // S_OLDBFG43 + + {0,0,-1,NULL,S_NULL}, // S_PLS1BALL + {0,0,-1,NULL,S_NULL}, // S_PLS1BALL2 + {0,0,-1,NULL,S_NULL}, // S_PLS1EXP + {0,0,-1,NULL,S_NULL}, // S_PLS1EXP2 + {0,0,-1,NULL,S_NULL}, // S_PLS1EXP3 + {0,0,-1,NULL,S_NULL}, // S_PLS1EXP4 + {0,0,-1,NULL,S_NULL}, // S_PLS1EXP5 + + {0,0,-1,NULL,S_NULL}, // S_PLS2BALL + {0,0,-1,NULL,S_NULL}, // S_PLS2BALL2 + {0,0,-1,NULL,S_NULL}, // S_PLS2BALLX1 + {0,0,-1,NULL,S_NULL}, // S_PLS2BALLX2 + {0,0,-1,NULL,S_NULL}, // S_PLS2BALLX3 + + {0,0,-1,NULL,S_NULL}, // S_BON3 + {0,0,-1,NULL,S_NULL}, // S_BON4 + + {0,0,-1,NULL,S_NULL}, // S_BSKUL_STND + {0,0,-1,NULL,S_NULL}, // S_BSKUL_RUN1 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_RUN2 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_RUN3 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_RUN4 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_ATK1 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_ATK2 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_ATK3 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_PAIN1 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_PAIN2 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_PAIN3 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_DIE1 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_DIE2 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_DIE3 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_DIE4 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_DIE5 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_DIE6 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_DIE7 + {0,0,-1,NULL,S_NULL}, // S_BSKUL_DIE8 + + // killough 10/98: mushroom effect + {SPR_MISL,32769,8,A_Mushroom,S_EXPLODE2}, // S_MUSHROOM +}; + +// ******************************************************************** +// Object "Thing" definitions +// ******************************************************************** +// Now we get to the actual objects and their characteristics. If +// you've seen Dehacked, much of this is where the Bits are set, +// commented below as "flags", as well as where you wire in which +// frames are the beginning frames for near and far attack, death, +// and such. Sounds are hooked in here too, as well as how much +// mass, speed and so forth a Thing has. Everything you ever wanted +// to know... +// +// Like all this other stuff, the MT_* entries are enumerated in info.h +// +// Note that these are all just indices of the elements involved, and +// not real pointers to them. For example, the player's death sequence +// is S_PLAY_DIE1, which just evaluates to the index in the states[] +// array above, which actually knows what happens then and what the +// sprite looks like, if it makes noise or not, etc. +// +// Additional comments about each of the entries are located in info.h +// next to the mobjinfo_t structure definition. +// +// This goes on for the next 3000+ lines... + +mobjinfo_t mobjinfo[NUMMOBJTYPES] = { + { // MT_PLAYER + -1, // doomednum + S_PLAY, // spawnstate + 100, // spawnhealth + S_PLAY_RUN1, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_PLAY_PAIN, // painstate + 255, // painchance + sfx_plpain, // painsound + S_NULL, // meleestate + S_PLAY_ATK1, // missilestate + S_PLAY_DIE1, // deathstate + S_PLAY_XDIE1, // xdeathstate + sfx_pldeth, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_POSSESSED + 3004, // doomednum + S_POSS_STND, // spawnstate + 20, // spawnhealth + S_POSS_RUN1, // seestate + sfx_posit1, // seesound + 8, // reactiontime + sfx_pistol, // attacksound + S_POSS_PAIN, // painstate + 200, // painchance + sfx_popain, // painsound + 0, // meleestate + S_POSS_ATK1, // missilestate + S_POSS_DIE1, // deathstate + S_POSS_XDIE1, // xdeathstate + sfx_podth1, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_POSS_RAISE1 // raisestate + }, + + { // MT_SHOTGUY + 9, // doomednum + S_SPOS_STND, // spawnstate + 30, // spawnhealth + S_SPOS_RUN1, // seestate + sfx_posit2, // seesound + 8, // reactiontime + 0, // attacksound + S_SPOS_PAIN, // painstate + 170, // painchance + sfx_popain, // painsound + 0, // meleestate + S_SPOS_ATK1, // missilestate + S_SPOS_DIE1, // deathstate + S_SPOS_XDIE1, // xdeathstate + sfx_podth2, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_SPOS_RAISE1 // raisestate + }, + + { // MT_VILE + 64, // doomednum + S_VILE_STND, // spawnstate + 700, // spawnhealth + S_VILE_RUN1, // seestate + sfx_vilsit, // seesound + 8, // reactiontime + 0, // attacksound + S_VILE_PAIN, // painstate + 10, // painchance + sfx_vipain, // painsound + 0, // meleestate + S_VILE_ATK1, // missilestate + S_VILE_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_vildth, // deathsound + 15, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 500, // mass + 0, // damage + sfx_vilact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_NULL // raisestate + }, + + { // MT_FIRE + -1, // doomednum + S_FIRE1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_UNDEAD + 66, // doomednum + S_SKEL_STND, // spawnstate + 300, // spawnhealth + S_SKEL_RUN1, // seestate + sfx_skesit, // seesound + 8, // reactiontime + 0, // attacksound + S_SKEL_PAIN, // painstate + 100, // painchance + sfx_popain, // painsound + S_SKEL_FIST1, // meleestate + S_SKEL_MISS1, // missilestate + S_SKEL_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_skedth, // deathsound + 10, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 500, // mass + 0, // damage + sfx_skeact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_SKEL_RAISE1 // raisestate + }, + + { // MT_TRACER + -1, // doomednum + S_TRACER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_skeatk, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_TRACEEXP1, // deathstate + S_NULL, // xdeathstate + sfx_barexp, // deathsound + 10*FRACUNIT, // speed + 11*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 10, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_SMOKE + -1, // doomednum + S_SMOKE1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_FATSO + 67, // doomednum + S_FATT_STND, // spawnstate + 600, // spawnhealth + S_FATT_RUN1, // seestate + sfx_mansit, // seesound + 8, // reactiontime + 0, // attacksound + S_FATT_PAIN, // painstate + 80, // painchance + sfx_mnpain, // painsound + 0, // meleestate + S_FATT_ATK1, // missilestate + S_FATT_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_mandth, // deathsound + 8, // speed + 48*FRACUNIT, // radius + 64*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_FATT_RAISE1 // raisestate + }, + + { // MT_FATSHOT + -1, // doomednum + S_FATSHOT1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_firsht, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_FATSHOTX1, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 20*FRACUNIT, // speed + 6*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 8, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags \\ killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_CHAINGUY + 65, // doomednum + S_CPOS_STND, // spawnstate + 70, // spawnhealth + S_CPOS_RUN1, // seestate + sfx_posit2, // seesound + 8, // reactiontime + 0, // attacksound + S_CPOS_PAIN, // painstate + 170, // painchance + sfx_popain, // painsound + 0, // meleestate + S_CPOS_ATK1, // missilestate + S_CPOS_DIE1, // deathstate + S_CPOS_XDIE1, // xdeathstate + sfx_podth2, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_CPOS_RAISE1 // raisestate + }, + + { // MT_TROOP + 3001, // doomednum + S_TROO_STND, // spawnstate + 60, // spawnhealth + S_TROO_RUN1, // seestate + sfx_bgsit1, // seesound + 8, // reactiontime + 0, // attacksound + S_TROO_PAIN, // painstate + 200, // painchance + sfx_popain, // painsound + S_TROO_ATK1, // meleestate + S_TROO_ATK1, // missilestate + S_TROO_DIE1, // deathstate + S_TROO_XDIE1, // xdeathstate + sfx_bgdth1, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_bgact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // killough |MF_TRANSLUCENT, // flags // phares + S_TROO_RAISE1 // raisestate + }, + + { // MT_SERGEANT + 3002, // doomednum + S_SARG_STND, // spawnstate + 150, // spawnhealth + S_SARG_RUN1, // seestate + sfx_sgtsit, // seesound + 8, // reactiontime + sfx_sgtatk, // attacksound + S_SARG_PAIN, // painstate + 180, // painchance + sfx_dmpain, // painsound + S_SARG_ATK1, // meleestate + 0, // missilestate + S_SARG_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_sgtdth, // deathsound + 10, // speed + 30*FRACUNIT, // radius + 56*FRACUNIT, // height + 400, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_SARG_RAISE1 // raisestate + }, + + { // MT_SHADOWS + 58, // doomednum + S_SARG_STND, // spawnstate + 150, // spawnhealth + S_SARG_RUN1, // seestate + sfx_sgtsit, // seesound + 8, // reactiontime + sfx_sgtatk, // attacksound + S_SARG_PAIN, // painstate + 180, // painchance + sfx_dmpain, // painsound + S_SARG_ATK1, // meleestate + 0, // missilestate + S_SARG_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_sgtdth, // deathsound + 10, // speed + 30*FRACUNIT, // radius + 56*FRACUNIT, // height + 400, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_SHADOW|MF_COUNTKILL, // flags + S_SARG_RAISE1 // raisestate + }, + + { // MT_HEAD + 3005, // doomednum + S_HEAD_STND, // spawnstate + 400, // spawnhealth + S_HEAD_RUN1, // seestate + sfx_cacsit, // seesound + 8, // reactiontime + 0, // attacksound + S_HEAD_PAIN, // painstate + 128, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_HEAD_ATK1, // missilestate + S_HEAD_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_cacdth, // deathsound + 8, // speed + 31*FRACUNIT, // radius + 56*FRACUNIT, // height + 400, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY|MF_COUNTKILL, // flags + S_HEAD_RAISE1 // raisestate + }, + + { // MT_BRUISER + 3003, // doomednum + S_BOSS_STND, // spawnstate + 1000, // spawnhealth + S_BOSS_RUN1, // seestate + sfx_brssit, // seesound + 8, // reactiontime + 0, // attacksound + S_BOSS_PAIN, // painstate + 50, // painchance + sfx_dmpain, // painsound + S_BOSS_ATK1, // meleestate + S_BOSS_ATK1, // missilestate + S_BOSS_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_brsdth, // deathsound + 8, // speed + 24*FRACUNIT, // radius + 64*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_BOSS_RAISE1 // raisestate + }, + + { // MT_BRUISERSHOT + -1, // doomednum + S_BRBALL1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_firsht, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BRBALLX1, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 15*FRACUNIT, // speed + 6*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 8, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_KNIGHT + 69, // doomednum + S_BOS2_STND, // spawnstate + 500, // spawnhealth + S_BOS2_RUN1, // seestate + sfx_kntsit, // seesound + 8, // reactiontime + 0, // attacksound + S_BOS2_PAIN, // painstate + 50, // painchance + sfx_dmpain, // painsound + S_BOS2_ATK1, // meleestate + S_BOS2_ATK1, // missilestate + S_BOS2_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_kntdth, // deathsound + 8, // speed + 24*FRACUNIT, // radius + 64*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_BOS2_RAISE1 // raisestate + }, + + { // MT_SKULL + 3006, // doomednum + S_SKULL_STND, // spawnstate + 100, // spawnhealth + S_SKULL_RUN1, // seestate + 0, // seesound + 8, // reactiontime + sfx_sklatk, // attacksound + S_SKULL_PAIN, // painstate + 256, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_SKULL_ATK1, // missilestate + S_SKULL_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 8, // speed + 16*FRACUNIT, // radius + 56*FRACUNIT, // height + 50, // mass + 3, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_SPIDER + 7, // doomednum + S_SPID_STND, // spawnstate + 3000, // spawnhealth + S_SPID_RUN1, // seestate + sfx_spisit, // seesound + 8, // reactiontime + sfx_shotgn, // attacksound + S_SPID_PAIN, // painstate + 40, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_SPID_ATK1, // missilestate + S_SPID_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_spidth, // deathsound + 12, // speed + 128*FRACUNIT, // radius + 100*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_NULL // raisestate + }, + + { // MT_BABY + 68, // doomednum + S_BSPI_STND, // spawnstate + 500, // spawnhealth + S_BSPI_SIGHT, // seestate + sfx_bspsit, // seesound + 8, // reactiontime + 0, // attacksound + S_BSPI_PAIN, // painstate + 128, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_BSPI_ATK1, // missilestate + S_BSPI_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_bspdth, // deathsound + 12, // speed + 64*FRACUNIT, // radius + 64*FRACUNIT, // height + 600, // mass + 0, // damage + sfx_bspact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_BSPI_RAISE1 // raisestate + }, + + { // MT_CYBORG + 16, // doomednum + S_CYBER_STND, // spawnstate + 4000, // spawnhealth + S_CYBER_RUN1, // seestate + sfx_cybsit, // seesound + 8, // reactiontime + 0, // attacksound + S_CYBER_PAIN, // painstate + 20, // painchance + sfx_dmpain, // painsound + 0, // meleestate + S_CYBER_ATK1, // missilestate + S_CYBER_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_cybdth, // deathsound + 16, // speed + 40*FRACUNIT, // radius + 110*FRACUNIT, // height + 1000, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_NULL // raisestate + }, + + { // MT_PAIN + 71, // doomednum + S_PAIN_STND, // spawnstate + 400, // spawnhealth + S_PAIN_RUN1, // seestate + sfx_pesit, // seesound + 8, // reactiontime + 0, // attacksound + S_PAIN_PAIN, // painstate + 128, // painchance + sfx_pepain, // painsound + 0, // meleestate + S_PAIN_ATK1, // missilestate + S_PAIN_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_pedth, // deathsound + 8, // speed + 31*FRACUNIT, // radius + 56*FRACUNIT, // height + 400, // mass + 0, // damage + sfx_dmact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY|MF_COUNTKILL, // flags + S_PAIN_RAISE1 // raisestate + }, + + { // MT_WOLFSS + 84, // doomednum + S_SSWV_STND, // spawnstate + 50, // spawnhealth + S_SSWV_RUN1, // seestate + sfx_sssit, // seesound + 8, // reactiontime + 0, // attacksound + S_SSWV_PAIN, // painstate + 170, // painchance + sfx_popain, // painsound + 0, // meleestate + S_SSWV_ATK1, // missilestate + S_SSWV_DIE1, // deathstate + S_SSWV_XDIE1, // xdeathstate + sfx_ssdth, // deathsound + 8, // speed + 20*FRACUNIT, // radius + 56*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_posact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_SSWV_RAISE1 // raisestate + }, + + { // MT_KEEN + 72, // doomednum + S_KEENSTND, // spawnstate + 100, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_KEENPAIN, // painstate + 256, // painchance + sfx_keenpn, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_COMMKEEN, // deathstate + S_NULL, // xdeathstate + sfx_keendt, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 72*FRACUNIT, // height + 10000000, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_NULL // raisestate + }, + + { // MT_BOSSBRAIN + 88, // doomednum + S_BRAIN, // spawnstate + 250, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_BRAIN_PAIN, // painstate + 255, // painchance + sfx_bospn, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BRAIN_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_bosdth, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 10000000, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SHOOTABLE, // flags + S_NULL // raisestate + }, + + { // MT_BOSSSPIT + 89, // doomednum + S_BRAINEYE, // spawnstate + 1000, // spawnhealth + S_BRAINEYESEE, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 32*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOSECTOR, // flags + S_NULL // raisestate + }, + + { // MT_BOSSTARGET + 87, // doomednum + S_NULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 32*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOSECTOR, // flags + S_NULL // raisestate + }, + + { // MT_SPAWNSHOT + -1, // doomednum + S_SPAWN1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_bospit, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 10*FRACUNIT, // speed + 6*FRACUNIT, // radius + 32*FRACUNIT, // height + 100, // mass + 3, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOCLIP, // flags + S_NULL // raisestate + }, + + { // MT_SPAWNFIRE + -1, // doomednum + S_SPAWNFIRE1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_BARREL + 2035, // doomednum + S_BAR1, // spawnstate + 20, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BEXP, // deathstate + S_NULL, // xdeathstate + sfx_barexp, // deathsound + 0, // speed + 10*FRACUNIT, // radius + 42*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD, // flags + S_NULL // raisestate + }, + + { // MT_TROOPSHOT + -1, // doomednum + S_TBALL1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_firsht, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_TBALLX1, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 10*FRACUNIT, // speed + 6*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 3, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_HEADSHOT + -1, // doomednum + S_RBALL1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_firsht, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_RBALLX1, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 10*FRACUNIT, // speed + 6*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 5, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares, // flags + S_NULL // raisestate + }, + + { // MT_ROCKET + -1, // doomednum + S_ROCKET, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_rlaunc, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_EXPLODE1, // deathstate + S_NULL, // xdeathstate + sfx_barexp, // deathsound + 20*FRACUNIT, // speed + 11*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 20, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_PLASMA + -1, // doomednum + S_PLASBALL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_plasma, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_PLASEXP, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 25*FRACUNIT, // speed + 13*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 5, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_BFG + -1, // doomednum + S_BFGSHOT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + 0, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BFGLAND, // deathstate + S_NULL, // xdeathstate + sfx_rxplod, // deathsound + 25*FRACUNIT, // speed + 13*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 100, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_ARACHPLAZ + -1, // doomednum + S_ARACH_PLAZ, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_plasma, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_ARACH_PLEX, // deathstate + S_NULL, // xdeathstate + sfx_firxpl, // deathsound + 25*FRACUNIT, // speed + 13*FRACUNIT, // radius + 8*FRACUNIT, // height + 100, // mass + 5, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_PUFF + -1, // doomednum + S_PUFF1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_BLOOD + -1, // doomednum + S_BLOOD1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_TFOG + -1, // doomednum + S_TFOG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_IFOG + -1, // doomednum + S_IFOG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_TRANSLUCENT, // flags // phares + S_NULL // raisestate + }, + + { // MT_TELEPORTMAN + 14, // doomednum + S_NULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOSECTOR, // flags + S_NULL // raisestate + }, + + { // MT_EXTRABFG + -1, // doomednum + S_BFGEXP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC0 + 2018, // doomednum + S_ARM1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC1 + 2019, // doomednum + S_ARM2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC2 + 2014, // doomednum + S_BON1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM, // flags + S_NULL // raisestate + }, + + { // MT_MISC3 + 2015, // doomednum + S_BON2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM, // flags + S_NULL // raisestate + }, + + { // MT_MISC4 + 5, // doomednum + S_BKEY, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC5 + 13, // doomednum + S_RKEY, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC6 + 6, // doomednum + S_YKEY, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC7 + 39, // doomednum + S_YSKULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC8 + 38, // doomednum + S_RSKULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC9 + 40, // doomednum + S_BSKULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOTDMATCH, // flags + S_NULL // raisestate + }, + + { // MT_MISC10 + 2011, // doomednum + S_STIM, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC11 + 2012, // doomednum + S_MEDI, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC12 + 2013, // doomednum + S_SOUL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM|MF_TRANSLUCENT, // flags // killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_INV + 2022, // doomednum + S_PINV, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM|MF_TRANSLUCENT, // flags // killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_MISC13 + 2023, // doomednum + S_PSTR, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM, // flags + S_NULL // raisestate + }, + + { // MT_INS + 2024, // doomednum + S_PINS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM|MF_TRANSLUCENT, // flags // killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_MISC14 + 2025, // doomednum + S_SUIT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC15 + 2026, // doomednum + S_PMAP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM, // flags + S_NULL // raisestate + }, + + { // MT_MISC16 + 2045, // doomednum + S_PVIS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM, // flags + S_NULL // raisestate + }, + + { // MT_MEGA + 83, // doomednum + S_MEGA, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_COUNTITEM|MF_TRANSLUCENT, // flags // killough 2/21/98 + S_NULL // raisestate + }, + + { // MT_CLIP + 2007, // doomednum + S_CLIP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC17 + 2048, // doomednum + S_AMMO, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC18 + 2010, // doomednum + S_ROCK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC19 + 2046, // doomednum + S_BROK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC20 + 2047, // doomednum + S_CELL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC21 + 17, // doomednum + S_CELP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC22 + 2008, // doomednum + S_SHEL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC23 + 2049, // doomednum + S_SBOX, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC24 + 8, // doomednum + S_BPAK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC25 + 2006, // doomednum + S_BFUG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_CHAINGUN + 2002, // doomednum + S_MGUN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC26 + 2005, // doomednum + S_CSAW, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC27 + 2003, // doomednum + S_LAUN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC28 + 2004, // doomednum + S_PLAS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_SHOTGUN + 2001, // doomednum + S_SHOT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_SUPERSHOTGUN + 82, // doomednum + S_SHOT2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MISC29 + 85, // doomednum + S_TECHLAMP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC30 + 86, // doomednum + S_TECH2LAMP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC31 + 2028, // doomednum + S_COLU, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC32 + 30, // doomednum + S_TALLGRNCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC33 + 31, // doomednum + S_SHRTGRNCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC34 + 32, // doomednum + S_TALLREDCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC35 + 33, // doomednum + S_SHRTREDCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC36 + 37, // doomednum + S_SKULLCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC37 + 36, // doomednum + S_HEARTCOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC38 + 41, // doomednum + S_EVILEYE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC39 + 42, // doomednum + S_FLOATSKULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC40 + 43, // doomednum + S_TORCHTREE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC41 + 44, // doomednum + S_BLUETORCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC42 + 45, // doomednum + S_GREENTORCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC43 + 46, // doomednum + S_REDTORCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC44 + 55, // doomednum + S_BTORCHSHRT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC45 + 56, // doomednum + S_GTORCHSHRT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC46 + 57, // doomednum + S_RTORCHSHRT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC47 + 47, // doomednum + S_STALAGTITE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC48 + 48, // doomednum + S_TECHPILLAR, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC49 + 34, // doomednum + S_CANDLESTIK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC50 + 35, // doomednum + S_CANDELABRA, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC51 + 49, // doomednum + S_BLOODYTWITCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 68*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC52 + 50, // doomednum + S_MEAT2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 84*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC53 + 51, // doomednum + S_MEAT3, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 84*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC54 + 52, // doomednum + S_MEAT4, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 68*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC55 + 53, // doomednum + S_MEAT5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 52*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC56 + 59, // doomednum + S_MEAT2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 84*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC57 + 60, // doomednum + S_MEAT4, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 68*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC58 + 61, // doomednum + S_MEAT3, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 52*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC59 + 62, // doomednum + S_MEAT5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 52*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC60 + 63, // doomednum + S_BLOODYTWITCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 68*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC61 + 22, // doomednum + S_HEAD_DIE6, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC62 + 15, // doomednum + S_PLAY_DIE7, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC63 + 18, // doomednum + S_POSS_DIE5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC64 + 21, // doomednum + S_SARG_DIE6, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC65 + 23, // doomednum + S_SKULL_DIE6, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC66 + 20, // doomednum + S_TROO_DIE5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC67 + 19, // doomednum + S_SPOS_DIE5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC68 + 10, // doomednum + S_PLAY_XDIE9, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC69 + 12, // doomednum + S_PLAY_XDIE9, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC70 + 28, // doomednum + S_HEADSONSTICK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC71 + 24, // doomednum + S_GIBS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + 0, // flags + S_NULL // raisestate + }, + + { // MT_MISC72 + 27, // doomednum + S_HEADONASTICK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC73 + 29, // doomednum + S_HEADCANDLES, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC74 + 25, // doomednum + S_DEADSTICK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC75 + 26, // doomednum + S_LIVESTICK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC76 + 54, // doomednum + S_BIGTREE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC77 + 70, // doomednum + S_BBAR1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_MISC78 + 73, // doomednum + S_HANGNOGUTS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 88*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC79 + 74, // doomednum + S_HANGBNOBRAIN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 88*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC80 + 75, // doomednum + S_HANGTLOOKDN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC81 + 76, // doomednum + S_HANGTSKULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC82 + 77, // doomednum + S_HANGTLOOKUP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC83 + 78, // doomednum + S_HANGTNOBRAIN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MISC84 + 79, // doomednum + S_COLONGIBS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_MISC85 + 80, // doomednum + S_SMALLPOOL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_MISC86 + 81, // doomednum + S_BRAINSTEM, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + // For use with wind and current effects + { // MT_PUSH // phares + 5001, // doomednum // | //jff 5/11/98 deconflict + S_TNT1, // spawnstate // V // with DOSDoom + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8, // radius + 8, // height + 10, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + // For use with wind and current effects + { // MT_PULL + 5002, // doomednum //jff 5/11/98 deconflict + S_TNT1, // spawnstate // with DOSDoom + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8, // radius + 8, // height + 10, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, +#ifdef DOGS + // Marine's best friend :) // killough 7/19/98 + { // MT_DOGS + 888, // doomednum + S_DOGS_STND, // spawnstate + 500, // spawnhealth + S_DOGS_RUN1, // seestate + sfx_dgsit, // seesound + 8, // reactiontime + sfx_dgatk, // attacksound + S_DOGS_PAIN, // painstate + 180, // painchance + sfx_dgpain, // painsound + S_DOGS_ATK1, // meleestate + 0, // missilestate + S_DOGS_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_dgdth, // deathsound + 10, // speed + 12*FRACUNIT, // radius + 28*FRACUNIT, // height + 100, // mass + 0, // damage + sfx_dgact, // activesound + MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags + S_DOGS_RAISE1 // raisestate + }, +#endif +}; diff --git a/src/info.h b/src/info.h new file mode 100644 index 0000000..11cfb47 --- /dev/null +++ b/src/info.h @@ -0,0 +1,1498 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Thing frame/state LUT, + * generated by multigen utilitiy. + * This one is the original DOOM version, preserved. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __INFO__ +#define __INFO__ + +/* Needed for action function pointer handling. */ +#include "d_think.h" + +/******************************************************************** + * Sprite name enumeration - must match info.c * + ********************************************************************/ +typedef enum +{ + SPR_TROO, + SPR_SHTG, + SPR_PUNG, + SPR_PISG, + SPR_PISF, + SPR_SHTF, + SPR_SHT2, + SPR_CHGG, + SPR_CHGF, + SPR_MISG, + SPR_MISF, + SPR_SAWG, + SPR_PLSG, + SPR_PLSF, + SPR_BFGG, + SPR_BFGF, + SPR_BLUD, + SPR_PUFF, + SPR_BAL1, + SPR_BAL2, + SPR_PLSS, + SPR_PLSE, + SPR_MISL, + SPR_BFS1, + SPR_BFE1, + SPR_BFE2, + SPR_TFOG, + SPR_IFOG, + SPR_PLAY, + SPR_POSS, + SPR_SPOS, + SPR_VILE, + SPR_FIRE, + SPR_FATB, + SPR_FBXP, + SPR_SKEL, + SPR_MANF, + SPR_FATT, + SPR_CPOS, + SPR_SARG, + SPR_HEAD, + SPR_BAL7, + SPR_BOSS, + SPR_BOS2, + SPR_SKUL, + SPR_SPID, + SPR_BSPI, + SPR_APLS, + SPR_APBX, + SPR_CYBR, + SPR_PAIN, + SPR_SSWV, + SPR_KEEN, + SPR_BBRN, + SPR_BOSF, + SPR_ARM1, + SPR_ARM2, + SPR_BAR1, + SPR_BEXP, + SPR_FCAN, + SPR_BON1, + SPR_BON2, + SPR_BKEY, + SPR_RKEY, + SPR_YKEY, + SPR_BSKU, + SPR_RSKU, + SPR_YSKU, + SPR_STIM, + SPR_MEDI, + SPR_SOUL, + SPR_PINV, + SPR_PSTR, + SPR_PINS, + SPR_MEGA, + SPR_SUIT, + SPR_PMAP, + SPR_PVIS, + SPR_CLIP, + SPR_AMMO, + SPR_ROCK, + SPR_BROK, + SPR_CELL, + SPR_CELP, + SPR_SHEL, + SPR_SBOX, + SPR_BPAK, + SPR_BFUG, + SPR_MGUN, + SPR_CSAW, + SPR_LAUN, + SPR_PLAS, + SPR_SHOT, + SPR_SGN2, + SPR_COLU, + SPR_SMT2, + SPR_GOR1, + SPR_POL2, + SPR_POL5, + SPR_POL4, + SPR_POL3, + SPR_POL1, + SPR_POL6, + SPR_GOR2, + SPR_GOR3, + SPR_GOR4, + SPR_GOR5, + SPR_SMIT, + SPR_COL1, + SPR_COL2, + SPR_COL3, + SPR_COL4, + SPR_CAND, + SPR_CBRA, + SPR_COL6, + SPR_TRE1, + SPR_TRE2, + SPR_ELEC, + SPR_CEYE, + SPR_FSKU, + SPR_COL5, + SPR_TBLU, + SPR_TGRN, + SPR_TRED, + SPR_SMBT, + SPR_SMGT, + SPR_SMRT, + SPR_HDB1, + SPR_HDB2, + SPR_HDB3, + SPR_HDB4, + SPR_HDB5, + SPR_HDB6, + SPR_POB1, + SPR_POB2, + SPR_BRS1, + SPR_TLMP, + SPR_TLP2, + SPR_TNT1, /* add invisible sprite phares 3/8/98 */ + +#ifdef DOGS + SPR_DOGS, /* killough 7/19/98: Marine's best friend :) */ +#endif + + NUMSPRITES /* counter of how many there are */ + +} spritenum_t; + +/******************************************************************** + * States (frames) enumeration -- must match info.c * + ********************************************************************/ + +typedef enum +{ + S_NULL, + S_LIGHTDONE, + S_PUNCH, + S_PUNCHDOWN, + S_PUNCHUP, + S_PUNCH1, + S_PUNCH2, + S_PUNCH3, + S_PUNCH4, + S_PUNCH5, + S_PISTOL, + S_PISTOLDOWN, + S_PISTOLUP, + S_PISTOL1, + S_PISTOL2, + S_PISTOL3, + S_PISTOL4, + S_PISTOLFLASH, + S_SGUN, + S_SGUNDOWN, + S_SGUNUP, + S_SGUN1, + S_SGUN2, + S_SGUN3, + S_SGUN4, + S_SGUN5, + S_SGUN6, + S_SGUN7, + S_SGUN8, + S_SGUN9, + S_SGUNFLASH1, + S_SGUNFLASH2, + S_DSGUN, + S_DSGUNDOWN, + S_DSGUNUP, + S_DSGUN1, + S_DSGUN2, + S_DSGUN3, + S_DSGUN4, + S_DSGUN5, + S_DSGUN6, + S_DSGUN7, + S_DSGUN8, + S_DSGUN9, + S_DSGUN10, + S_DSNR1, + S_DSNR2, + S_DSGUNFLASH1, + S_DSGUNFLASH2, + S_CHAIN, + S_CHAINDOWN, + S_CHAINUP, + S_CHAIN1, + S_CHAIN2, + S_CHAIN3, + S_CHAINFLASH1, + S_CHAINFLASH2, + S_MISSILE, + S_MISSILEDOWN, + S_MISSILEUP, + S_MISSILE1, + S_MISSILE2, + S_MISSILE3, + S_MISSILEFLASH1, + S_MISSILEFLASH2, + S_MISSILEFLASH3, + S_MISSILEFLASH4, + S_SAW, + S_SAWB, + S_SAWDOWN, + S_SAWUP, + S_SAW1, + S_SAW2, + S_SAW3, + S_PLASMA, + S_PLASMADOWN, + S_PLASMAUP, + S_PLASMA1, + S_PLASMA2, + S_PLASMAFLASH1, + S_PLASMAFLASH2, + S_BFG, + S_BFGDOWN, + S_BFGUP, + S_BFG1, + S_BFG2, + S_BFG3, + S_BFG4, + S_BFGFLASH1, + S_BFGFLASH2, + S_BLOOD1, + S_BLOOD2, + S_BLOOD3, + S_PUFF1, + S_PUFF2, + S_PUFF3, + S_PUFF4, + S_TBALL1, + S_TBALL2, + S_TBALLX1, + S_TBALLX2, + S_TBALLX3, + S_RBALL1, + S_RBALL2, + S_RBALLX1, + S_RBALLX2, + S_RBALLX3, + S_PLASBALL, + S_PLASBALL2, + S_PLASEXP, + S_PLASEXP2, + S_PLASEXP3, + S_PLASEXP4, + S_PLASEXP5, + S_ROCKET, + S_BFGSHOT, + S_BFGSHOT2, + S_BFGLAND, + S_BFGLAND2, + S_BFGLAND3, + S_BFGLAND4, + S_BFGLAND5, + S_BFGLAND6, + S_BFGEXP, + S_BFGEXP2, + S_BFGEXP3, + S_BFGEXP4, + S_EXPLODE1, + S_EXPLODE2, + S_EXPLODE3, + S_TFOG, + S_TFOG01, + S_TFOG02, + S_TFOG2, + S_TFOG3, + S_TFOG4, + S_TFOG5, + S_TFOG6, + S_TFOG7, + S_TFOG8, + S_TFOG9, + S_TFOG10, + S_IFOG, + S_IFOG01, + S_IFOG02, + S_IFOG2, + S_IFOG3, + S_IFOG4, + S_IFOG5, + S_PLAY, + S_PLAY_RUN1, + S_PLAY_RUN2, + S_PLAY_RUN3, + S_PLAY_RUN4, + S_PLAY_ATK1, + S_PLAY_ATK2, + S_PLAY_PAIN, + S_PLAY_PAIN2, + S_PLAY_DIE1, + S_PLAY_DIE2, + S_PLAY_DIE3, + S_PLAY_DIE4, + S_PLAY_DIE5, + S_PLAY_DIE6, + S_PLAY_DIE7, + S_PLAY_XDIE1, + S_PLAY_XDIE2, + S_PLAY_XDIE3, + S_PLAY_XDIE4, + S_PLAY_XDIE5, + S_PLAY_XDIE6, + S_PLAY_XDIE7, + S_PLAY_XDIE8, + S_PLAY_XDIE9, + S_POSS_STND, + S_POSS_STND2, + S_POSS_RUN1, + S_POSS_RUN2, + S_POSS_RUN3, + S_POSS_RUN4, + S_POSS_RUN5, + S_POSS_RUN6, + S_POSS_RUN7, + S_POSS_RUN8, + S_POSS_ATK1, + S_POSS_ATK2, + S_POSS_ATK3, + S_POSS_PAIN, + S_POSS_PAIN2, + S_POSS_DIE1, + S_POSS_DIE2, + S_POSS_DIE3, + S_POSS_DIE4, + S_POSS_DIE5, + S_POSS_XDIE1, + S_POSS_XDIE2, + S_POSS_XDIE3, + S_POSS_XDIE4, + S_POSS_XDIE5, + S_POSS_XDIE6, + S_POSS_XDIE7, + S_POSS_XDIE8, + S_POSS_XDIE9, + S_POSS_RAISE1, + S_POSS_RAISE2, + S_POSS_RAISE3, + S_POSS_RAISE4, + S_SPOS_STND, + S_SPOS_STND2, + S_SPOS_RUN1, + S_SPOS_RUN2, + S_SPOS_RUN3, + S_SPOS_RUN4, + S_SPOS_RUN5, + S_SPOS_RUN6, + S_SPOS_RUN7, + S_SPOS_RUN8, + S_SPOS_ATK1, + S_SPOS_ATK2, + S_SPOS_ATK3, + S_SPOS_PAIN, + S_SPOS_PAIN2, + S_SPOS_DIE1, + S_SPOS_DIE2, + S_SPOS_DIE3, + S_SPOS_DIE4, + S_SPOS_DIE5, + S_SPOS_XDIE1, + S_SPOS_XDIE2, + S_SPOS_XDIE3, + S_SPOS_XDIE4, + S_SPOS_XDIE5, + S_SPOS_XDIE6, + S_SPOS_XDIE7, + S_SPOS_XDIE8, + S_SPOS_XDIE9, + S_SPOS_RAISE1, + S_SPOS_RAISE2, + S_SPOS_RAISE3, + S_SPOS_RAISE4, + S_SPOS_RAISE5, + S_VILE_STND, + S_VILE_STND2, + S_VILE_RUN1, + S_VILE_RUN2, + S_VILE_RUN3, + S_VILE_RUN4, + S_VILE_RUN5, + S_VILE_RUN6, + S_VILE_RUN7, + S_VILE_RUN8, + S_VILE_RUN9, + S_VILE_RUN10, + S_VILE_RUN11, + S_VILE_RUN12, + S_VILE_ATK1, + S_VILE_ATK2, + S_VILE_ATK3, + S_VILE_ATK4, + S_VILE_ATK5, + S_VILE_ATK6, + S_VILE_ATK7, + S_VILE_ATK8, + S_VILE_ATK9, + S_VILE_ATK10, + S_VILE_ATK11, + S_VILE_HEAL1, + S_VILE_HEAL2, + S_VILE_HEAL3, + S_VILE_PAIN, + S_VILE_PAIN2, + S_VILE_DIE1, + S_VILE_DIE2, + S_VILE_DIE3, + S_VILE_DIE4, + S_VILE_DIE5, + S_VILE_DIE6, + S_VILE_DIE7, + S_VILE_DIE8, + S_VILE_DIE9, + S_VILE_DIE10, + S_FIRE1, + S_FIRE2, + S_FIRE3, + S_FIRE4, + S_FIRE5, + S_FIRE6, + S_FIRE7, + S_FIRE8, + S_FIRE9, + S_FIRE10, + S_FIRE11, + S_FIRE12, + S_FIRE13, + S_FIRE14, + S_FIRE15, + S_FIRE16, + S_FIRE17, + S_FIRE18, + S_FIRE19, + S_FIRE20, + S_FIRE21, + S_FIRE22, + S_FIRE23, + S_FIRE24, + S_FIRE25, + S_FIRE26, + S_FIRE27, + S_FIRE28, + S_FIRE29, + S_FIRE30, + S_SMOKE1, + S_SMOKE2, + S_SMOKE3, + S_SMOKE4, + S_SMOKE5, + S_TRACER, + S_TRACER2, + S_TRACEEXP1, + S_TRACEEXP2, + S_TRACEEXP3, + S_SKEL_STND, + S_SKEL_STND2, + S_SKEL_RUN1, + S_SKEL_RUN2, + S_SKEL_RUN3, + S_SKEL_RUN4, + S_SKEL_RUN5, + S_SKEL_RUN6, + S_SKEL_RUN7, + S_SKEL_RUN8, + S_SKEL_RUN9, + S_SKEL_RUN10, + S_SKEL_RUN11, + S_SKEL_RUN12, + S_SKEL_FIST1, + S_SKEL_FIST2, + S_SKEL_FIST3, + S_SKEL_FIST4, + S_SKEL_MISS1, + S_SKEL_MISS2, + S_SKEL_MISS3, + S_SKEL_MISS4, + S_SKEL_PAIN, + S_SKEL_PAIN2, + S_SKEL_DIE1, + S_SKEL_DIE2, + S_SKEL_DIE3, + S_SKEL_DIE4, + S_SKEL_DIE5, + S_SKEL_DIE6, + S_SKEL_RAISE1, + S_SKEL_RAISE2, + S_SKEL_RAISE3, + S_SKEL_RAISE4, + S_SKEL_RAISE5, + S_SKEL_RAISE6, + S_FATSHOT1, + S_FATSHOT2, + S_FATSHOTX1, + S_FATSHOTX2, + S_FATSHOTX3, + S_FATT_STND, + S_FATT_STND2, + S_FATT_RUN1, + S_FATT_RUN2, + S_FATT_RUN3, + S_FATT_RUN4, + S_FATT_RUN5, + S_FATT_RUN6, + S_FATT_RUN7, + S_FATT_RUN8, + S_FATT_RUN9, + S_FATT_RUN10, + S_FATT_RUN11, + S_FATT_RUN12, + S_FATT_ATK1, + S_FATT_ATK2, + S_FATT_ATK3, + S_FATT_ATK4, + S_FATT_ATK5, + S_FATT_ATK6, + S_FATT_ATK7, + S_FATT_ATK8, + S_FATT_ATK9, + S_FATT_ATK10, + S_FATT_PAIN, + S_FATT_PAIN2, + S_FATT_DIE1, + S_FATT_DIE2, + S_FATT_DIE3, + S_FATT_DIE4, + S_FATT_DIE5, + S_FATT_DIE6, + S_FATT_DIE7, + S_FATT_DIE8, + S_FATT_DIE9, + S_FATT_DIE10, + S_FATT_RAISE1, + S_FATT_RAISE2, + S_FATT_RAISE3, + S_FATT_RAISE4, + S_FATT_RAISE5, + S_FATT_RAISE6, + S_FATT_RAISE7, + S_FATT_RAISE8, + S_CPOS_STND, + S_CPOS_STND2, + S_CPOS_RUN1, + S_CPOS_RUN2, + S_CPOS_RUN3, + S_CPOS_RUN4, + S_CPOS_RUN5, + S_CPOS_RUN6, + S_CPOS_RUN7, + S_CPOS_RUN8, + S_CPOS_ATK1, + S_CPOS_ATK2, + S_CPOS_ATK3, + S_CPOS_ATK4, + S_CPOS_PAIN, + S_CPOS_PAIN2, + S_CPOS_DIE1, + S_CPOS_DIE2, + S_CPOS_DIE3, + S_CPOS_DIE4, + S_CPOS_DIE5, + S_CPOS_DIE6, + S_CPOS_DIE7, + S_CPOS_XDIE1, + S_CPOS_XDIE2, + S_CPOS_XDIE3, + S_CPOS_XDIE4, + S_CPOS_XDIE5, + S_CPOS_XDIE6, + S_CPOS_RAISE1, + S_CPOS_RAISE2, + S_CPOS_RAISE3, + S_CPOS_RAISE4, + S_CPOS_RAISE5, + S_CPOS_RAISE6, + S_CPOS_RAISE7, + S_TROO_STND, + S_TROO_STND2, + S_TROO_RUN1, + S_TROO_RUN2, + S_TROO_RUN3, + S_TROO_RUN4, + S_TROO_RUN5, + S_TROO_RUN6, + S_TROO_RUN7, + S_TROO_RUN8, + S_TROO_ATK1, + S_TROO_ATK2, + S_TROO_ATK3, + S_TROO_PAIN, + S_TROO_PAIN2, + S_TROO_DIE1, + S_TROO_DIE2, + S_TROO_DIE3, + S_TROO_DIE4, + S_TROO_DIE5, + S_TROO_XDIE1, + S_TROO_XDIE2, + S_TROO_XDIE3, + S_TROO_XDIE4, + S_TROO_XDIE5, + S_TROO_XDIE6, + S_TROO_XDIE7, + S_TROO_XDIE8, + S_TROO_RAISE1, + S_TROO_RAISE2, + S_TROO_RAISE3, + S_TROO_RAISE4, + S_TROO_RAISE5, + S_SARG_STND, + S_SARG_STND2, + S_SARG_RUN1, + S_SARG_RUN2, + S_SARG_RUN3, + S_SARG_RUN4, + S_SARG_RUN5, + S_SARG_RUN6, + S_SARG_RUN7, + S_SARG_RUN8, + S_SARG_ATK1, + S_SARG_ATK2, + S_SARG_ATK3, + S_SARG_PAIN, + S_SARG_PAIN2, + S_SARG_DIE1, + S_SARG_DIE2, + S_SARG_DIE3, + S_SARG_DIE4, + S_SARG_DIE5, + S_SARG_DIE6, + S_SARG_RAISE1, + S_SARG_RAISE2, + S_SARG_RAISE3, + S_SARG_RAISE4, + S_SARG_RAISE5, + S_SARG_RAISE6, + S_HEAD_STND, + S_HEAD_RUN1, + S_HEAD_ATK1, + S_HEAD_ATK2, + S_HEAD_ATK3, + S_HEAD_PAIN, + S_HEAD_PAIN2, + S_HEAD_PAIN3, + S_HEAD_DIE1, + S_HEAD_DIE2, + S_HEAD_DIE3, + S_HEAD_DIE4, + S_HEAD_DIE5, + S_HEAD_DIE6, + S_HEAD_RAISE1, + S_HEAD_RAISE2, + S_HEAD_RAISE3, + S_HEAD_RAISE4, + S_HEAD_RAISE5, + S_HEAD_RAISE6, + S_BRBALL1, + S_BRBALL2, + S_BRBALLX1, + S_BRBALLX2, + S_BRBALLX3, + S_BOSS_STND, + S_BOSS_STND2, + S_BOSS_RUN1, + S_BOSS_RUN2, + S_BOSS_RUN3, + S_BOSS_RUN4, + S_BOSS_RUN5, + S_BOSS_RUN6, + S_BOSS_RUN7, + S_BOSS_RUN8, + S_BOSS_ATK1, + S_BOSS_ATK2, + S_BOSS_ATK3, + S_BOSS_PAIN, + S_BOSS_PAIN2, + S_BOSS_DIE1, + S_BOSS_DIE2, + S_BOSS_DIE3, + S_BOSS_DIE4, + S_BOSS_DIE5, + S_BOSS_DIE6, + S_BOSS_DIE7, + S_BOSS_RAISE1, + S_BOSS_RAISE2, + S_BOSS_RAISE3, + S_BOSS_RAISE4, + S_BOSS_RAISE5, + S_BOSS_RAISE6, + S_BOSS_RAISE7, + S_BOS2_STND, + S_BOS2_STND2, + S_BOS2_RUN1, + S_BOS2_RUN2, + S_BOS2_RUN3, + S_BOS2_RUN4, + S_BOS2_RUN5, + S_BOS2_RUN6, + S_BOS2_RUN7, + S_BOS2_RUN8, + S_BOS2_ATK1, + S_BOS2_ATK2, + S_BOS2_ATK3, + S_BOS2_PAIN, + S_BOS2_PAIN2, + S_BOS2_DIE1, + S_BOS2_DIE2, + S_BOS2_DIE3, + S_BOS2_DIE4, + S_BOS2_DIE5, + S_BOS2_DIE6, + S_BOS2_DIE7, + S_BOS2_RAISE1, + S_BOS2_RAISE2, + S_BOS2_RAISE3, + S_BOS2_RAISE4, + S_BOS2_RAISE5, + S_BOS2_RAISE6, + S_BOS2_RAISE7, + S_SKULL_STND, + S_SKULL_STND2, + S_SKULL_RUN1, + S_SKULL_RUN2, + S_SKULL_ATK1, + S_SKULL_ATK2, + S_SKULL_ATK3, + S_SKULL_ATK4, + S_SKULL_PAIN, + S_SKULL_PAIN2, + S_SKULL_DIE1, + S_SKULL_DIE2, + S_SKULL_DIE3, + S_SKULL_DIE4, + S_SKULL_DIE5, + S_SKULL_DIE6, + S_SPID_STND, + S_SPID_STND2, + S_SPID_RUN1, + S_SPID_RUN2, + S_SPID_RUN3, + S_SPID_RUN4, + S_SPID_RUN5, + S_SPID_RUN6, + S_SPID_RUN7, + S_SPID_RUN8, + S_SPID_RUN9, + S_SPID_RUN10, + S_SPID_RUN11, + S_SPID_RUN12, + S_SPID_ATK1, + S_SPID_ATK2, + S_SPID_ATK3, + S_SPID_ATK4, + S_SPID_PAIN, + S_SPID_PAIN2, + S_SPID_DIE1, + S_SPID_DIE2, + S_SPID_DIE3, + S_SPID_DIE4, + S_SPID_DIE5, + S_SPID_DIE6, + S_SPID_DIE7, + S_SPID_DIE8, + S_SPID_DIE9, + S_SPID_DIE10, + S_SPID_DIE11, + S_BSPI_STND, + S_BSPI_STND2, + S_BSPI_SIGHT, + S_BSPI_RUN1, + S_BSPI_RUN2, + S_BSPI_RUN3, + S_BSPI_RUN4, + S_BSPI_RUN5, + S_BSPI_RUN6, + S_BSPI_RUN7, + S_BSPI_RUN8, + S_BSPI_RUN9, + S_BSPI_RUN10, + S_BSPI_RUN11, + S_BSPI_RUN12, + S_BSPI_ATK1, + S_BSPI_ATK2, + S_BSPI_ATK3, + S_BSPI_ATK4, + S_BSPI_PAIN, + S_BSPI_PAIN2, + S_BSPI_DIE1, + S_BSPI_DIE2, + S_BSPI_DIE3, + S_BSPI_DIE4, + S_BSPI_DIE5, + S_BSPI_DIE6, + S_BSPI_DIE7, + S_BSPI_RAISE1, + S_BSPI_RAISE2, + S_BSPI_RAISE3, + S_BSPI_RAISE4, + S_BSPI_RAISE5, + S_BSPI_RAISE6, + S_BSPI_RAISE7, + S_ARACH_PLAZ, + S_ARACH_PLAZ2, + S_ARACH_PLEX, + S_ARACH_PLEX2, + S_ARACH_PLEX3, + S_ARACH_PLEX4, + S_ARACH_PLEX5, + S_CYBER_STND, + S_CYBER_STND2, + S_CYBER_RUN1, + S_CYBER_RUN2, + S_CYBER_RUN3, + S_CYBER_RUN4, + S_CYBER_RUN5, + S_CYBER_RUN6, + S_CYBER_RUN7, + S_CYBER_RUN8, + S_CYBER_ATK1, + S_CYBER_ATK2, + S_CYBER_ATK3, + S_CYBER_ATK4, + S_CYBER_ATK5, + S_CYBER_ATK6, + S_CYBER_PAIN, + S_CYBER_DIE1, + S_CYBER_DIE2, + S_CYBER_DIE3, + S_CYBER_DIE4, + S_CYBER_DIE5, + S_CYBER_DIE6, + S_CYBER_DIE7, + S_CYBER_DIE8, + S_CYBER_DIE9, + S_CYBER_DIE10, + S_PAIN_STND, + S_PAIN_RUN1, + S_PAIN_RUN2, + S_PAIN_RUN3, + S_PAIN_RUN4, + S_PAIN_RUN5, + S_PAIN_RUN6, + S_PAIN_ATK1, + S_PAIN_ATK2, + S_PAIN_ATK3, + S_PAIN_ATK4, + S_PAIN_PAIN, + S_PAIN_PAIN2, + S_PAIN_DIE1, + S_PAIN_DIE2, + S_PAIN_DIE3, + S_PAIN_DIE4, + S_PAIN_DIE5, + S_PAIN_DIE6, + S_PAIN_RAISE1, + S_PAIN_RAISE2, + S_PAIN_RAISE3, + S_PAIN_RAISE4, + S_PAIN_RAISE5, + S_PAIN_RAISE6, + S_SSWV_STND, + S_SSWV_STND2, + S_SSWV_RUN1, + S_SSWV_RUN2, + S_SSWV_RUN3, + S_SSWV_RUN4, + S_SSWV_RUN5, + S_SSWV_RUN6, + S_SSWV_RUN7, + S_SSWV_RUN8, + S_SSWV_ATK1, + S_SSWV_ATK2, + S_SSWV_ATK3, + S_SSWV_ATK4, + S_SSWV_ATK5, + S_SSWV_ATK6, + S_SSWV_PAIN, + S_SSWV_PAIN2, + S_SSWV_DIE1, + S_SSWV_DIE2, + S_SSWV_DIE3, + S_SSWV_DIE4, + S_SSWV_DIE5, + S_SSWV_XDIE1, + S_SSWV_XDIE2, + S_SSWV_XDIE3, + S_SSWV_XDIE4, + S_SSWV_XDIE5, + S_SSWV_XDIE6, + S_SSWV_XDIE7, + S_SSWV_XDIE8, + S_SSWV_XDIE9, + S_SSWV_RAISE1, + S_SSWV_RAISE2, + S_SSWV_RAISE3, + S_SSWV_RAISE4, + S_SSWV_RAISE5, + S_KEENSTND, + S_COMMKEEN, + S_COMMKEEN2, + S_COMMKEEN3, + S_COMMKEEN4, + S_COMMKEEN5, + S_COMMKEEN6, + S_COMMKEEN7, + S_COMMKEEN8, + S_COMMKEEN9, + S_COMMKEEN10, + S_COMMKEEN11, + S_COMMKEEN12, + S_KEENPAIN, + S_KEENPAIN2, + S_BRAIN, + S_BRAIN_PAIN, + S_BRAIN_DIE1, + S_BRAIN_DIE2, + S_BRAIN_DIE3, + S_BRAIN_DIE4, + S_BRAINEYE, + S_BRAINEYESEE, + S_BRAINEYE1, + S_SPAWN1, + S_SPAWN2, + S_SPAWN3, + S_SPAWN4, + S_SPAWNFIRE1, + S_SPAWNFIRE2, + S_SPAWNFIRE3, + S_SPAWNFIRE4, + S_SPAWNFIRE5, + S_SPAWNFIRE6, + S_SPAWNFIRE7, + S_SPAWNFIRE8, + S_BRAINEXPLODE1, + S_BRAINEXPLODE2, + S_BRAINEXPLODE3, + S_ARM1, + S_ARM1A, + S_ARM2, + S_ARM2A, + S_BAR1, + S_BAR2, + S_BEXP, + S_BEXP2, + S_BEXP3, + S_BEXP4, + S_BEXP5, + S_BBAR1, + S_BBAR2, + S_BBAR3, + S_BON1, + S_BON1A, + S_BON1B, + S_BON1C, + S_BON1D, + S_BON1E, + S_BON2, + S_BON2A, + S_BON2B, + S_BON2C, + S_BON2D, + S_BON2E, + S_BKEY, + S_BKEY2, + S_RKEY, + S_RKEY2, + S_YKEY, + S_YKEY2, + S_BSKULL, + S_BSKULL2, + S_RSKULL, + S_RSKULL2, + S_YSKULL, + S_YSKULL2, + S_STIM, + S_MEDI, + S_SOUL, + S_SOUL2, + S_SOUL3, + S_SOUL4, + S_SOUL5, + S_SOUL6, + S_PINV, + S_PINV2, + S_PINV3, + S_PINV4, + S_PSTR, + S_PINS, + S_PINS2, + S_PINS3, + S_PINS4, + S_MEGA, + S_MEGA2, + S_MEGA3, + S_MEGA4, + S_SUIT, + S_PMAP, + S_PMAP2, + S_PMAP3, + S_PMAP4, + S_PMAP5, + S_PMAP6, + S_PVIS, + S_PVIS2, + S_CLIP, + S_AMMO, + S_ROCK, + S_BROK, + S_CELL, + S_CELP, + S_SHEL, + S_SBOX, + S_BPAK, + S_BFUG, + S_MGUN, + S_CSAW, + S_LAUN, + S_PLAS, + S_SHOT, + S_SHOT2, + S_COLU, + S_STALAG, + S_BLOODYTWITCH, + S_BLOODYTWITCH2, + S_BLOODYTWITCH3, + S_BLOODYTWITCH4, + S_DEADTORSO, + S_DEADBOTTOM, + S_HEADSONSTICK, + S_GIBS, + S_HEADONASTICK, + S_HEADCANDLES, + S_HEADCANDLES2, + S_DEADSTICK, + S_LIVESTICK, + S_LIVESTICK2, + S_MEAT2, + S_MEAT3, + S_MEAT4, + S_MEAT5, + S_STALAGTITE, + S_TALLGRNCOL, + S_SHRTGRNCOL, + S_TALLREDCOL, + S_SHRTREDCOL, + S_CANDLESTIK, + S_CANDELABRA, + S_SKULLCOL, + S_TORCHTREE, + S_BIGTREE, + S_TECHPILLAR, + S_EVILEYE, + S_EVILEYE2, + S_EVILEYE3, + S_EVILEYE4, + S_FLOATSKULL, + S_FLOATSKULL2, + S_FLOATSKULL3, + S_HEARTCOL, + S_HEARTCOL2, + S_BLUETORCH, + S_BLUETORCH2, + S_BLUETORCH3, + S_BLUETORCH4, + S_GREENTORCH, + S_GREENTORCH2, + S_GREENTORCH3, + S_GREENTORCH4, + S_REDTORCH, + S_REDTORCH2, + S_REDTORCH3, + S_REDTORCH4, + S_BTORCHSHRT, + S_BTORCHSHRT2, + S_BTORCHSHRT3, + S_BTORCHSHRT4, + S_GTORCHSHRT, + S_GTORCHSHRT2, + S_GTORCHSHRT3, + S_GTORCHSHRT4, + S_RTORCHSHRT, + S_RTORCHSHRT2, + S_RTORCHSHRT3, + S_RTORCHSHRT4, + S_HANGNOGUTS, + S_HANGBNOBRAIN, + S_HANGTLOOKDN, + S_HANGTSKULL, + S_HANGTLOOKUP, + S_HANGTNOBRAIN, + S_COLONGIBS, + S_SMALLPOOL, + S_BRAINSTEM, + S_TECHLAMP, + S_TECHLAMP2, + S_TECHLAMP3, + S_TECHLAMP4, + S_TECH2LAMP, + S_TECH2LAMP2, + S_TECH2LAMP3, + S_TECH2LAMP4, + S_TNT1, /* add state for invisible sprite phares 3/8/98 */ + + S_GRENADE, /* killough 8/9/98: grenade launcher */ + S_DETONATE, /* killough 8/9/98: detonation of objects */ + S_DETONATE2, + S_DETONATE3, + + // always count dog states, even if dogs are disabled + S_DOGS_STND, /* killough 7/19/98: Marine's best friend :) */ + S_DOGS_STND2, + S_DOGS_RUN1, + S_DOGS_RUN2, + S_DOGS_RUN3, + S_DOGS_RUN4, + S_DOGS_RUN5, + S_DOGS_RUN6, + S_DOGS_RUN7, + S_DOGS_RUN8, + S_DOGS_ATK1, + S_DOGS_ATK2, + S_DOGS_ATK3, + S_DOGS_PAIN, + S_DOGS_PAIN2, + S_DOGS_DIE1, + S_DOGS_DIE2, + S_DOGS_DIE3, + S_DOGS_DIE4, + S_DOGS_DIE5, + S_DOGS_DIE6, + S_DOGS_RAISE1, + S_DOGS_RAISE2, + S_DOGS_RAISE3, + S_DOGS_RAISE4, + S_DOGS_RAISE5, + S_DOGS_RAISE6, + + // add dummy beta bfg / lost soul frames for dehacked compatibility + // fixes bug #1576151 (part 2) + S_OLDBFG1, // killough 7/11/98: the old BFG's 43 firing frames + S_OLDBFG42 = S_OLDBFG1+41, + S_OLDBFG43, + + S_PLS1BALL, // killough 7/19/98: first plasma fireball in the beta + S_PLS1BALL2, + S_PLS1EXP, + S_PLS1EXP2, + S_PLS1EXP3, + S_PLS1EXP4, + S_PLS1EXP5, + + S_PLS2BALL, // killough 7/19/98: second plasma fireball in the beta + S_PLS2BALL2, + S_PLS2BALLX1, + S_PLS2BALLX2, + S_PLS2BALLX3, + S_BON3, // killough 7/11/98: evil sceptre in beta version + S_BON4, // killough 7/11/98: unholy bible in beta version + + // killough 10/98: beta lost souls were different from their modern cousins + S_BSKUL_STND, + S_BSKUL_RUN1, + S_BSKUL_RUN2, + S_BSKUL_RUN3, + S_BSKUL_RUN4, + S_BSKUL_ATK1, + S_BSKUL_ATK2, + S_BSKUL_ATK3, + S_BSKUL_PAIN1, + S_BSKUL_PAIN2, + S_BSKUL_PAIN3, + S_BSKUL_DIE1, + S_BSKUL_DIE2, + S_BSKUL_DIE3, + S_BSKUL_DIE4, + S_BSKUL_DIE5, + S_BSKUL_DIE6, + S_BSKUL_DIE7, + S_BSKUL_DIE8, + + S_MUSHROOM, /* killough 10/98: mushroom explosion effect */ + + NUMSTATES /* Counter of how many there are */ + +} statenum_t; + +/******************************************************************** + * Definition of the state (frames) structure * + ********************************************************************/ + +typedef struct +{ + spritenum_t sprite; /* sprite number to show */ + long frame; /* which frame/subframe of the sprite is shown */ + long tics; /* number of gametics this frame should last */ + actionf_t action; /* code pointer to function for action if any */ + statenum_t nextstate; /* linked list pointer to next state or zero */ + long misc1, misc2; /* apparently never used in DOOM */ +} state_t; + +/* these are in info.c */ +extern state_t states[NUMSTATES]; +extern const char *sprnames[]; /* 1/17/98 killough - CPhipps - const */ + +/******************************************************************** + * Thing enumeration -- must match info.c * + ******************************************************************** + * Note that many of these are generically named for the ornamentals + */ + +typedef enum { + MT_PLAYER, + MT_POSSESSED, + MT_SHOTGUY, + MT_VILE, + MT_FIRE, + MT_UNDEAD, + MT_TRACER, + MT_SMOKE, + MT_FATSO, + MT_FATSHOT, + MT_CHAINGUY, + MT_TROOP, + MT_SERGEANT, + MT_SHADOWS, + MT_HEAD, + MT_BRUISER, + MT_BRUISERSHOT, + MT_KNIGHT, + MT_SKULL, + MT_SPIDER, + MT_BABY, + MT_CYBORG, + MT_PAIN, + MT_WOLFSS, + MT_KEEN, + MT_BOSSBRAIN, + MT_BOSSSPIT, + MT_BOSSTARGET, + MT_SPAWNSHOT, + MT_SPAWNFIRE, + MT_BARREL, + MT_TROOPSHOT, + MT_HEADSHOT, + MT_ROCKET, + MT_PLASMA, + MT_BFG, + MT_ARACHPLAZ, + MT_PUFF, + MT_BLOOD, + MT_TFOG, + MT_IFOG, + MT_TELEPORTMAN, + MT_EXTRABFG, + MT_MISC0, + MT_MISC1, + MT_MISC2, + MT_MISC3, + MT_MISC4, + MT_MISC5, + MT_MISC6, + MT_MISC7, + MT_MISC8, + MT_MISC9, + MT_MISC10, + MT_MISC11, + MT_MISC12, + MT_INV, + MT_MISC13, + MT_INS, + MT_MISC14, + MT_MISC15, + MT_MISC16, + MT_MEGA, + MT_CLIP, + MT_MISC17, + MT_MISC18, + MT_MISC19, + MT_MISC20, + MT_MISC21, + MT_MISC22, + MT_MISC23, + MT_MISC24, + MT_MISC25, + MT_CHAINGUN, + MT_MISC26, + MT_MISC27, + MT_MISC28, + MT_SHOTGUN, + MT_SUPERSHOTGUN, + MT_MISC29, + MT_MISC30, + MT_MISC31, + MT_MISC32, + MT_MISC33, + MT_MISC34, + MT_MISC35, + MT_MISC36, + MT_MISC37, + MT_MISC38, + MT_MISC39, + MT_MISC40, + MT_MISC41, + MT_MISC42, + MT_MISC43, + MT_MISC44, + MT_MISC45, + MT_MISC46, + MT_MISC47, + MT_MISC48, + MT_MISC49, + MT_MISC50, + MT_MISC51, + MT_MISC52, + MT_MISC53, + MT_MISC54, + MT_MISC55, + MT_MISC56, + MT_MISC57, + MT_MISC58, + MT_MISC59, + MT_MISC60, + MT_MISC61, + MT_MISC62, + MT_MISC63, + MT_MISC64, + MT_MISC65, + MT_MISC66, + MT_MISC67, + MT_MISC68, + MT_MISC69, + MT_MISC70, + MT_MISC71, + MT_MISC72, + MT_MISC73, + MT_MISC74, + MT_MISC75, + MT_MISC76, + MT_MISC77, + MT_MISC78, + MT_MISC79, + MT_MISC80, + MT_MISC81, + MT_MISC82, + MT_MISC83, + MT_MISC84, + MT_MISC85, + MT_MISC86, + MT_PUSH, /* controls push source - phares */ + MT_PULL, /* controls pull source - phares 3/20/98 */ + +#ifdef DOGS + MT_DOGS, /* killough 7/19/98: Marine's best friend */ +#endif + + /* proff 11/22/98: Andy Baker's stealth monsters (next 12) + * cph - moved below the MBF stuff, no need to displace them */ + MT_STEALTHBABY, + MT_STEALTHVILE, + MT_STEALTHBRUISER, + MT_STEALTHHEAD, + MT_STEALTHCHAINGUY, + MT_STEALTHSERGEANT, + MT_STEALTHKNIGHT, + MT_STEALTHIMP, + MT_STEALTHFATSO, + MT_STEALTHUNDEAD, + MT_STEALTHSHOTGUY, + MT_STEALTHZOMBIE, + + NUMMOBJTYPES // Counter of how many there are +} mobjtype_t; + +/******************************************************************** + * Definition of the Thing structure + ********************************************************************/ +/* Note that these are only indices to the state, sound, etc. arrays + * and not actual pointers. Most can be set to zero if the action or + * sound doesn't apply (like lamps generally don't attack or whistle). + */ + +typedef struct +{ + int doomednum; /* Thing number used in id's editor, and now + probably by every other editor too */ + int spawnstate; /* The state (frame) index when this Thing is + first created */ + int spawnhealth; /* The initial hit points for this Thing */ + int seestate; /* The state when it sees you or wakes up */ + int seesound; /* The sound it makes when waking */ + int reactiontime; /* How many tics it waits after it wakes up + before it will start to attack, in normal + skills (halved for nightmare) */ + int attacksound; /* The sound it makes when it attacks */ + int painstate; /* The state to indicate pain */ + int painchance; /* A number that is checked against a random + number 0-255 to see if the Thing is supposed + to go to its painstate or not. Note this + has absolutely nothing to do with the chance + it will get hurt, just the chance of it + reacting visibly. */ + int painsound; /* The sound it emits when it feels pain */ + int meleestate; /* Melee==close attack */ + int missilestate; /* What states to use when it's in the air, if + in fact it is ever used as a missile */ + int deathstate; /* What state begins the death sequence */ + int xdeathstate; /* What state begins the horrible death sequence + like when a rocket takes out a trooper */ + int deathsound; /* The death sound. See also A_Scream() in + p_enemy.c for some tweaking that goes on + for certain monsters */ + int speed; /* How fast it moves. Too fast and it can miss + collision logic. */ + int radius; /* An often incorrect radius */ + int height; /* An often incorrect height, used only to see + if a monster can enter a sector */ + int mass; /* How much an impact will move it. Cacodemons + seem to retreat when shot because they have + very little mass and are moved by impact */ + int damage; /* If this is a missile, how much does it hurt? */ + int activesound; /* What sound it makes wandering around, once + in a while. Chance is 3/256 it will. */ + uint_64_t flags; /* Bit masks for lots of things. See p_mobj.h */ + int raisestate; /* The first state for an Archvile or respawn + resurrection. Zero means it won't come + back to life. */ +} mobjinfo_t; + +/* See p_mobj_h for addition more technical info */ +extern mobjinfo_t mobjinfo[NUMMOBJTYPES]; + +#endif diff --git a/src/lprintf.c b/src/lprintf.c new file mode 100644 index 0000000..0951cf3 --- /dev/null +++ b/src/lprintf.c @@ -0,0 +1,382 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Provides a logical console output routine that allows what is + * output to console normally and when output is redirected to + * be controlled.. + * + *-----------------------------------------------------------------------------*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif +#ifdef _MSC_VER +#include +#endif +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include "doomtype.h" +#include "lprintf.h" +#include "i_main.h" +#include "m_argv.h" + +int cons_error_mask = -1-LO_INFO; /* all but LO_INFO when redir'd */ +int cons_output_mask = -1; /* all output enabled */ + +/* cphipps - enlarged message buffer and made non-static + * We still have to be careful here, this function can be called after exit + */ +#define MAX_MESSAGE_SIZE 2048 + +#ifdef _WIN32 +// Variables for the console +HWND con_hWnd=0; +HFONT OemFont; +LONG OemWidth, OemHeight; +int ConWidth,ConHeight; +char szConName[] = "PrBoomConWinClass"; +char Lines[(80+2)*25+1]; +char *Last = NULL; +boolean console_inited=FALSE; +static boolean should_exit = 0; + +static CALLBACK ConWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) +{ + PAINTSTRUCT paint; + HDC dc; + + switch (iMsg) { + case WM_KEYDOWN: + if (wParam == VK_ESCAPE) + should_exit = 1; + break; + case WM_CLOSE: + return 1; + break; + case WM_PAINT: + if (dc = BeginPaint (con_hWnd, &paint)) + { + if (Last) + { + char *row; + int line, last; + + line = paint.rcPaint.top / OemHeight; + last = paint.rcPaint.bottom / OemHeight; + for (row = Lines + (line*(80+2)); line < last; line++) + { + if (row[1]>0) + TextOut (dc, 0, line * OemHeight, &row[2], row[1]); + row += 80 + 2; + } + } + EndPaint (con_hWnd, &paint); + } + return 0; + break; + default: + break; + } + return(DefWindowProc(hwnd,iMsg,wParam,lParam)); +} + +static void I_PrintStr (int xp, const char *cp, int count, BOOL scroll) { + RECT rect; + HDC conDC; + + if ((!con_hWnd) || (!console_inited)) + return; + if (count) + { + conDC=GetDC(con_hWnd); + TextOut (conDC, xp * OemWidth, ConHeight - OemHeight, cp, count); + ReleaseDC(con_hWnd,conDC); + } + if (scroll) { + rect.left = 0; + rect.top = 0; + rect.right = ConWidth; + rect.bottom = ConHeight; + ScrollWindowEx (con_hWnd, 0, -OemHeight, NULL, &rect, NULL, NULL, SW_ERASE|SW_INVALIDATE); + UpdateWindow (con_hWnd); + } +} + +static int I_ConPrintString (const char *outline) +{ + const char *cp, *newcp; + static int xp = 0; + int newxp; + BOOL scroll; + + if (!console_inited) + return 0; + cp = outline; + while (*cp) { + for (newcp = cp, newxp = xp; + *newcp != '\n' && *newcp != '\0' && newxp < 80; + newcp++) { + if (*newcp == '\x08') { + newxp--; + break; + } + else if (*newcp == '\t') { + newxp = ((newxp + 8) / 8) * 8; + break; + } + else + newxp++; + } + + if (*cp) { + const char *poop; + int x; + + for (x = xp, poop = cp; poop < newcp; poop++, x++) { + Last[x+2] = ((*poop) < 32) ? 32 : (*poop); + } + + if (*newcp == '\t') + for (x = xp; x < newxp; x++) + Last[x+2] = ' '; + + if (Last[1] < xp + (newcp - cp)) + Last[1] = xp + (newcp - cp); + + if (*newcp == '\n' || xp == 80) { + if (*newcp != '\n') { + Last[0] = 1; + } + memmove (Lines, Lines + (80 + 2), (80 + 2) * (25 - 1)); + Last[0] = 0; + Last[1] = 0; + newxp = 0; + scroll = TRUE; + } else { + scroll = FALSE; + } + I_PrintStr (xp, cp, newcp - cp, scroll); + + xp = newxp; + + if ((*newcp == '\n') || (*newcp == '\x08') || (*newcp == '\t')) + cp = newcp + 1; + else + cp = newcp; + } + } + + return strlen (outline); +} + +void I_ConTextAttr(unsigned char a) +{ + int r,g,b,col; + HDC conDC; + + if (!console_inited) + return; + conDC=GetDC(con_hWnd); + r=0; g=0; b=0; + if (a & FOREGROUND_INTENSITY) col=255; + else col=128; + if (a & FOREGROUND_RED) r=col; + if (a & FOREGROUND_GREEN) g=col; + if (a & FOREGROUND_BLUE) b=col; + SetTextColor(conDC, PALETTERGB(r,g,b)); + r=0; g=0; b=0; + if (a & BACKGROUND_INTENSITY) col=255; + else col=128; + if (a & BACKGROUND_RED) r=col; + if (a & BACKGROUND_GREEN) g=col; + if (a & BACKGROUND_BLUE) b=col; + SetBkColor(conDC, PALETTERGB(r,g,b)); + ReleaseDC(con_hWnd,conDC); +} + +void I_UpdateConsole(void) +{ + MSG msg; + + UpdateWindow(con_hWnd); + while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + if (should_exit) + exit(0); +} + +static void Init_Console(void) +{ + memset(Lines,0,25*(80+2)+1); + Last = Lines + (25 - 1) * (80 + 2); + console_inited=TRUE; +} + +int Init_ConsoleWin(void) +{ + HDC conDC; + WNDCLASS wndclass; + TEXTMETRIC metrics; + RECT cRect; + int width,height; + int scr_width,scr_height; + HINSTANCE hInstance; + char titlebuffer[2048]; + + if (con_hWnd) + return TRUE; + hInstance = GetModuleHandle(NULL); + Init_Console(); + /* Register the frame class */ + wndclass.style = CS_OWNDC; + wndclass.lpfnWndProc = (WNDPROC)ConWndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = hInstance; + wndclass.hIcon = LoadIcon (hInstance, IDI_WINLOGO); + wndclass.hCursor = LoadCursor (NULL,IDC_ARROW); + wndclass.hbrBackground = (HBRUSH)GetStockObject (BLACK_BRUSH); + wndclass.lpszMenuName = szConName; + wndclass.lpszClassName = szConName; + + if (!RegisterClass(&wndclass)) + return FALSE; + + width=100; + height=100; + strcpy(titlebuffer,PACKAGE); + strcat(titlebuffer," "); + strcat(titlebuffer,VERSION); + strcat(titlebuffer," console"); + con_hWnd = CreateWindow(szConName, titlebuffer, + WS_CAPTION | WS_POPUP, + 0, 0, width, height, + NULL, NULL, hInstance, NULL); + conDC=GetDC(con_hWnd); + OemFont = GetStockObject(OEM_FIXED_FONT); + SelectObject(conDC, OemFont); + GetTextMetrics(conDC, &metrics); + OemWidth = metrics.tmAveCharWidth; + OemHeight = metrics.tmHeight; + GetClientRect(con_hWnd, &cRect); + width += (OemWidth * 80) - cRect.right; + height += (OemHeight * 25) - cRect.bottom; + // proff 11/09/98: Added code for centering console + scr_width = GetSystemMetrics(SM_CXFULLSCREEN); + scr_height = GetSystemMetrics(SM_CYFULLSCREEN); + MoveWindow(con_hWnd, (scr_width-width)/2, (scr_height-height)/2, width, height, TRUE); + GetClientRect(con_hWnd, &cRect); + ConWidth = cRect.right; + ConHeight = cRect.bottom; + SetTextColor(conDC, RGB(192,192,192)); + SetBkColor(conDC, RGB(0,0,0)); + SetBkMode(conDC, OPAQUE); + ReleaseDC(con_hWnd,conDC); + ShowWindow(con_hWnd, SW_SHOW); + UpdateWindow(con_hWnd); + return TRUE; +} + +void Done_ConsoleWin(void) +{ + if (con_hWnd) + DestroyWindow(con_hWnd); + UnregisterClass(szConName,GetModuleHandle(NULL)); + con_hWnd=0; +} +#endif + +int lprintf(OutputLevels pri, const char *s, ...) +{ + int r=0; + char msg[MAX_MESSAGE_SIZE]; + int lvl=pri; + + va_list v; + va_start(v,s); +#ifdef HAVE_VSNPRINTF + vsnprintf(msg,sizeof(msg),s,v); /* print message in buffer */ +#else + vsprintf(msg,s,v); +#endif + va_end(v); + + if (lvl&cons_output_mask) /* mask output as specified */ + { + r=fprintf(stdout,"%s",msg); +#ifdef _WIN32 + I_ConPrintString(msg); +#endif + } + if (!isatty(1) && lvl&cons_error_mask) /* if stdout redirected */ + r=fprintf(stderr,"%s",msg); /* select output at console */ + + return r; +} + +/* + * I_Error + * + * cphipps - moved out of i_* headers, to minimise source files that depend on + * the low-level headers. All this does is print the error, then call the + * low-level safe exit function. + * killough 3/20/98: add const + */ + +void I_Error(const char *error, ...) +{ + char errmsg[MAX_MESSAGE_SIZE]; + va_list argptr; + va_start(argptr,error); +#ifdef HAVE_VSNPRINTF + vsnprintf(errmsg,sizeof(errmsg),error,argptr); +#else + vsprintf(errmsg,error,argptr); +#endif + va_end(argptr); + lprintf(LO_ERROR, "%s\n", errmsg); +#ifdef _MSC_VER + if (!M_CheckParm ("-nodraw")) { + //Init_ConsoleWin(); + MessageBox(con_hWnd,errmsg,"PrBoom",MB_OK | MB_TASKMODAL | MB_TOPMOST); + } +#endif + I_SafeExit(-1); +} diff --git a/src/lprintf.h b/src/lprintf.h new file mode 100644 index 0000000..9871688 --- /dev/null +++ b/src/lprintf.h @@ -0,0 +1,68 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Declarations etc. for logical console output + * + *-----------------------------------------------------------------------------*/ + +#ifndef __LPRINTF__ +#define __LPRINTF__ + +typedef enum /* Logical output levels */ +{ + LO_INFO=1, /* One of these is used in each physical output */ + LO_CONFIRM=2, /* call. Which are output, or echoed to console */ + LO_WARN=4, /* if output redirected is determined by the */ + LO_ERROR=8, /* global masks: cons_output_mask,cons_error_mask. */ + LO_FATAL=16, + LO_DEBUG=32, + LO_ALWAYS=64, +} OutputLevels; + +#ifndef __GNUC__ +#define __attribute__(x) +#endif + +extern int lprintf(OutputLevels pri, const char *fmt, ...) __attribute__((format(printf,2,3))); +extern int cons_output_mask; +extern int cons_error_mask; + +/* killough 3/20/98: add const + * killough 4/25/98: add gcc attributes + * cphipps 01/11- moved from i_system.h */ +void I_Error(const char *error, ...) __attribute__((format(printf,1,2))); + +#ifdef _WIN32 +void I_ConTextAttr(unsigned char a); +void I_UpdateConsole(void); +int Init_ConsoleWin(void); +void Done_ConsoleWin(void); +#endif + +#endif diff --git a/src/m_argv.c b/src/m_argv.c new file mode 100644 index 0000000..9392840 --- /dev/null +++ b/src/m_argv.c @@ -0,0 +1,58 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Some argument handling. + * + *-----------------------------------------------------------------------------*/ + +#include +// CPhipps - include the correct header +#include "doomtype.h" +#include "m_argv.h" + +int myargc; +const char * const * myargv; // CPhipps - not sure if ANSI C allows you to +// modify contents of argv, but I can't imagine it does. + +// +// M_CheckParm +// Checks for the given parameter +// in the program's command line arguments. +// Returns the argument number (1 to argc-1) +// or 0 if not present +// + +int M_CheckParm(const char *check) +{ + signed int i = myargc; + while (--i>0) + if (!strcasecmp(check, myargv[i])) + return i; + return 0; +} diff --git a/src/m_argv.h b/src/m_argv.h new file mode 100644 index 0000000..5340c15 --- /dev/null +++ b/src/m_argv.h @@ -0,0 +1,47 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Argument handling. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __M_ARGV__ +#define __M_ARGV__ + +/* + * MISC + */ +extern int myargc; +extern const char * const * myargv; /* CPhipps - const * const * */ + +/* Returns the position of the given parameter in the arg list (0 if not found). */ +int M_CheckParm(const char *check); + +#endif diff --git a/src/m_bbox.c b/src/m_bbox.c new file mode 100644 index 0000000..f2097ce --- /dev/null +++ b/src/m_bbox.c @@ -0,0 +1,58 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Main loop menu stuff. + * Random number LUT. + * Default Config File. + * PCX Screenshots. + * + *-----------------------------------------------------------------------------*/ + +#ifdef __GNUG__ +#pragma implementation "m_bbox.h" +#endif +#include "m_bbox.h" + +void M_ClearBox (fixed_t *box) +{ + box[BOXTOP] = box[BOXRIGHT] = INT_MIN; + box[BOXBOTTOM] = box[BOXLEFT] = INT_MAX; +} + +void M_AddToBox(fixed_t* box,fixed_t x,fixed_t y) + { + if (xbox[BOXRIGHT]) + box[BOXRIGHT] = x; + if (ybox[BOXTOP]) + box[BOXTOP] = y; + } diff --git a/src/m_bbox.h b/src/m_bbox.h new file mode 100644 index 0000000..5c2f2df --- /dev/null +++ b/src/m_bbox.h @@ -0,0 +1,56 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Simple bounding box datatype and functions. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __M_BBOX__ +#define __M_BBOX__ + +#include +#include "m_fixed.h" + +/* Bounding box coordinate storage. */ +enum +{ + BOXTOP, + BOXBOTTOM, + BOXLEFT, + BOXRIGHT +}; /* bbox coordinates */ + +/* Bounding box functions. */ + +void M_ClearBox(fixed_t* box); + +void M_AddToBox(fixed_t* box,fixed_t x,fixed_t y); + +#endif diff --git a/src/m_cheat.c b/src/m_cheat.c new file mode 100644 index 0000000..aebad97 --- /dev/null +++ b/src/m_cheat.c @@ -0,0 +1,744 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2002 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Cheat sequence checking. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "g_game.h" +#include "r_data.h" +#include "p_inter.h" +#include "p_tick.h" +#include "m_cheat.h" +#include "m_argv.h" +#include "s_sound.h" +#include "sounds.h" +#include "dstrings.h" +#include "r_main.h" +#include "p_map.h" +#include "d_deh.h" // Ty 03/27/98 - externalized strings +/* cph 2006/07/23 - needs direct access to thinkercap */ +#include "p_tick.h" + +#define plyr (players+consoleplayer) /* the console player */ + +//----------------------------------------------------------------------------- +// +// CHEAT SEQUENCE PACKAGE +// +//----------------------------------------------------------------------------- + +static void cheat_mus(); +static void cheat_choppers(); +static void cheat_god(); +static void cheat_fa(); +static void cheat_k(); +static void cheat_kfa(); +static void cheat_noclip(); +static void cheat_pw(); +static void cheat_behold(); +static void cheat_clev(); +static void cheat_mypos(); +static void cheat_rate(); +static void cheat_comp(); +static void cheat_friction(); +static void cheat_pushers(); +static void cheat_tnttran(); +static void cheat_massacre(); +static void cheat_ddt(); +static void cheat_hom(); +static void cheat_fast(); +static void cheat_tntkey(); +static void cheat_tntkeyx(); +static void cheat_tntkeyxx(); +static void cheat_tntweap(); +static void cheat_tntweapx(); +static void cheat_tntammo(); +static void cheat_tntammox(); +static void cheat_smart(); +static void cheat_pitch(); +static void cheat_megaarmour(); +static void cheat_health(); + +//----------------------------------------------------------------------------- +// +// List of cheat codes, functions, and special argument indicators. +// +// The first argument is the cheat code. +// +// The second argument is its DEH name, or NULL if it's not supported by -deh. +// +// The third argument is a combination of the bitmasks: +// {always, not_dm, not_coop, not_net, not_menu, not_demo, not_deh}, +// which excludes the cheat during certain modes of play. +// +// The fourth argument is the handler function. +// +// The fifth argument is passed to the handler function if it's non-negative; +// if negative, then its negative indicates the number of extra characters +// expected after the cheat code, which are passed to the handler function +// via a pointer to a buffer (after folding any letters to lowercase). +// +//----------------------------------------------------------------------------- + +struct cheat_s cheat[] = { + {"idmus", "Change music", always, + cheat_mus, -2}, + + {"idchoppers", "Chainsaw", not_net | not_demo, + cheat_choppers }, + + {"iddqd", "God mode", not_net | not_demo, + cheat_god }, + +#if 0 + {"idk", NULL, not_net | not_demo | not_deh, + cheat_k }, // The most controversial cheat code in Doom history!!! +#endif + + {"idkfa", "Ammo & Keys", not_net | not_demo, + cheat_kfa }, + + {"idfa", "Ammo", not_net | not_demo, + cheat_fa }, + + {"idspispopd", "No Clipping 1", not_net | not_demo, + cheat_noclip }, + + {"idclip", "No Clipping 2", not_net | not_demo, + cheat_noclip }, + + {"idbeholdh", "Invincibility", not_net | not_demo, + cheat_health }, + + {"idbeholdm", "Invincibility", not_net | not_demo, + cheat_megaarmour }, + + {"idbeholdv", "Invincibility", not_net | not_demo, + cheat_pw, pw_invulnerability }, + + {"idbeholds", "Berserk", not_net | not_demo, + cheat_pw, pw_strength }, + + {"idbeholdi", "Invisibility", not_net | not_demo, + cheat_pw, pw_invisibility }, + + {"idbeholdr", "Radiation Suit", not_net | not_demo, + cheat_pw, pw_ironfeet }, + + {"idbeholda", "Auto-map", not_dm, + cheat_pw, pw_allmap }, + + {"idbeholdl", "Lite-Amp Goggles", not_dm, + cheat_pw, pw_infrared }, + + {"idbehold", "BEHOLD menu", not_dm, + cheat_behold }, + + {"idclev", "Level Warp", not_net | not_demo | not_menu, + cheat_clev, -2}, + + {"idmypos", "Player Position", not_dm, + cheat_mypos }, + + {"idrate", "Frame rate", 0, + cheat_rate }, + + {"tntcomp", NULL, not_net | not_demo, + cheat_comp }, // phares + + {"tntem", NULL, not_net | not_demo, + cheat_massacre }, // jff 2/01/98 kill all monsters + + {"iddt", "Map cheat", not_dm, + cheat_ddt }, // killough 2/07/98: moved from am_map.c + + {"tnthom", NULL, always, + cheat_hom }, // killough 2/07/98: HOM autodetector + + {"tntkey", NULL, not_net | not_demo, + cheat_tntkey }, // killough 2/16/98: generalized key cheats + + {"tntkeyr", NULL, not_net | not_demo, + cheat_tntkeyx }, + + {"tntkeyy", NULL, not_net | not_demo, + cheat_tntkeyx }, + + {"tntkeyb", NULL, not_net | not_demo, + cheat_tntkeyx }, + + {"tntkeyrc", NULL, not_net | not_demo, + cheat_tntkeyxx, it_redcard }, + + {"tntkeyyc", NULL, not_net | not_demo, + cheat_tntkeyxx, it_yellowcard }, + + {"tntkeybc", NULL, not_net | not_demo, + cheat_tntkeyxx, it_bluecard }, + + {"tntkeyrs", NULL, not_net | not_demo, + cheat_tntkeyxx, it_redskull }, + + {"tntkeyys", NULL, not_net | not_demo, + cheat_tntkeyxx, it_yellowskull}, + + {"tntkeybs", NULL, not_net | not_demo, + cheat_tntkeyxx, it_blueskull }, // killough 2/16/98: end generalized keys + + {"tntka", NULL, not_net | not_demo, + cheat_k }, // Ty 04/11/98 - Added TNTKA + + {"tntweap", NULL, not_net | not_demo, + cheat_tntweap }, // killough 2/16/98: generalized weapon cheats + + {"tntweap", NULL, not_net | not_demo, + cheat_tntweapx, -1}, + + {"tntammo", NULL, not_net | not_demo, + cheat_tntammo }, + + {"tntammo", NULL, not_net | not_demo, + cheat_tntammox, -1}, // killough 2/16/98: end generalized weapons + + {"tnttran", NULL, always, + cheat_tnttran }, // invoke translucency // phares + + {"tntsmart", NULL, not_net | not_demo, + cheat_smart}, // killough 2/21/98: smart monster toggle + + {"tntpitch", NULL, always, + cheat_pitch}, // killough 2/21/98: pitched sound toggle + + // killough 2/21/98: reduce RSI injury by adding simpler alias sequences: + {"tntran", NULL, always, + cheat_tnttran }, // killough 2/21/98: same as tnttran + + {"tntamo", NULL, not_net | not_demo, + cheat_tntammo }, // killough 2/21/98: same as tntammo + + {"tntamo", NULL, not_net | not_demo, + cheat_tntammox, -1}, // killough 2/21/98: same as tntammo + + {"tntfast", NULL, not_net | not_demo, + cheat_fast }, // killough 3/6/98: -fast toggle + + {"tntice", NULL, not_net | not_demo, + cheat_friction }, // phares 3/10/98: toggle variable friction effects + + {"tntpush", NULL, not_net | not_demo, + cheat_pushers }, // phares 3/10/98: toggle pushers + + {NULL} // end-of-list marker +}; + +//----------------------------------------------------------------------------- + +static void cheat_mus(buf) +char buf[3]; +{ + int musnum; + + //jff 3/20/98 note: this cheat allowed in netgame/demorecord + + //jff 3/17/98 avoid musnum being negative and crashing + if (!isdigit(buf[0]) || !isdigit(buf[1])) + return; + + plyr->message = s_STSTR_MUS; // Ty 03/27/98 - externalized + + if (gamemode == commercial) + { + musnum = mus_runnin + (buf[0]-'0')*10 + buf[1]-'0' - 1; + + //jff 4/11/98 prevent IDMUS00 in DOOMII and IDMUS36 or greater + if (musnum < mus_runnin || ((buf[0]-'0')*10 + buf[1]-'0') > 35) + plyr->message = s_STSTR_NOMUS; // Ty 03/27/98 - externalized + else + { + S_ChangeMusic(musnum, 1); + idmusnum = musnum; //jff 3/17/98 remember idmus number for restore + } + } + else + { + musnum = mus_e1m1 + (buf[0]-'1')*9 + (buf[1]-'1'); + + //jff 4/11/98 prevent IDMUS0x IDMUSx0 in DOOMI and greater than introa + if (buf[0] < '1' || buf[1] < '1' || ((buf[0]-'1')*9 + buf[1]-'1') > 31) + plyr->message = s_STSTR_NOMUS; // Ty 03/27/98 - externalized + else + { + S_ChangeMusic(musnum, 1); + idmusnum = musnum; //jff 3/17/98 remember idmus number for restore + } + } +} + +// 'choppers' invulnerability & chainsaw +static void cheat_choppers() +{ + plyr->weaponowned[wp_chainsaw] = true; + plyr->powers[pw_invulnerability] = true; + plyr->message = s_STSTR_CHOPPERS; // Ty 03/27/98 - externalized +} + +static void cheat_god() +{ // 'dqd' cheat for toggleable god mode + plyr->cheats ^= CF_GODMODE; + if (plyr->cheats & CF_GODMODE) + { + if (plyr->mo) + plyr->mo->health = god_health; // Ty 03/09/98 - deh + + plyr->health = god_health; + plyr->message = s_STSTR_DQDON; // Ty 03/27/98 - externalized + } + else + plyr->message = s_STSTR_DQDOFF; // Ty 03/27/98 - externalized +} + +// CPhipps - new health and armour cheat codes +static void cheat_health() +{ + if (!(plyr->cheats & CF_GODMODE)) { + if (plyr->mo) + plyr->mo->health = mega_health; + plyr->health = mega_health; + plyr->message = s_STSTR_BEHOLDX; // Ty 03/27/98 - externalized + } +} + +static void cheat_megaarmour() +{ + plyr->armorpoints = idfa_armor; // Ty 03/09/98 - deh + plyr->armortype = idfa_armor_class; // Ty 03/09/98 - deh + plyr->message = s_STSTR_BEHOLDX; // Ty 03/27/98 - externalized +} + +static void cheat_fa() +{ + int i; + + if (!plyr->backpack) + { + for (i=0 ; imaxammo[i] *= 2; + plyr->backpack = true; + } + + plyr->armorpoints = idfa_armor; // Ty 03/09/98 - deh + plyr->armortype = idfa_armor_class; // Ty 03/09/98 - deh + + // You can't own weapons that aren't in the game // phares 02/27/98 + for (i=0;iweaponowned[i] = true; + + for (i=0;iammo[i] = plyr->maxammo[i]; + + plyr->message = s_STSTR_FAADDED; +} + +static void cheat_k() +{ + int i; + for (i=0;icards[i]) // only print message if at least one key added + { // however, caller may overwrite message anyway + plyr->cards[i] = true; + plyr->message = "Keys Added"; + } +} + +static void cheat_kfa() +{ + cheat_k(); + cheat_fa(); + plyr->message = STSTR_KFAADDED; +} + +static void cheat_noclip() +{ + // Simplified, accepting both "noclip" and "idspispopd". + // no clipping mode cheat + + plyr->message = (plyr->cheats ^= CF_NOCLIP) & CF_NOCLIP ? + s_STSTR_NCON : s_STSTR_NCOFF; // Ty 03/27/98 - externalized +} + +// 'behold?' power-up cheats (modified for infinite duration -- killough) +static void cheat_pw(int pw) +{ + if (plyr->powers[pw]) + plyr->powers[pw] = pw!=pw_strength && pw!=pw_allmap; // killough + else + { + P_GivePower(plyr, pw); + if (pw != pw_strength) + plyr->powers[pw] = -1; // infinite duration -- killough + } + plyr->message = s_STSTR_BEHOLDX; // Ty 03/27/98 - externalized +} + +// 'behold' power-up menu +static void cheat_behold() +{ + plyr->message = s_STSTR_BEHOLD; // Ty 03/27/98 - externalized +} + +// 'clev' change-level cheat +static void cheat_clev(char buf[3]) +{ + int epsd, map; + + if (gamemode == commercial) + { + epsd = 1; //jff was 0, but espd is 1-based + map = (buf[0] - '0')*10 + buf[1] - '0'; + } + else + { + epsd = buf[0] - '0'; + map = buf[1] - '0'; + } + + // Catch invalid maps. + if (epsd < 1 || map < 1 || // Ohmygod - this is not going to work. + (gamemode == retail && (epsd > 4 || map > 9 )) || + (gamemode == registered && (epsd > 3 || map > 9 )) || + (gamemode == shareware && (epsd > 1 || map > 9 )) || + (gamemode == commercial && (epsd > 1 || map > 32 )) ) //jff no 33 and 34 + return; //8/14/98 allowed + + // So be it. + + idmusnum = -1; //jff 3/17/98 revert to normal level music on IDCLEV + + plyr->message = s_STSTR_CLEV; // Ty 03/27/98 - externalized + + G_DeferedInitNew(gameskill, epsd, map); +} + +// 'mypos' for player position +// killough 2/7/98: simplified using dprintf and made output more user-friendly +static void cheat_mypos() +{ + doom_printf("Position (%d,%d,%d)\tAngle %-.0f", + players[consoleplayer].mo->x >> FRACBITS, + players[consoleplayer].mo->y >> FRACBITS, + players[consoleplayer].mo->z >> FRACBITS, + players[consoleplayer].mo->angle * (90.0/ANG90)); +} + +// cph - cheat to toggle frame rate/rendering stats display +static void cheat_rate() +{ + rendering_stats ^= 1; +} + +// compatibility cheat + +static void cheat_comp() +{ + // CPhipps - modified for new compatibility system + compatibility_level++; compatibility_level %= MAX_COMPATIBILITY_LEVEL; + // must call G_Compatibility after changing compatibility_level + // (fixes sf bug number 1558738) + G_Compatibility(); + doom_printf("New compatibility level:\n%s", + comp_lev_str[compatibility_level]); +} + +// variable friction cheat +static void cheat_friction() +{ + plyr->message = // Ty 03/27/98 - *not* externalized + (variable_friction = !variable_friction) ? "Variable Friction enabled" : + "Variable Friction disabled"; +} + + +// Pusher cheat +// phares 3/10/98 +static void cheat_pushers() +{ + plyr->message = // Ty 03/27/98 - *not* externalized + (allow_pushers = !allow_pushers) ? "Pushers enabled" : "Pushers disabled"; +} + +// translucency cheat +static void cheat_tnttran() +{ + plyr->message = // Ty 03/27/98 - *not* externalized + (general_translucency = !general_translucency) ? "Translucency enabled" : + "Translucency disabled"; + + // killough 3/1/98, 4/11/98: cache translucency map on a demand basis + if (general_translucency && !main_tranmap) + R_InitTranMap(0); +} + +static void cheat_massacre() // jff 2/01/98 kill all monsters +{ + // jff 02/01/98 'em' cheat - kill all monsters + // partially taken from Chi's .46 port + // + // killough 2/7/98: cleaned up code and changed to use dprintf; + // fixed lost soul bug (LSs left behind when PEs are killed) + + int killcount=0; + thinker_t *currentthinker = NULL; + extern void A_PainDie(mobj_t *); + + // killough 7/20/98: kill friendly monsters only if no others to kill + uint_64_t mask = MF_FRIEND; + P_MapStart(); + do + while ((currentthinker = P_NextThinker(currentthinker,th_all)) != NULL) + if (currentthinker->function == P_MobjThinker && + !(((mobj_t *) currentthinker)->flags & mask) && // killough 7/20/98 + (((mobj_t *) currentthinker)->flags & MF_COUNTKILL || + ((mobj_t *) currentthinker)->type == MT_SKULL)) + { // killough 3/6/98: kill even if PE is dead + if (((mobj_t *) currentthinker)->health > 0) + { + killcount++; + P_DamageMobj((mobj_t *)currentthinker, NULL, NULL, 10000); + } + if (((mobj_t *) currentthinker)->type == MT_PAIN) + { + A_PainDie((mobj_t *) currentthinker); // killough 2/8/98 + P_SetMobjState ((mobj_t *) currentthinker, S_PAIN_DIE6); + } + } + while (!killcount && mask ? mask=0, 1 : 0); // killough 7/20/98 + P_MapEnd(); + // killough 3/22/98: make more intelligent about plural + // Ty 03/27/98 - string(s) *not* externalized + doom_printf("%d Monster%s Killed", killcount, killcount==1 ? "" : "s"); +} + +// killough 2/7/98: move iddt cheat from am_map.c to here +// killough 3/26/98: emulate Doom better +static void cheat_ddt() +{ + extern int ddt_cheating; + if (automapmode & am_active) + ddt_cheating = (ddt_cheating+1) % 3; +} + +// killough 2/7/98: HOM autodetection +static void cheat_hom() +{ + extern int autodetect_hom; // Ty 03/27/98 - *not* externalized + plyr->message = (autodetect_hom = !autodetect_hom) ? "HOM Detection On" : + "HOM Detection Off"; +} + +// killough 3/6/98: -fast parameter toggle +static void cheat_fast() +{ + plyr->message = (fastparm = !fastparm) ? "Fast Monsters On" : + "Fast Monsters Off"; // Ty 03/27/98 - *not* externalized + G_SetFastParms(fastparm); // killough 4/10/98: set -fast parameter correctly +} + +// killough 2/16/98: keycard/skullkey cheat functions +static void cheat_tntkey() +{ + plyr->message = "Red, Yellow, Blue"; // Ty 03/27/98 - *not* externalized +} + +static void cheat_tntkeyx() +{ + plyr->message = "Card, Skull"; // Ty 03/27/98 - *not* externalized +} + +static void cheat_tntkeyxx(int key) +{ + plyr->message = (plyr->cards[key] = !plyr->cards[key]) ? + "Key Added" : "Key Removed"; // Ty 03/27/98 - *not* externalized +} + +// killough 2/16/98: generalized weapon cheats + +static void cheat_tntweap() +{ // Ty 03/27/98 - *not* externalized + plyr->message = gamemode==commercial ? // killough 2/28/98 + "Weapon number 1-9" : "Weapon number 1-8"; +} + +static void cheat_tntweapx(buf) +char buf[3]; +{ + int w = *buf - '1'; + + if ((w==wp_supershotgun && gamemode!=commercial) || // killough 2/28/98 + ((w==wp_bfg || w==wp_plasma) && gamemode==shareware)) + return; + + if (w==wp_fist) // make '1' apply beserker strength toggle + cheat_pw(pw_strength); + else + if (w >= 0 && w < NUMWEAPONS) { + if ((plyr->weaponowned[w] = !plyr->weaponowned[w])) + plyr->message = "Weapon Added"; // Ty 03/27/98 - *not* externalized + else + { + plyr->message = "Weapon Removed"; // Ty 03/27/98 - *not* externalized + if (w==plyr->readyweapon) // maybe switch if weapon removed + plyr->pendingweapon = P_SwitchWeapon(plyr); + } + } +} + +// killough 2/16/98: generalized ammo cheats +static void cheat_tntammo() +{ + plyr->message = "Ammo 1-4, Backpack"; // Ty 03/27/98 - *not* externalized +} + +static void cheat_tntammox(buf) +char buf[1]; +{ + int a = *buf - '1'; + if (*buf == 'b') // Ty 03/27/98 - strings *not* externalized + if ((plyr->backpack = !plyr->backpack)) + for (plyr->message = "Backpack Added", a=0 ; amaxammo[a] <<= 1; + else + for (plyr->message = "Backpack Removed", a=0 ; aammo[a] > (plyr->maxammo[a] >>= 1)) + plyr->ammo[a] = plyr->maxammo[a]; + } + else + if (a>=0 && amessage = (plyr->ammo[a] = !plyr->ammo[a]) ? + plyr->ammo[a] = plyr->maxammo[a], "Ammo Added" : "Ammo Removed"; + } +} + +static void cheat_smart() +{ + plyr->message = (monsters_remember = !monsters_remember) ? + "Smart Monsters Enabled" : "Smart Monsters Disabled"; +} + +static void cheat_pitch() +{ + plyr->message=(pitched_sounds = !pitched_sounds) ? "Pitch Effects Enabled" : + "Pitch Effects Disabled"; +} + +//----------------------------------------------------------------------------- +// 2/7/98: Cheat detection rewritten by Lee Killough, to avoid +// scrambling and to use a more general table-driven approach. +//----------------------------------------------------------------------------- + +#define CHEAT_ARGS_MAX 8 /* Maximum number of args at end of cheats */ + +boolean M_FindCheats(int key) +{ + static uint_64_t sr; + static char argbuf[CHEAT_ARGS_MAX+1], *arg; + static int init, argsleft, cht; + int i, ret, matchedbefore; + + // If we are expecting arguments to a cheat + // (e.g. idclev), put them in the arg buffer + + if (argsleft) + { + *arg++ = tolower(key); // store key in arg buffer + if (!--argsleft) // if last key in arg list, + cheat[cht].func(argbuf); // process the arg buffer + return 1; // affirmative response + } + + key = tolower(key) - 'a'; + if (key < 0 || key >= 32) // ignore most non-alpha cheat letters + { + sr = 0; // clear shift register + return 0; + } + + if (!init) // initialize aux entries of table + { + init = 1; + for (i=0;cheat[i].cheat;i++) + { + uint_64_t c=0, m=0; + const char *p; + + for (p=cheat[i].cheat; *p; p++) + { + unsigned key = tolower(*p)-'a'; // convert to 0-31 + if (key >= 32) // ignore most non-alpha cheat letters + continue; + c = (c<<5) + key; // shift key into code + m = (m<<5) + 31; // shift 1's into mask + } + cheat[i].code = c; // code for this cheat key + cheat[i].mask = m; // mask for this cheat key + } + } + + sr = (sr<<5) + key; // shift this key into shift register + + for (matchedbefore = ret = i = 0; cheat[i].cheat; i++) + if ((sr & cheat[i].mask) == cheat[i].code && // if match found + !(cheat[i].when & not_dm && deathmatch) && // and if cheat allowed + !(cheat[i].when & not_coop && netgame && !deathmatch) && + !(cheat[i].when & not_demo && (demorecording || demoplayback)) && + !(cheat[i].when & not_menu && menuactive) && + !(cheat[i].when & not_deh && M_CheckParm("-deh"))) { + if (cheat[i].arg < 0) // if additional args are required + { + cht = i; // remember this cheat code + arg = argbuf; // point to start of arg buffer + argsleft = -cheat[i].arg; // number of args expected + ret = 1; // responder has eaten key + } + else + if (!matchedbefore) // allow only one cheat at a time + { + matchedbefore = ret = 1; // responder has eaten key + cheat[i].func(cheat[i].arg); // call cheat handler + } + } + return ret; +} diff --git a/src/m_cheat.h b/src/m_cheat.h new file mode 100644 index 0000000..f7bafce --- /dev/null +++ b/src/m_cheat.h @@ -0,0 +1,58 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Cheat code checking. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __M_CHEAT__ +#define __M_CHEAT__ + +/* killough 4/16/98: Cheat table structure */ + +extern struct cheat_s { + const char * cheat; + const char *const deh_cheat; + enum { + always = 0, + not_dm = 1, + not_coop = 2, + not_demo = 4, + not_menu = 8, + not_deh = 16, + not_net = not_dm | not_coop + } const when; + void (*const func)(); + const int arg; + uint_64_t code, mask; +} cheat[]; + +boolean M_FindCheats(int key); + +#endif diff --git a/src/m_fixed.h b/src/m_fixed.h new file mode 100644 index 0000000..2eb36db --- /dev/null +++ b/src/m_fixed.h @@ -0,0 +1,101 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Fixed point arithemtics, implementation. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __M_FIXED__ +#define __M_FIXED__ + +#include "config.h" +#include "doomtype.h" + +/* + * Fixed point, 32bit as 16.16. + */ + +#define FRACBITS 16 +#define FRACUNIT (1<> (8*sizeof _t-1); + return (_t^_s)-_s; +} +/* + * Fixed Point Multiplication + */ + +/* CPhipps - made __inline__ to inline, as specified in the gcc docs + * Also made const */ + +inline static CONSTFUNC fixed_t FixedMul(fixed_t a, fixed_t b) +{ + return (fixed_t)((int_64_t) a*b >> FRACBITS); +} +/* + * Fixed Point Division + */ + +/* CPhipps - made __inline__ to inline, as specified in the gcc docs + * Also made const */ + +inline static CONSTFUNC fixed_t FixedDiv(fixed_t a, fixed_t b) +{ + return ((unsigned)D_abs(a)>>14) >= (unsigned)D_abs(b) ? ((a^b)>>31) ^ INT_MAX : + (fixed_t)(((int_64_t) a << FRACBITS) / b); +} + + +/* CPhipps - + * FixedMod - returns a % b, guaranteeing 0<=a +#include + +#include "doomdef.h" +#include "doomstat.h" +#include "dstrings.h" +#include "d_main.h" +#include "v_video.h" +#include "w_wad.h" +#include "r_main.h" +#include "hu_stuff.h" +#include "g_game.h" +#include "s_sound.h" +#include "sounds.h" +#include "m_menu.h" +#include "d_deh.h" +#include "m_misc.h" +#include "lprintf.h" +#include "am_map.h" +#include "i_main.h" +#include "i_system.h" +#include "i_video.h" +#include "i_sound.h" +#include "r_demo.h" +#include "r_fps.h" + +extern patchnum_t hu_font[HU_FONTSIZE]; +extern boolean message_dontfuckwithme; + +extern boolean chat_on; // in heads-up code + +// +// defaulted values +// + +int mouseSensitivity_horiz; // has default // killough +int mouseSensitivity_vert; // has default + +int showMessages; // Show messages has default, 0 = off, 1 = on + +int hide_setup=1; // killough 5/15/98 + +// Blocky mode, has default, 0 = high, 1 = normal +//int detailLevel; obsolete -- killough +int screenblocks; // has default + +int screenSize; // temp for screenblocks (0-9) + +int quickSaveSlot; // -1 = no quicksave slot picked! + +int messageToPrint; // 1 = message to be printed + +// CPhipps - static const +static const char* messageString; // ...and here is the message string! + +// message x & y +int messx; +int messy; +int messageLastMenuActive; + +boolean messageNeedsInput; // timed message = no input from user + +void (*messageRoutine)(int response); + +#define SAVESTRINGSIZE 24 + +/* killough 8/15/98: when changes are allowed to sync-critical variables */ +static int allow_changes(void) +{ + return !(demoplayback || demorecording || netgame); +} + +static void M_UpdateCurrent(default_t* def) +{ + /* cph - requires rewrite of m_misc.c */ + if (def->current) { + if (allow_changes()) /* killough 8/15/98 */ + *def->current = *def->location.pi; + else if (*def->current != *def->location.pi) + warn_about_changes(S_LEVWARN); /* killough 8/15/98 */ + } +} + +int warning_about_changes, print_warning_about_changes; + +/* cphipps - M_DrawBackground renamed and moved to v_video.c */ +#define M_DrawBackground V_DrawBackground + +// we are going to be entering a savegame string + +int saveStringEnter; +int saveSlot; // which slot to save in +int saveCharIndex; // which char we're editing +// old save description before edit +char saveOldString[SAVESTRINGSIZE]; + +boolean inhelpscreens; // indicates we are in or just left a help screen + +boolean menuactive; // The menus are up + +#define SKULLXOFF -32 +#define LINEHEIGHT 16 + +char savegamestrings[10][SAVESTRINGSIZE]; + +// +// MENU TYPEDEFS +// + +typedef struct +{ + short status; // 0 = no cursor here, 1 = ok, 2 = arrows ok + char name[10]; + + // choice = menu item #. + // if status = 2, + // choice=0:leftarrow,1:rightarrow + void (*routine)(int choice); + char alphaKey; // hotkey in menu +} menuitem_t; + +typedef struct menu_s +{ + short numitems; // # of menu items + struct menu_s* prevMenu; // previous menu + menuitem_t* menuitems; // menu items + void (*routine)(); // draw routine + short x; + short y; // x,y of menu + short lastOn; // last item user was on in menu +} menu_t; + +short itemOn; // menu item skull is on (for Big Font menus) +short skullAnimCounter; // skull animation counter +short whichSkull; // which skull to draw (he blinks) + +// graphic name of skulls + +const char skullName[2][/*8*/9] = {"M_SKULL1","M_SKULL2"}; + +menu_t* currentMenu; // current menudef + +// phares 3/30/98 +// externs added for setup menus + +extern int mousebfire; +extern int mousebstrafe; +extern int mousebforward; +// proff 08/17/98: Added backward to mousebuttons +extern int mousebbackward; +extern int joybfire; +extern int joybstrafe; +extern int joybuse; +extern int joybspeed; +int mapcolor_me; // cph + +extern int map_point_coordinates; // killough 10/98 + +extern char* chat_macros[]; // chat macros +extern const char* shiftxform; +extern default_t defaults[]; +extern int numdefaults; + +// end of externs added for setup menus + +// +// PROTOTYPES +// +void M_NewGame(int choice); +void M_Episode(int choice); +void M_ChooseSkill(int choice); +void M_LoadGame(int choice); +void M_SaveGame(int choice); +void M_Options(int choice); +void M_EndGame(int choice); +void M_ReadThis(int choice); +void M_ReadThis2(int choice); +void M_QuitDOOM(int choice); + +void M_ChangeMessages(int choice); +void M_ChangeSensitivity(int choice); +void M_SfxVol(int choice); +void M_MusicVol(int choice); +/* void M_ChangeDetail(int choice); unused -- killough */ +void M_SizeDisplay(int choice); +void M_StartGame(int choice); +void M_Sound(int choice); + +void M_Mouse(int choice, int *sens); /* killough */ +void M_MouseVert(int choice); +void M_MouseHoriz(int choice); +void M_DrawMouse(void); + +void M_FinishReadThis(int choice); +void M_FinishHelp(int choice); // killough 10/98 +void M_LoadSelect(int choice); +void M_SaveSelect(int choice); +void M_ReadSaveStrings(void); +void M_QuickSave(void); +void M_QuickLoad(void); + +void M_DrawMainMenu(void); +void M_DrawReadThis1(void); +void M_DrawReadThis2(void); +void M_DrawNewGame(void); +void M_DrawEpisode(void); +void M_DrawOptions(void); +void M_DrawSound(void); +void M_DrawLoad(void); +void M_DrawSave(void); +void M_DrawSetup(void); // phares 3/21/98 +void M_DrawHelp (void); // phares 5/04/98 + +void M_DrawSaveLoadBorder(int x,int y); +void M_SetupNextMenu(menu_t *menudef); +void M_DrawThermo(int x,int y,int thermWidth,int thermDot); +void M_DrawEmptyCell(menu_t *menu,int item); +void M_DrawSelCell(menu_t *menu,int item); +void M_WriteText(int x, int y, const char *string); +int M_StringWidth(const char *string); +int M_StringHeight(const char *string); +void M_StartMessage(const char *string,void *routine,boolean input); +void M_StopMessage(void); +void M_ClearMenus (void); + +// phares 3/30/98 +// prototypes added to support Setup Menus and Extended HELP screens + +int M_GetKeyString(int,int); +void M_Setup(int choice); +void M_KeyBindings(int choice); +void M_Weapons(int); +void M_StatusBar(int); +void M_Automap(int); +void M_Enemy(int); +void M_Messages(int); +void M_ChatStrings(int); +void M_InitExtendedHelp(void); +void M_ExtHelpNextScreen(int); +void M_ExtHelp(int); +static int M_GetPixelWidth(const char*); +void M_DrawKeybnd(void); +void M_DrawWeapons(void); +static void M_DrawMenuString(int,int,int); +static void M_DrawStringCentered(int,int,int,const char*); +void M_DrawStatusHUD(void); +void M_DrawExtHelp(void); +void M_DrawAutoMap(void); +void M_DrawEnemy(void); +void M_DrawMessages(void); +void M_DrawChatStrings(void); +void M_Compat(int); // killough 10/98 +void M_ChangeDemoSmoothTurns(void); +void M_General(int); // killough 10/98 +void M_DrawCompat(void); // killough 10/98 +void M_DrawGeneral(void); // killough 10/98 +void M_FullScreen(void); // nathanh 01/01 + +menu_t NewDef; // phares 5/04/98 + +// end of prototypes added to support Setup Menus and Extended HELP screens + +///////////////////////////////////////////////////////////////////////////// +// +// DOOM MENUS +// + +///////////////////////////// +// +// MAIN MENU +// + +// main_e provides numerical values for which Big Font screen you're on + +enum +{ + newgame = 0, + loadgame, + savegame, + options, + readthis, + quitdoom, + main_end +} main_e; + +// +// MainMenu is the definition of what the main menu Screen should look +// like. Each entry shows that the cursor can land on each item (1), the +// built-in graphic lump (i.e. "M_NGAME") that should be displayed, +// the program which takes over when an item is selected, and the hotkey +// associated with the item. +// + +menuitem_t MainMenu[]= +{ + {1,"M_NGAME", M_NewGame, 'n'}, + {1,"M_OPTION",M_Options, 'o'}, + {1,"M_LOADG", M_LoadGame,'l'}, + {1,"M_SAVEG", M_SaveGame,'s'}, + // Another hickup with Special edition. + {1,"M_RDTHIS",M_ReadThis,'r'}, + {1,"M_QUITG", M_QuitDOOM,'q'} +}; + +menu_t MainDef = +{ + main_end, // number of menu items + NULL, // previous menu screen + MainMenu, // table that defines menu items + M_DrawMainMenu, // drawing routine + 97,64, // initial cursor position + 0 // last menu item the user was on +}; + +// +// M_DrawMainMenu +// + +void M_DrawMainMenu(void) +{ + // CPhipps - patch drawing updated + V_DrawNamePatch(94, 2, 0, "M_DOOM", CR_DEFAULT, VPT_STRETCH); +} + +///////////////////////////// +// +// Read This! MENU 1 & 2 +// + +// There are no menu items on the Read This! screens, so read_e just +// provides a placeholder to maintain structure. + +enum +{ + rdthsempty1, + read1_end +} read_e; + +enum +{ + rdthsempty2, + read2_end +} read_e2; + +enum // killough 10/98 +{ + helpempty, + help_end +} help_e; + + +// The definitions of the Read This! screens + +menuitem_t ReadMenu1[] = +{ + {1,"",M_ReadThis2,0} +}; + +menuitem_t ReadMenu2[]= +{ + {1,"",M_FinishReadThis,0} +}; + +menuitem_t HelpMenu[]= // killough 10/98 +{ + {1,"",M_FinishHelp,0} +}; + +menu_t ReadDef1 = +{ + read1_end, + &MainDef, + ReadMenu1, + M_DrawReadThis1, + 330,175, + //280,185, // killough 2/21/98: fix help screens + 0 +}; + +menu_t ReadDef2 = +{ + read2_end, + &ReadDef1, + ReadMenu2, + M_DrawReadThis2, + 330,175, + 0 +}; + +menu_t HelpDef = // killough 10/98 +{ + help_end, + &HelpDef, + HelpMenu, + M_DrawHelp, + 330,175, + 0 +}; + +// +// M_ReadThis +// + +void M_ReadThis(int choice) +{ + M_SetupNextMenu(&ReadDef1); +} + +void M_ReadThis2(int choice) +{ + M_SetupNextMenu(&ReadDef2); +} + +void M_FinishReadThis(int choice) +{ + M_SetupNextMenu(&MainDef); +} + +void M_FinishHelp(int choice) // killough 10/98 +{ + M_SetupNextMenu(&MainDef); +} + +// +// Read This Menus +// Had a "quick hack to fix romero bug" +// +// killough 10/98: updated with new screens + +void M_DrawReadThis1(void) +{ + inhelpscreens = true; + if (gamemode == shareware) + V_DrawNamePatch(0, 0, 0, "HELP2", CR_DEFAULT, VPT_STRETCH); + else + M_DrawCredits(); +} + +// +// Read This Menus - optional second page. +// +// killough 10/98: updated with new screens + +void M_DrawReadThis2(void) +{ + inhelpscreens = true; + if (gamemode == shareware) + M_DrawCredits(); + else + V_DrawNamePatch(0, 0, 0, "CREDIT", CR_DEFAULT, VPT_STRETCH); +} + +///////////////////////////// +// +// EPISODE SELECT +// + +// +// episodes_e provides numbers for the episode menu items. The default is +// 4, to accomodate Ultimate Doom. If the user is running anything else, +// this is accounted for in the code. +// + +enum +{ + ep1, + ep2, + ep3, + ep4, + ep_end +} episodes_e; + +// The definitions of the Episodes menu + +menuitem_t EpisodeMenu[]= +{ + {1,"M_EPI1", M_Episode,'k'}, + {1,"M_EPI2", M_Episode,'t'}, + {1,"M_EPI3", M_Episode,'i'}, + {1,"M_EPI4", M_Episode,'t'} +}; + +menu_t EpiDef = +{ + ep_end, // # of menu items + &MainDef, // previous menu + EpisodeMenu, // menuitem_t -> + M_DrawEpisode, // drawing routine -> + 48,63, // x,y + ep1 // lastOn +}; + +// +// M_Episode +// +int epi; + +void M_DrawEpisode(void) +{ + // CPhipps - patch drawing updated + V_DrawNamePatch(54, 38, 0, "M_EPISOD", CR_DEFAULT, VPT_STRETCH); +} + +void M_Episode(int choice) +{ + if ( (gamemode == shareware) && choice) { + M_StartMessage(s_SWSTRING,NULL,false); // Ty 03/27/98 - externalized + M_SetupNextMenu(&ReadDef1); + return; + } + + // Yet another hack... + if ( (gamemode == registered) && (choice > 2)) + { + lprintf( LO_WARN, + "M_Episode: 4th episode requires UltimateDOOM\n"); + choice = 0; + } + + epi = choice; + M_SetupNextMenu(&NewDef); +} + +///////////////////////////// +// +// NEW GAME +// + +// numerical values for the New Game menu items + +enum +{ + killthings, + toorough, + hurtme, + violence, + nightmare, + newg_end +} newgame_e; + +// The definitions of the New Game menu + +menuitem_t NewGameMenu[]= +{ + {1,"M_JKILL", M_ChooseSkill, 'i'}, + {1,"M_ROUGH", M_ChooseSkill, 'h'}, + {1,"M_HURT", M_ChooseSkill, 'h'}, + {1,"M_ULTRA", M_ChooseSkill, 'u'}, + {1,"M_NMARE", M_ChooseSkill, 'n'} +}; + +menu_t NewDef = +{ + newg_end, // # of menu items + &EpiDef, // previous menu + NewGameMenu, // menuitem_t -> + M_DrawNewGame, // drawing routine -> + 48,63, // x,y + hurtme // lastOn +}; + +// +// M_NewGame +// + +void M_DrawNewGame(void) +{ + // CPhipps - patch drawing updated + V_DrawNamePatch(96, 14, 0, "M_NEWG", CR_DEFAULT, VPT_STRETCH); + V_DrawNamePatch(54, 38, 0, "M_SKILL",CR_DEFAULT, VPT_STRETCH); +} + +/* cph - make `New Game' restart the level in a netgame */ +static void M_RestartLevelResponse(int ch) +{ + if (ch != 'y') + return; + + if (demorecording) + exit(0); + + currentMenu->lastOn = itemOn; + M_ClearMenus (); + G_RestartLevel (); +} + +void M_NewGame(int choice) +{ + if (netgame && !demoplayback) { + if (compatibility_level < lxdoom_1_compatibility) + M_StartMessage(s_NEWGAME,NULL,false); // Ty 03/27/98 - externalized + else // CPhipps - query restarting the level + M_StartMessage(s_RESTARTLEVEL,M_RestartLevelResponse,true); + return; + } + + if (demorecording) { /* killough 5/26/98: exclude during demo recordings */ + M_StartMessage("you can't start a new game\n" + "while recording a demo!\n\n"PRESSKEY, + NULL, false); // killough 5/26/98: not externalized + return; + } + + if ( gamemode == commercial ) + M_SetupNextMenu(&NewDef); + else + M_SetupNextMenu(&EpiDef); +} + +// CPhipps - static +static void M_VerifyNightmare(int ch) +{ + if (ch != 'y') + return; + + G_DeferedInitNew(nightmare,epi+1,1); + M_ClearMenus (); +} + +void M_ChooseSkill(int choice) +{ + if (choice == nightmare) + { // Ty 03/27/98 - externalized + M_StartMessage(s_NIGHTMARE,M_VerifyNightmare,true); + return; + } + + G_DeferedInitNew(choice,epi+1,1); + M_ClearMenus (); +} + +///////////////////////////// +// +// LOAD GAME MENU +// + +// numerical values for the Load Game slots + +enum +{ + load1, + load2, + load3, + load4, + load5, + load6, + load7, //jff 3/15/98 extend number of slots + load8, + load_end +} load_e; + +// The definitions of the Load Game screen + +menuitem_t LoadMenue[]= +{ + {1,"", M_LoadSelect,'1'}, + {1,"", M_LoadSelect,'2'}, + {1,"", M_LoadSelect,'3'}, + {1,"", M_LoadSelect,'4'}, + {1,"", M_LoadSelect,'5'}, + {1,"", M_LoadSelect,'6'}, + {1,"", M_LoadSelect,'7'}, //jff 3/15/98 extend number of slots + {1,"", M_LoadSelect,'8'}, +}; + +menu_t LoadDef = +{ + load_end, + &MainDef, + LoadMenue, + M_DrawLoad, + 80,34, //jff 3/15/98 move menu up + 0 +}; + +#define LOADGRAPHIC_Y 8 + +// +// M_LoadGame & Cie. +// + +void M_DrawLoad(void) +{ + int i; + + //jff 3/15/98 use symbolic load position + // CPhipps - patch drawing updated + V_DrawNamePatch(72 ,LOADGRAPHIC_Y, 0, "M_LOADG", CR_DEFAULT, VPT_STRETCH); + for (i = 0 ; i < load_end ; i++) { + M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); + M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]); + } +} + +// +// Draw border for the savegame description +// + +void M_DrawSaveLoadBorder(int x,int y) +{ + int i; + + V_DrawNamePatch(x-8, y+7, 0, "M_LSLEFT", CR_DEFAULT, VPT_STRETCH); + + for (i = 0 ; i < 24 ; i++) + { + V_DrawNamePatch(x, y+7, 0, "M_LSCNTR", CR_DEFAULT, VPT_STRETCH); + x += 8; + } + + V_DrawNamePatch(x, y+7, 0, "M_LSRGHT", CR_DEFAULT, VPT_STRETCH); +} + +// +// User wants to load this game +// + +void M_LoadSelect(int choice) +{ + // CPhipps - Modified so savegame filename is worked out only internal + // to g_game.c, this only passes the slot. + + G_LoadGame(choice, false); // killough 3/16/98, 5/15/98: add slot, cmd + + M_ClearMenus (); +} + +// +// killough 5/15/98: add forced loadgames +// + +static void M_VerifyForcedLoadGame(int ch) +{ + if (ch=='y') + G_ForcedLoadGame(); + free((char*)messageString); // free the message strdup()'ed below + M_ClearMenus(); +} + +void M_ForcedLoadGame(const char *msg) +{ + M_StartMessage(strdup(msg), M_VerifyForcedLoadGame, true); // free()'d above +} + +// +// Selected from DOOM menu +// + +void M_LoadGame (int choice) +{ + /* killough 5/26/98: exclude during demo recordings + * cph - unless a new demo */ + if (demorecording && (compatibility_level < prboom_2_compatibility)) + { + M_StartMessage("you can't load a game\n" + "while recording an old demo!\n\n"PRESSKEY, + NULL, false); // killough 5/26/98: not externalized + return; + } + + M_SetupNextMenu(&LoadDef); + M_ReadSaveStrings(); +} + +///////////////////////////// +// +// SAVE GAME MENU +// + +// The definitions of the Save Game screen + +menuitem_t SaveMenu[]= +{ + {1,"", M_SaveSelect,'1'}, + {1,"", M_SaveSelect,'2'}, + {1,"", M_SaveSelect,'3'}, + {1,"", M_SaveSelect,'4'}, + {1,"", M_SaveSelect,'5'}, + {1,"", M_SaveSelect,'6'}, + {1,"", M_SaveSelect,'7'}, //jff 3/15/98 extend number of slots + {1,"", M_SaveSelect,'8'}, +}; + +menu_t SaveDef = +{ + load_end, // same number of slots as the Load Game screen + &MainDef, + SaveMenu, + M_DrawSave, + 80,34, //jff 3/15/98 move menu up + 0 +}; + +// +// M_ReadSaveStrings +// read the strings from the savegame files +// +void M_ReadSaveStrings(void) +{ + int i; + + for (i = 0 ; i < load_end ; i++) { + char name[PATH_MAX+1]; // killough 3/22/98 + FILE *fp; // killough 11/98: change to use stdio + + /* killough 3/22/98 + * cph - add not-demoplayback parameter */ + G_SaveGameName(name,sizeof(name),i,false); + fp = fopen(name,"rb"); + if (!fp) { // Ty 03/27/98 - externalized: + strcpy(&savegamestrings[i][0],s_EMPTYSTRING); + LoadMenue[i].status = 0; + continue; + } + fread(&savegamestrings[i], SAVESTRINGSIZE, 1, fp); + fclose(fp); + LoadMenue[i].status = 1; + } +} + +// +// M_SaveGame & Cie. +// +void M_DrawSave(void) +{ + int i; + + //jff 3/15/98 use symbolic load position + // CPhipps - patch drawing updated + V_DrawNamePatch(72, LOADGRAPHIC_Y, 0, "M_SAVEG", CR_DEFAULT, VPT_STRETCH); + for (i = 0 ; i < load_end ; i++) + { + M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); + M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]); + } + + if (saveStringEnter) + { + i = M_StringWidth(savegamestrings[saveSlot]); + M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*saveSlot,"_"); + } +} + +// +// M_Responder calls this when user is finished +// +static void M_DoSave(int slot) +{ + G_SaveGame (slot,savegamestrings[slot]); + M_ClearMenus (); + + // PICK QUICKSAVE SLOT YET? + if (quickSaveSlot == -2) + quickSaveSlot = slot; +} + +// +// User wants to save. Start string input for M_Responder +// +void M_SaveSelect(int choice) +{ + // we are going to be intercepting all chars + saveStringEnter = 1; + + saveSlot = choice; + strcpy(saveOldString,savegamestrings[choice]); + if (!strcmp(savegamestrings[choice],s_EMPTYSTRING)) // Ty 03/27/98 - externalized + savegamestrings[choice][0] = 0; + saveCharIndex = strlen(savegamestrings[choice]); +} + +// +// Selected from DOOM menu +// +void M_SaveGame (int choice) +{ + // killough 10/6/98: allow savegames during single-player demo playback + if (!usergame && (!demoplayback || netgame)) + { + M_StartMessage(s_SAVEDEAD,NULL,false); // Ty 03/27/98 - externalized + return; + } + + if (gamestate != GS_LEVEL) + return; + + M_SetupNextMenu(&SaveDef); + M_ReadSaveStrings(); +} + +///////////////////////////// +// +// OPTIONS MENU +// + +// numerical values for the Options menu items + +enum +{ + general, // killough 10/98 + // killough 4/6/98: move setup to be a sub-menu of OPTIONs + setup, // phares 3/21/98 + endgame, + messages, + /* detail, obsolete -- killough */ + scrnsize, + option_empty1, + mousesens, + /* option_empty2, submenu now -- killough */ + soundvol, + opt_end +} options_e; + +// The definitions of the Options menu + +menuitem_t OptionsMenu[]= +{ + // killough 4/6/98: move setup to be a sub-menu of OPTIONs + {1,"M_GENERL", M_General, 'g'}, // killough 10/98 + {1,"M_SETUP", M_Setup, 's'}, // phares 3/21/98 + {1,"M_ENDGAM", M_EndGame,'e'}, + {1,"M_MESSG", M_ChangeMessages,'m'}, + /* {1,"M_DETAIL", M_ChangeDetail,'g'}, unused -- killough */ + {2,"M_SCRNSZ", M_SizeDisplay,'s'}, + {-1,"",0}, + {1,"M_MSENS", M_ChangeSensitivity,'m'}, + /* {-1,"",0}, replaced with submenu -- killough */ + {1,"M_SVOL", M_Sound,'s'} +}; + +menu_t OptionsDef = +{ + opt_end, + &MainDef, + OptionsMenu, + M_DrawOptions, + 60,37, + 0 +}; + +// +// M_Options +// +char detailNames[2][9] = {"M_GDHIGH","M_GDLOW"}; +char msgNames[2][9] = {"M_MSGOFF","M_MSGON"}; + + +void M_DrawOptions(void) +{ + // CPhipps - patch drawing updated + // proff/nicolas 09/20/98 -- changed for hi-res + V_DrawNamePatch(108, 15, 0, "M_OPTTTL", CR_DEFAULT, VPT_STRETCH); + + V_DrawNamePatch(OptionsDef.x + 120, OptionsDef.y+LINEHEIGHT*messages, 0, + msgNames[showMessages], CR_DEFAULT, VPT_STRETCH); + + M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1), + 9,screenSize); +} + +void M_Options(int choice) +{ + M_SetupNextMenu(&OptionsDef); +} + +///////////////////////////// +// +// M_QuitDOOM +// +int quitsounds[8] = +{ + sfx_pldeth, + sfx_dmpain, + sfx_popain, + sfx_slop, + sfx_telept, + sfx_posit1, + sfx_posit3, + sfx_sgtatk +}; + +int quitsounds2[8] = +{ + sfx_vilact, + sfx_getpow, + sfx_boscub, + sfx_slop, + sfx_skeswg, + sfx_kntdth, + sfx_bspact, + sfx_sgtatk +}; + +static void M_QuitResponse(int ch) +{ + if (ch != 'y') + return; + if ((!netgame || demoplayback) // killough 12/98 + && !nosfxparm && snd_card) // avoid delay if no sound card + { + int i; + + if (gamemode == commercial) + S_StartSound(NULL,quitsounds2[(gametic>>2)&7]); + else + S_StartSound(NULL,quitsounds[(gametic>>2)&7]); + + // wait till all sounds stopped or 3 seconds are over + i = 30; + while (i>0) { + I_uSleep(100000); // CPhipps - don't thrash cpu in this loop + if (!I_AnySoundStillPlaying()) + break; + i--; + } + } + exit(0); // killough +} + +void M_QuitDOOM(int choice) +{ + static char endstring[160]; + + // We pick index 0 which is language sensitive, + // or one at random, between 1 and maximum number. + // Ty 03/27/98 - externalized DOSY as a string s_DOSY that's in the sprintf + if (language != english) + sprintf(endstring,"%s\n\n%s",s_DOSY, endmsg[0] ); + else // killough 1/18/98: fix endgame message calculation: + sprintf(endstring,"%s\n\n%s", endmsg[gametic%(NUM_QUITMESSAGES-1)+1], s_DOSY); + + M_StartMessage(endstring,M_QuitResponse,true); +} + +///////////////////////////// +// +// SOUND VOLUME MENU +// + +// numerical values for the Sound Volume menu items +// The 'empty' slots are where the sliding scales appear. + +enum +{ + sfx_vol, + sfx_empty1, + music_vol, + sfx_empty2, + sound_end +} sound_e; + +// The definitions of the Sound Volume menu + +menuitem_t SoundMenu[]= +{ + {2,"M_SFXVOL",M_SfxVol,'s'}, + {-1,"",0}, + {2,"M_MUSVOL",M_MusicVol,'m'}, + {-1,"",0} +}; + +menu_t SoundDef = +{ + sound_end, + &OptionsDef, + SoundMenu, + M_DrawSound, + 80,64, + 0 +}; + +// +// Change Sfx & Music volumes +// + +void M_DrawSound(void) +{ + // CPhipps - patch drawing updated + V_DrawNamePatch(60, 38, 0, "M_SVOL", CR_DEFAULT, VPT_STRETCH); + + M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1),16,snd_SfxVolume); + + M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1),16,snd_MusicVolume); +} + +void M_Sound(int choice) +{ + M_SetupNextMenu(&SoundDef); +} + +void M_SfxVol(int choice) +{ + switch(choice) + { + case 0: + if (snd_SfxVolume) + snd_SfxVolume--; + break; + case 1: + if (snd_SfxVolume < 15) + snd_SfxVolume++; + break; + } + + S_SetSfxVolume(snd_SfxVolume /* *8 */); +} + +void M_MusicVol(int choice) +{ + switch(choice) + { + case 0: + if (snd_MusicVolume) + snd_MusicVolume--; + break; + case 1: + if (snd_MusicVolume < 15) + snd_MusicVolume++; + break; + } + + S_SetMusicVolume(snd_MusicVolume /* *8 */); +} + +///////////////////////////// +// +// MOUSE SENSITIVITY MENU -- killough +// + +// numerical values for the Mouse Sensitivity menu items +// The 'empty' slots are where the sliding scales appear. + +enum +{ + mouse_horiz, + mouse_empty1, + mouse_vert, + mouse_empty2, + mouse_end +} mouse_e; + +// The definitions of the Mouse Sensitivity menu + +menuitem_t MouseMenu[]= +{ + {2,"M_HORSEN",M_MouseHoriz,'h'}, + {-1,"",0}, + {2,"M_VERSEN",M_MouseVert,'v'}, + {-1,"",0} +}; + +menu_t MouseDef = +{ + mouse_end, + &OptionsDef, + MouseMenu, + M_DrawMouse, + 60,64, + 0 +}; + + +// I'm using a scale of 100 since I don't know what's normal -- killough. + +#define MOUSE_SENS_MAX 100 + +// +// Change Mouse Sensitivities -- killough +// + +void M_DrawMouse(void) +{ + int mhmx,mvmx; /* jff 4/3/98 clamp drawn position 99max mead */ + + // CPhipps - patch drawing updated + V_DrawNamePatch(60, 38, 0, "M_MSENS", CR_DEFAULT, VPT_STRETCH); + + //jff 4/3/98 clamp horizontal sensitivity display + mhmx = mouseSensitivity_horiz>99? 99 : mouseSensitivity_horiz; /*mead*/ + M_DrawThermo(MouseDef.x,MouseDef.y+LINEHEIGHT*(mouse_horiz+1),100,mhmx); + //jff 4/3/98 clamp vertical sensitivity display + mvmx = mouseSensitivity_vert>99? 99 : mouseSensitivity_vert; /*mead*/ + M_DrawThermo(MouseDef.x,MouseDef.y+LINEHEIGHT*(mouse_vert+1),100,mvmx); +} + +void M_ChangeSensitivity(int choice) +{ + M_SetupNextMenu(&MouseDef); // killough + + // switch(choice) + // { + // case 0: + // if (mouseSensitivity) + // mouseSensitivity--; + // break; + // case 1: + // if (mouseSensitivity < 9) + // mouseSensitivity++; + // break; + // } +} + +void M_MouseHoriz(int choice) +{ + M_Mouse(choice, &mouseSensitivity_horiz); +} + +void M_MouseVert(int choice) +{ + M_Mouse(choice, &mouseSensitivity_vert); +} + +void M_Mouse(int choice, int *sens) +{ + switch(choice) + { + case 0: + if (*sens) + --*sens; + break; + case 1: + if (*sens < 99) + ++*sens; /*mead*/ + break; + } +} + +///////////////////////////// +// +// M_QuickSave +// + +char tempstring[80]; + +static void M_QuickSaveResponse(int ch) +{ + if (ch == 'y') { + M_DoSave(quickSaveSlot); + S_StartSound(NULL,sfx_swtchx); + } +} + +void M_QuickSave(void) +{ + if (!usergame && (!demoplayback || netgame)) { /* killough 10/98 */ + S_StartSound(NULL,sfx_oof); + return; + } + + if (gamestate != GS_LEVEL) + return; + + if (quickSaveSlot < 0) { + M_StartControlPanel(); + M_ReadSaveStrings(); + M_SetupNextMenu(&SaveDef); + quickSaveSlot = -2; // means to pick a slot now + return; + } + sprintf(tempstring,s_QSPROMPT,savegamestrings[quickSaveSlot]); // Ty 03/27/98 - externalized + M_StartMessage(tempstring,M_QuickSaveResponse,true); +} + +///////////////////////////// +// +// M_QuickLoad +// + +static void M_QuickLoadResponse(int ch) +{ + if (ch == 'y') { + M_LoadSelect(quickSaveSlot); + S_StartSound(NULL,sfx_swtchx); + } +} + +void M_QuickLoad(void) +{ + // cph - removed restriction against quickload in a netgame + + if (demorecording) { // killough 5/26/98: exclude during demo recordings + M_StartMessage("you can't quickload\n" + "while recording a demo!\n\n"PRESSKEY, + NULL, false); // killough 5/26/98: not externalized + return; + } + + if (quickSaveSlot < 0) { + M_StartMessage(s_QSAVESPOT,NULL,false); // Ty 03/27/98 - externalized + return; + } + sprintf(tempstring,s_QLPROMPT,savegamestrings[quickSaveSlot]); // Ty 03/27/98 - externalized + M_StartMessage(tempstring,M_QuickLoadResponse,true); +} + +///////////////////////////// +// +// M_EndGame +// + +static void M_EndGameResponse(int ch) +{ + if (ch != 'y') + return; + + // killough 5/26/98: make endgame quit if recording or playing back demo + if (demorecording || singledemo) + G_CheckDemoStatus(); + + currentMenu->lastOn = itemOn; + M_ClearMenus (); + D_StartTitle (); +} + +void M_EndGame(int choice) +{ + if (netgame) + { + M_StartMessage(s_NETEND,NULL,false); // Ty 03/27/98 - externalized + return; + } + M_StartMessage(s_ENDGAME,M_EndGameResponse,true); // Ty 03/27/98 - externalized +} + +///////////////////////////// +// +// Toggle messages on/off +// + +void M_ChangeMessages(int choice) +{ + // warning: unused parameter `int choice' + choice = 0; + showMessages = 1 - showMessages; + + if (!showMessages) + players[consoleplayer].message = s_MSGOFF; // Ty 03/27/98 - externalized + else + players[consoleplayer].message = s_MSGON ; // Ty 03/27/98 - externalized + + message_dontfuckwithme = true; +} + +///////////////////////////// +// +// CHANGE DISPLAY SIZE +// +// jff 2/23/98 restored to pre-HUD state +// hud_active controlled soley by F5=key_detail (key_hud) +// hud_displayed is toggled by + or = in fullscreen +// hud_displayed is cleared by - + +void M_SizeDisplay(int choice) +{ + switch(choice) { + case 0: + if (screenSize > 0) { + screenblocks--; + screenSize--; + hud_displayed = 0; + } + break; + case 1: + if (screenSize < 8) { + screenblocks++; + screenSize++; + } + else + hud_displayed = !hud_displayed; + break; + } + R_SetViewSize (screenblocks /*, detailLevel obsolete -- killough */); +} + +// +// End of Original Menus +// +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// +// SETUP MENU (phares) +// +// We've added a set of Setup Screens from which you can configure a number +// of variables w/o having to restart the game. There are 7 screens: +// +// Key Bindings +// Weapons +// Status Bar / HUD +// Automap +// Enemies +// Messages +// Chat Strings +// +// killough 10/98: added Compatibility and General menus +// + +///////////////////////////// +// +// booleans for setup screens +// these tell you what state the setup screens are in, and whether any of +// the overlay screens (automap colors, reset button message) should be +// displayed + +boolean setup_active = false; // in one of the setup screens +boolean set_keybnd_active = false; // in key binding setup screens +boolean set_weapon_active = false; // in weapons setup screen +boolean set_status_active = false; // in status bar/hud setup screen +boolean set_auto_active = false; // in automap setup screen +boolean set_enemy_active = false; // in enemies setup screen +boolean set_mess_active = false; // in messages setup screen +boolean set_chat_active = false; // in chat string setup screen +boolean setup_select = false; // changing an item +boolean setup_gather = false; // gathering keys for value +boolean colorbox_active = false; // color palette being shown +boolean default_verify = false; // verify reset defaults decision +boolean set_general_active = false; +boolean set_compat_active = false; + +///////////////////////////// +// +// set_menu_itemon is an index that starts at zero, and tells you which +// item on the current screen the cursor is sitting on. +// +// current_setup_menu is a pointer to the current setup menu table. + +static int set_menu_itemon; // which setup item is selected? // phares 3/98 +setup_menu_t* current_setup_menu; // points to current setup menu table + +///////////////////////////// +// +// The menu_buffer is used to construct strings for display on the screen. + +static char menu_buffer[64]; + +///////////////////////////// +// +// The setup_e enum is used to provide a unique number for each group of Setup +// Screens. + +enum +{ + set_compat, + set_key_bindings, + set_weapons, + set_statbar, + set_automap, + set_enemy, + set_messages, + set_chatstrings, + set_setup_end +} setup_e; + +int setup_screen; // the current setup screen. takes values from setup_e + +///////////////////////////// +// +// SetupMenu is the definition of what the main Setup Screen should look +// like. Each entry shows that the cursor can land on each item (1), the +// built-in graphic lump (i.e. "M_KEYBND") that should be displayed, +// the program which takes over when an item is selected, and the hotkey +// associated with the item. + +menuitem_t SetupMenu[]= +{ + {1,"M_COMPAT",M_Compat, 'p'}, + {1,"M_KEYBND",M_KeyBindings,'k'}, + {1,"M_WEAP" ,M_Weapons, 'w'}, + {1,"M_STAT" ,M_StatusBar, 's'}, + {1,"M_AUTO" ,M_Automap, 'a'}, + {1,"M_ENEM" ,M_Enemy, 'e'}, + {1,"M_MESS" ,M_Messages, 'm'}, + {1,"M_CHAT" ,M_ChatStrings,'c'}, +}; + +///////////////////////////// +// +// M_DoNothing does just that: nothing. Just a placeholder. + +static void M_DoNothing(int choice) +{ +} + +///////////////////////////// +// +// Items needed to satisfy the 'Big Font' menu structures: +// +// the generic_setup_e enum mimics the 'Big Font' menu structures, but +// means nothing to the Setup Menus. + +enum +{ + generic_setupempty1, + generic_setup_end +} generic_setup_e; + +// Generic_Setup is a do-nothing definition that the mainstream Menu code +// can understand, while the Setup Menu code is working. Another placeholder. + +menuitem_t Generic_Setup[] = +{ + {1,"",M_DoNothing,0} +}; + +///////////////////////////// +// +// SetupDef is the menu definition that the mainstream Menu code understands. +// This is used by M_Setup (below) to define what is drawn and what is done +// with the main Setup screen. + +menu_t SetupDef = +{ + set_setup_end, // number of Setup Menu items (Key Bindings, etc.) + &OptionsDef, // menu to return to when BACKSPACE is hit on this menu + SetupMenu, // definition of items to show on the Setup Screen + M_DrawSetup, // program that draws the Setup Screen + 59,37, // x,y position of the skull (modified when the skull is + // drawn). The skull is parked on the upper-left corner + // of the Setup screens, since it isn't needed as a cursor + 0 // last item the user was on for this menu +}; + +///////////////////////////// +// +// Here are the definitions of the individual Setup Menu screens. They +// follow the format of the 'Big Font' menu structures. See the comments +// for SetupDef (above) to help understand what each of these says. + +menu_t KeybndDef = +{ + generic_setup_end, + &SetupDef, + Generic_Setup, + M_DrawKeybnd, + 34,5, // skull drawn here + 0 +}; + +menu_t WeaponDef = +{ + generic_setup_end, + &SetupDef, + Generic_Setup, + M_DrawWeapons, + 34,5, // skull drawn here + 0 +}; + +menu_t StatusHUDDef = +{ + generic_setup_end, + &SetupDef, + Generic_Setup, + M_DrawStatusHUD, + 34,5, // skull drawn here + 0 +}; + +menu_t AutoMapDef = +{ + generic_setup_end, + &SetupDef, + Generic_Setup, + M_DrawAutoMap, + 34,5, // skull drawn here + 0 +}; + +menu_t EnemyDef = // phares 4/08/98 +{ + generic_setup_end, + &SetupDef, + Generic_Setup, + M_DrawEnemy, + 34,5, // skull drawn here + 0 +}; + +menu_t MessageDef = // phares 4/08/98 +{ + generic_setup_end, + &SetupDef, + Generic_Setup, + M_DrawMessages, + 34,5, // skull drawn here + 0 +}; + +menu_t ChatStrDef = // phares 4/10/98 +{ + generic_setup_end, + &SetupDef, + Generic_Setup, + M_DrawChatStrings, + 34,5, // skull drawn here + 0 +}; + +menu_t GeneralDef = // killough 10/98 +{ + generic_setup_end, + &OptionsDef, + Generic_Setup, + M_DrawGeneral, + 34,5, // skull drawn here + 0 +}; + +menu_t CompatDef = // killough 10/98 +{ + generic_setup_end, + &SetupDef, + Generic_Setup, + M_DrawCompat, + 34,5, // skull drawn here + 0 +}; + +///////////////////////////// +// +// Draws the Title for the main Setup screen + +void M_DrawSetup(void) +{ + // CPhipps - patch drawing updated + V_DrawNamePatch(124, 15, 0, "M_SETUP", CR_DEFAULT, VPT_STRETCH); +} + +///////////////////////////// +// +// Uses the SetupDef structure to draw the menu items for the main +// Setup screen + +void M_Setup(int choice) +{ + M_SetupNextMenu(&SetupDef); +} + +///////////////////////////// +// +// Data that's used by the Setup screen code +// +// Establish the message colors to be used + +#define CR_TITLE CR_GOLD +#define CR_SET CR_GREEN +#define CR_ITEM CR_RED +#define CR_HILITE CR_ORANGE +#define CR_SELECT CR_GRAY + +// Data used by the Automap color selection code + +#define CHIP_SIZE 7 // size of color block for colored items + +#define COLORPALXORIG ((320 - 16*(CHIP_SIZE+1))/2) +#define COLORPALYORIG ((200 - 16*(CHIP_SIZE+1))/2) + +#define PAL_BLACK 0 +#define PAL_WHITE 4 + +// Data used by the Chat String editing code + +#define CHAT_STRING_BFR_SIZE 128 + +// chat strings must fit in this screen space +// killough 10/98: reduced, for more general uses +#define MAXCHATWIDTH 272 + +int chat_index; +char* chat_string_buffer; // points to new chat strings while editing + +///////////////////////////// +// +// phares 4/17/98: +// Added 'Reset to Defaults' Button to Setup Menu screens +// This is a small button that sits in the upper-right-hand corner of +// the first screen for each group. It blinks when selected, thus the +// two patches, which it toggles back and forth. + +char ResetButtonName[2][8] = {"M_BUTT1","M_BUTT2"}; + +///////////////////////////// +// +// phares 4/18/98: +// Consolidate Item drawing code +// +// M_DrawItem draws the description of the provided item (the left-hand +// part). A different color is used for the text depending on whether the +// item is selected or not, or whether it's about to change. + +// CPhipps - static, hanging else removed, const parameter +static void M_DrawItem(const setup_menu_t* s) +{ + int x = s->m_x; + int y = s->m_y; + int flags = s->m_flags; + if (flags & S_RESET) + + // This item is the reset button + // Draw the 'off' version if this isn't the current menu item + // Draw the blinking version in tune with the blinking skull otherwise + + // proff/nicolas 09/20/98 -- changed for hi-res + // CPhipps - Patch drawing updated, reformatted + + V_DrawNamePatch(x, y, 0, ResetButtonName[(flags & (S_HILITE|S_SELECT)) ? whichSkull : 0], + CR_DEFAULT, VPT_STRETCH); + + else { // Draw the item string + char *p, *t; + int w = 0; + int color = + flags & S_SELECT ? CR_SELECT : + flags & S_HILITE ? CR_HILITE : + flags & (S_TITLE|S_NEXT|S_PREV) ? CR_TITLE : CR_ITEM; // killough 10/98 + + /* killough 10/98: + * Enhance to support multiline text separated by newlines. + * This supports multiline items on horizontally-crowded menus. + */ + + for (p = t = strdup(s->m_text); (p = strtok(p,"\n")); y += 8, p = NULL) + { /* killough 10/98: support left-justification: */ + strcpy(menu_buffer,p); + if (!(flags & S_LEFTJUST)) + w = M_GetPixelWidth(menu_buffer) + 4; + M_DrawMenuString(x - w, y ,color); + } + free(t); + } +} + +// If a number item is being changed, allow up to N keystrokes to 'gather' +// the value. Gather_count tells you how many you have so far. The legality +// of what is gathered is determined by the low/high settings for the item. + +#define MAXGATHER 5 +int gather_count; +char gather_buffer[MAXGATHER+1]; // killough 10/98: make input character-based + +///////////////////////////// +// +// phares 4/18/98: +// Consolidate Item Setting drawing code +// +// M_DrawSetting draws the setting of the provided item (the right-hand +// part. It determines the text color based on whether the item is +// selected or being changed. Then, depending on the type of item, it +// displays the appropriate setting value: yes/no, a key binding, a number, +// a paint chip, etc. + +static void M_DrawSetting(const setup_menu_t* s) +{ + int x = s->m_x, y = s->m_y, flags = s->m_flags, color; + + // Determine color of the text. This may or may not be used later, + // depending on whether the item is a text string or not. + + color = flags & S_SELECT ? CR_SELECT : flags & S_HILITE ? CR_HILITE : CR_SET; + + // Is the item a YES/NO item? + + if (flags & S_YESNO) { + strcpy(menu_buffer,*s->var.def->location.pi ? "YES" : "NO"); + M_DrawMenuString(x,y,color); + return; + } + + // Is the item a simple number? + + if (flags & S_NUM) { + // killough 10/98: We must draw differently for items being gathered. + if (flags & (S_HILITE|S_SELECT) && setup_gather) { + gather_buffer[gather_count] = 0; + strcpy(menu_buffer, gather_buffer); + } + else + sprintf(menu_buffer,"%d",*s->var.def->location.pi); + M_DrawMenuString(x,y,color); + return; + } + + // Is the item a key binding? + + if (flags & S_KEY) { // Key Binding + int *key = s->var.m_key; + + // Draw the key bound to the action + + if (key) { + M_GetKeyString(*key,0); // string to display + if (key == &key_use) { + // For the 'use' key, you have to build the string + + if (s->m_mouse) + sprintf(menu_buffer+strlen(menu_buffer), "/DBL-CLK MB%d",*s->m_mouse+1); + if (s->m_joy) + sprintf(menu_buffer+strlen(menu_buffer), "/JSB%d",*s->m_joy+1); + } + else if (key == &key_up || key == &key_speed || + key == &key_fire || key == &key_strafe) + { + if (s->m_mouse) + sprintf(menu_buffer+strlen(menu_buffer), "/MB%d", + *s->m_mouse+1); + if (s->m_joy) + sprintf(menu_buffer+strlen(menu_buffer), "/JSB%d", + *s->m_joy+1); + } + M_DrawMenuString(x,y,color); + } + return; + } + + // Is the item a weapon number? + // OR, Is the item a colored text string from the Automap? + // + // killough 10/98: removed special code, since the rest of the engine + // already takes care of it, and this code prevented the user from setting + // their overall weapons preferences while playing Doom 1. + // + // killough 11/98: consolidated weapons code with color range code + + if (flags & (S_WEAP|S_CRITEM)) // weapon number or color range + { + sprintf(menu_buffer,"%d", *s->var.def->location.pi); + M_DrawMenuString(x,y, flags & S_CRITEM ? *s->var.def->location.pi : color); + return; + } + + // Is the item a paint chip? + + if (flags & S_COLOR) // Automap paint chip + { + int ch; + + ch = *s->var.def->location.pi; + // proff 12/6/98: Drawing of colorchips completly changed for hi-res, it now uses a patch + // draw the paint chip + V_FillRect(0, x*SCREENWIDTH/320, (y-1)*SCREENHEIGHT/200, + 8*SCREENWIDTH/320, 8*SCREENHEIGHT/200, + PAL_BLACK); + V_FillRect(0, (x+1)*SCREENWIDTH/320, y*SCREENHEIGHT/200, + 6*SCREENWIDTH/320, 6*SCREENHEIGHT/200, + (byte)ch); + + if (!ch) // don't show this item in automap mode + V_DrawNamePatch(x+1,y,0,"M_PALNO", CR_DEFAULT, VPT_STRETCH); + return; + } + + // Is the item a chat string? + // killough 10/98: or a filename? + + if (flags & S_STRING) { + /* cph - cast to char* as it's really a Z_Strdup'd string (see m_misc.h) */ + char *text = (char*)*s->var.def->location.ppsz; + + // Are we editing this string? If so, display a cursor under + // the correct character. + + if (setup_select && (s->m_flags & (S_HILITE|S_SELECT))) { + int cursor_start, char_width; + char c[2]; + + // If the string is too wide for the screen, trim it back, + // one char at a time until it fits. This should only occur + // while you're editing the string. + + while (M_GetPixelWidth(text) >= MAXCHATWIDTH) { + int len = strlen(text); + text[--len] = 0; + if (chat_index > len) + chat_index--; + } + + // Find the distance from the beginning of the string to + // where the cursor should be drawn, plus the width of + // the char the cursor is under.. + + *c = text[chat_index]; // hold temporarily + c[1] = 0; + char_width = M_GetPixelWidth(c); + if (char_width == 1) + char_width = 7; // default for end of line + text[chat_index] = 0; // NULL to get cursor position + cursor_start = M_GetPixelWidth(text); + text[chat_index] = *c; // replace stored char + + // Now draw the cursor + // proff 12/6/98: Drawing of cursor changed for hi-res + V_FillRect(0, ((x+cursor_start-1)*SCREENWIDTH)/320, (y*SCREENHEIGHT)/200, + (char_width*SCREENWIDTH)/320, 9*SCREENHEIGHT/200, PAL_WHITE); + } + + // Draw the setting for the item + + strcpy(menu_buffer,text); + M_DrawMenuString(x,y,color); + return; + } + + // Is the item a selection of choices? + + if (flags & S_CHOICE) { + if (s->var.def->type == def_int) { + if (s->selectstrings == NULL) { + sprintf(menu_buffer,"%d",*s->var.def->location.pi); + } else { + strcpy(menu_buffer,s->selectstrings[*s->var.def->location.pi]); + } + } + + if (s->var.def->type == def_str) { + sprintf(menu_buffer,"%s", *s->var.def->location.ppsz); + } + + M_DrawMenuString(x,y,color); + return; + } +} + +///////////////////////////// +// +// M_DrawScreenItems takes the data for each menu item and gives it to +// the drawing routines above. + +// CPhipps - static, const parameter, formatting +static void M_DrawScreenItems(const setup_menu_t* src) +{ + if (print_warning_about_changes > 0) { /* killough 8/15/98: print warning */ + if (warning_about_changes & S_BADVAL) { + strcpy(menu_buffer, "Value out of Range"); + M_DrawMenuString(100,176,CR_RED); + } else if (warning_about_changes & S_PRGWARN) { + strcpy(menu_buffer, "Warning: Program must be restarted to see changes"); + M_DrawMenuString(3, 176, CR_RED); + } else if (warning_about_changes & S_BADVID) { + strcpy(menu_buffer, "Video mode not supported"); + M_DrawMenuString(80,176,CR_RED); + } else { + strcpy(menu_buffer, "Warning: Changes are pending until next game"); + M_DrawMenuString(18,184,CR_RED); + } + } + + while (!(src->m_flags & S_END)) { + + // See if we're to draw the item description (left-hand part) + + if (src->m_flags & S_SHOWDESC) + M_DrawItem(src); + + // See if we're to draw the setting (right-hand part) + + if (src->m_flags & S_SHOWSET) + M_DrawSetting(src); + src++; + } +} + +///////////////////////////// +// +// Data used to draw the "are you sure?" dialogue box when resetting +// to defaults. + +#define VERIFYBOXXORG 66 +#define VERIFYBOXYORG 88 +#define PAL_GRAY1 91 +#define PAL_GRAY2 98 +#define PAL_GRAY3 105 + +// And the routine to draw it. + +static void M_DrawDefVerify(void) +{ + // proff 12/6/98: Drawing of verify box changed for hi-res, it now uses a patch + V_DrawNamePatch(VERIFYBOXXORG,VERIFYBOXYORG,0,"M_VBOX",CR_DEFAULT,VPT_STRETCH); + // The blinking messages is keyed off of the blinking of the + // cursor skull. + + if (whichSkull) { // blink the text + strcpy(menu_buffer,"Reset to defaults? (Y or N)"); + M_DrawMenuString(VERIFYBOXXORG+8,VERIFYBOXYORG+8,CR_RED); + } +} + + +///////////////////////////// +// +// phares 4/18/98: +// M_DrawInstructions writes the instruction text just below the screen title +// +// cph 2006/08/06 - go back to the Boom version, and then clean up by using +// M_DrawStringCentered (much better than all those magic 'x' valies!) + +static void M_DrawInstructions(void) +{ + int flags = current_setup_menu[set_menu_itemon].m_flags; + + // There are different instruction messages depending on whether you + // are changing an item or just sitting on it. + + if (setup_select) { + switch (flags & (S_KEY | S_YESNO | S_WEAP | S_NUM | S_COLOR | S_CRITEM | S_CHAT | S_RESET | S_FILE | S_CHOICE)) { + case S_KEY: + // See if a joystick or mouse button setting is allowed for + // this item. + if (current_setup_menu[set_menu_itemon].m_mouse || current_setup_menu[set_menu_itemon].m_joy) + M_DrawStringCentered(160, 20, CR_SELECT, "Press key or button for this action"); + else + M_DrawStringCentered(160, 20, CR_SELECT, "Press key for this action"); + break; + + case S_YESNO: + M_DrawStringCentered(160, 20, CR_SELECT, "Press ENTER key to toggle"); + break; + case S_WEAP: + M_DrawStringCentered(160, 20, CR_SELECT, "Enter weapon number"); + break; + case S_NUM: + M_DrawStringCentered(160, 20, CR_SELECT, "Enter value. Press ENTER when finished."); + break; + case S_COLOR: + M_DrawStringCentered(160, 20, CR_SELECT, "Select color and press enter"); + break; + case S_CRITEM: + M_DrawStringCentered(160, 20, CR_SELECT, "Enter value"); + break; + case S_CHAT: + M_DrawStringCentered(160, 20, CR_SELECT, "Type/edit chat string and Press ENTER"); + break; + case S_FILE: + M_DrawStringCentered(160, 20, CR_SELECT, "Type/edit filename and Press ENTER"); + break; + case S_CHOICE: + M_DrawStringCentered(160, 20, CR_SELECT, "Press left or right to choose"); + break; + case S_RESET: + break; +#ifdef SIMPLECHECKS + default: + lprintf(LO_WARN,"Unrecognised menu item type %d", flags); +#endif + } + } else { + if (flags & S_RESET) + M_DrawStringCentered(160, 20, CR_HILITE, "Press ENTER key to reset to defaults"); + else + M_DrawStringCentered(160, 20, CR_HILITE, "Press Enter to Change"); + } +} + + +///////////////////////////// +// +// The Key Binding Screen tables. + +#define KB_X 160 +#define KB_PREV 57 +#define KB_NEXT 310 +#define KB_Y 31 + +// phares 4/16/98: +// X,Y position of reset button. This is the same for every screen, and is +// only defined once here. + +#define X_BUTTON 301 +#define Y_BUTTON 3 + +// Definitions of the (in this case) four key binding screens. + +setup_menu_t keys_settings1[]; +setup_menu_t keys_settings2[]; +setup_menu_t keys_settings3[]; +setup_menu_t keys_settings4[]; + +// The table which gets you from one screen table to the next. + +setup_menu_t* keys_settings[] = +{ + keys_settings1, + keys_settings2, + keys_settings3, + keys_settings4, + NULL +}; + +int mult_screens_index; // the index of the current screen in a set + +// Here's an example from this first screen, with explanations. +// +// { +// "STRAFE", // The description of the item ('strafe' key) +// S_KEY, // This is a key binding item +// m_scrn, // It belongs to the m_scrn group. Its key cannot be +// // bound to two items in this group. +// KB_X, // The X offset of the start of the right-hand side +// KB_Y+ 8*8, // The Y offset of the start of the right-hand side. +// // Always given in multiples off a baseline. +// &key_strafe, // The variable that holds the key value bound to this +// OR a string that holds the config variable name. +// OR a pointer to another setup_menu +// &mousebstrafe, // The variable that holds the mouse button bound to + // this. If zero, no mouse button can be bound here. +// &joybstrafe, // The variable that holds the joystick button bound to + // this. If zero, no mouse button can be bound here. +// } + +// The first Key Binding screen table. +// Note that the Y values are ascending. If you need to add something to +// this table, (well, this one's not a good example, because it's full) +// you need to make sure the Y values still make sense so everything gets +// displayed. +// +// Note also that the first screen of each set has a line for the reset +// button. If there is more than one screen in a set, the others don't get +// the reset button. +// +// Note also that this screen has a "NEXT ->" line. This acts like an +// item, in that 'activating' it moves you along to the next screen. If +// there's a "<- PREV" item on a screen, it behaves similarly, moving you +// to the previous screen. If you leave these off, you can't move from +// screen to screen. + +setup_menu_t keys_settings1[] = // Key Binding screen strings +{ + {"MOVEMENT" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y}, + {"FORWARD" ,S_KEY ,m_scrn,KB_X,KB_Y+1*8,{&key_up},&mousebforward}, + {"BACKWARD" ,S_KEY ,m_scrn,KB_X,KB_Y+2*8,{&key_down}}, + {"TURN LEFT" ,S_KEY ,m_scrn,KB_X,KB_Y+3*8,{&key_left}}, + {"TURN RIGHT" ,S_KEY ,m_scrn,KB_X,KB_Y+4*8,{&key_right}}, + {"RUN" ,S_KEY ,m_scrn,KB_X,KB_Y+5*8,{&key_speed},0,&joybspeed}, + {"STRAFE LEFT" ,S_KEY ,m_scrn,KB_X,KB_Y+6*8,{&key_strafeleft}}, + {"STRAFE RIGHT",S_KEY ,m_scrn,KB_X,KB_Y+7*8,{&key_straferight}}, + {"STRAFE" ,S_KEY ,m_scrn,KB_X,KB_Y+8*8,{&key_strafe},&mousebstrafe,&joybstrafe}, + {"AUTORUN" ,S_KEY ,m_scrn,KB_X,KB_Y+9*8,{&key_autorun}}, + {"180 TURN" ,S_KEY ,m_scrn,KB_X,KB_Y+10*8,{&key_reverse}}, + {"USE" ,S_KEY ,m_scrn,KB_X,KB_Y+11*8,{&key_use},&mousebforward,&joybuse}, + + {"MENUS" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y+12*8}, + {"NEXT ITEM" ,S_KEY ,m_menu,KB_X,KB_Y+13*8,{&key_menu_down}}, + {"PREV ITEM" ,S_KEY ,m_menu,KB_X,KB_Y+14*8,{&key_menu_up}}, + {"LEFT" ,S_KEY ,m_menu,KB_X,KB_Y+15*8,{&key_menu_left}}, + {"RIGHT" ,S_KEY ,m_menu,KB_X,KB_Y+16*8,{&key_menu_right}}, + {"BACKSPACE" ,S_KEY ,m_menu,KB_X,KB_Y+17*8,{&key_menu_backspace}}, + {"SELECT ITEM" ,S_KEY ,m_menu,KB_X,KB_Y+18*8,{&key_menu_enter}}, + {"EXIT" ,S_KEY ,m_menu,KB_X,KB_Y+19*8,{&key_menu_escape}}, + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON}, + + {"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {keys_settings2}}, + + // Final entry + {0,S_SKIP|S_END,m_null} + +}; + +setup_menu_t keys_settings2[] = // Key Binding screen strings +{ + {"SCREEN" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y}, + + // phares 4/13/98: + // key_help and key_escape can no longer be rebound. This keeps the + // player from getting themselves in a bind where they can't remember how + // to get to the menus, and can't remember how to get to the help screen + // to give them a clue as to how to get to the menus. :) + + // Also, the keys assigned to these functions cannot be bound to other + // functions. Introduce an S_KEEP flag to show that you cannot swap this + // key with other keys in the same 'group'. (m_scrn, etc.) + + {"HELP" ,S_SKIP|S_KEEP ,m_scrn,0 ,0 ,{&key_help}}, + {"MENU" ,S_SKIP|S_KEEP ,m_scrn,0 ,0 ,{&key_escape}}, + // killough 10/98: hotkey for entering setup menu: + {"SETUP" ,S_KEY ,m_scrn,KB_X,KB_Y+ 1*8,{&key_setup}}, + {"PAUSE" ,S_KEY ,m_scrn,KB_X,KB_Y+ 2*8,{&key_pause}}, + {"AUTOMAP" ,S_KEY ,m_scrn,KB_X,KB_Y+ 3*8,{&key_map}}, + {"VOLUME" ,S_KEY ,m_scrn,KB_X,KB_Y+ 4*8,{&key_soundvolume}}, + {"HUD" ,S_KEY ,m_scrn,KB_X,KB_Y+ 5*8,{&key_hud}}, + {"MESSAGES" ,S_KEY ,m_scrn,KB_X,KB_Y+ 6*8,{&key_messages}}, + {"GAMMA FIX" ,S_KEY ,m_scrn,KB_X,KB_Y+ 7*8,{&key_gamma}}, + {"SPY" ,S_KEY ,m_scrn,KB_X,KB_Y+ 8*8,{&key_spy}}, + {"LARGER VIEW" ,S_KEY ,m_scrn,KB_X,KB_Y+ 9*8,{&key_zoomin}}, + {"SMALLER VIEW",S_KEY ,m_scrn,KB_X,KB_Y+10*8,{&key_zoomout}}, + {"SCREENSHOT" ,S_KEY ,m_scrn,KB_X,KB_Y+11*8,{&key_screenshot}}, + {"GAME" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y+12*8}, + {"SAVE" ,S_KEY ,m_scrn,KB_X,KB_Y+13*8,{&key_savegame}}, + {"LOAD" ,S_KEY ,m_scrn,KB_X,KB_Y+14*8,{&key_loadgame}}, + {"QUICKSAVE" ,S_KEY ,m_scrn,KB_X,KB_Y+15*8,{&key_quicksave}}, + {"QUICKLOAD" ,S_KEY ,m_scrn,KB_X,KB_Y+16*8,{&key_quickload}}, + {"END GAME" ,S_KEY ,m_scrn,KB_X,KB_Y+17*8,{&key_endgame}}, + {"QUIT" ,S_KEY ,m_scrn,KB_X,KB_Y+18*8,{&key_quit}}, + {"<- PREV", S_SKIP|S_PREV,m_null,KB_PREV,KB_Y+20*8, {keys_settings1}}, + {"NEXT ->", S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {keys_settings3}}, + + // Final entry + + {0,S_SKIP|S_END,m_null} +}; + +setup_menu_t keys_settings3[] = // Key Binding screen strings +{ + {"WEAPONS" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y}, + {"FIST" ,S_KEY ,m_scrn,KB_X,KB_Y+ 1*8,{&key_weapon1}}, + {"PISTOL" ,S_KEY ,m_scrn,KB_X,KB_Y+ 2*8,{&key_weapon2}}, + {"SHOTGUN" ,S_KEY ,m_scrn,KB_X,KB_Y+ 3*8,{&key_weapon3}}, + {"CHAINGUN",S_KEY ,m_scrn,KB_X,KB_Y+ 4*8,{&key_weapon4}}, + {"ROCKET" ,S_KEY ,m_scrn,KB_X,KB_Y+ 5*8,{&key_weapon5}}, + {"PLASMA" ,S_KEY ,m_scrn,KB_X,KB_Y+ 6*8,{&key_weapon6}}, + {"BFG", S_KEY ,m_scrn,KB_X,KB_Y+ 7*8,{&key_weapon7}}, + {"CHAINSAW",S_KEY ,m_scrn,KB_X,KB_Y+ 8*8,{&key_weapon8}}, + {"SSG" ,S_KEY ,m_scrn,KB_X,KB_Y+ 9*8,{&key_weapon9}}, + {"BEST" ,S_KEY ,m_scrn,KB_X,KB_Y+10*8,{&key_weapontoggle}}, + {"FIRE" ,S_KEY ,m_scrn,KB_X,KB_Y+11*8,{&key_fire},&mousebfire,&joybfire}, + + {"<- PREV",S_SKIP|S_PREV,m_null,KB_PREV,KB_Y+20*8, {keys_settings2}}, + {"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {keys_settings4}}, + + // Final entry + + {0,S_SKIP|S_END,m_null} + +}; + +setup_menu_t keys_settings4[] = // Key Binding screen strings +{ + {"AUTOMAP" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y}, + {"FOLLOW" ,S_KEY ,m_map ,KB_X,KB_Y+ 1*8,{&key_map_follow}}, + {"ZOOM IN" ,S_KEY ,m_map ,KB_X,KB_Y+ 2*8,{&key_map_zoomin}}, + {"ZOOM OUT" ,S_KEY ,m_map ,KB_X,KB_Y+ 3*8,{&key_map_zoomout}}, + {"SHIFT UP" ,S_KEY ,m_map ,KB_X,KB_Y+ 4*8,{&key_map_up}}, + {"SHIFT DOWN" ,S_KEY ,m_map ,KB_X,KB_Y+ 5*8,{&key_map_down}}, + {"SHIFT LEFT" ,S_KEY ,m_map ,KB_X,KB_Y+ 6*8,{&key_map_left}}, + {"SHIFT RIGHT",S_KEY ,m_map ,KB_X,KB_Y+ 7*8,{&key_map_right}}, + {"MARK PLACE" ,S_KEY ,m_map ,KB_X,KB_Y+ 8*8,{&key_map_mark}}, + {"CLEAR MARKS",S_KEY ,m_map ,KB_X,KB_Y+ 9*8,{&key_map_clear}}, + {"FULL/ZOOM" ,S_KEY ,m_map ,KB_X,KB_Y+10*8,{&key_map_gobig}}, + {"GRID" ,S_KEY ,m_map ,KB_X,KB_Y+11*8,{&key_map_grid}}, + + {"CHATTING" ,S_SKIP|S_TITLE,m_null,KB_X,KB_Y+12*8}, + {"BEGIN CHAT" ,S_KEY ,m_scrn,KB_X,KB_Y+13*8,{&key_chat}}, + {"PLAYER 1" ,S_KEY ,m_scrn,KB_X,KB_Y+14*8,{&destination_keys[0]}}, + {"PLAYER 2" ,S_KEY ,m_scrn,KB_X,KB_Y+15*8,{&destination_keys[1]}}, + {"PLAYER 3" ,S_KEY ,m_scrn,KB_X,KB_Y+16*8,{&destination_keys[2]}}, + {"PLAYER 4" ,S_KEY ,m_scrn,KB_X,KB_Y+17*8,{&destination_keys[3]}}, + {"BACKSPACE" ,S_KEY ,m_scrn,KB_X,KB_Y+18*8,{&key_backspace}}, + {"ENTER" ,S_KEY ,m_scrn,KB_X,KB_Y+19*8,{&key_enter}}, + + {"<- PREV" ,S_SKIP|S_PREV,m_null,KB_PREV,KB_Y+20*8, {keys_settings3}}, + + // Final entry + + {0,S_SKIP|S_END,m_null} + +}; + +// Setting up for the Key Binding screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_KeyBindings(int choice) +{ + M_SetupNextMenu(&KeybndDef); + + setup_active = true; + setup_screen = ss_keys; + set_keybnd_active = true; + setup_select = false; + default_verify = false; + setup_gather = false; + mult_screens_index = 0; + current_setup_menu = keys_settings[0]; + set_menu_itemon = 0; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + +// The drawing part of the Key Bindings Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawKeybnd(void) + +{ + inhelpscreens = true; // killough 4/6/98: Force status bar redraw + + // Set up the Key Binding screen + + M_DrawBackground("FLOOR4_6", 0); // Draw background + // proff/nicolas 09/20/98 -- changed for hi-res + V_DrawNamePatch(84, 2, 0, "M_KEYBND", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + + // If the Reset Button has been selected, an "Are you sure?" message + // is overlayed across everything else. + + if (default_verify) + M_DrawDefVerify(); +} + +///////////////////////////// +// +// The Weapon Screen tables. + +#define WP_X 203 +#define WP_Y 33 + +// There's only one weapon settings screen (for now). But since we're +// trying to fit a common description for screens, it gets a setup_menu_t, +// which only has one screen definition in it. +// +// Note that this screen has no PREV or NEXT items, since there are no +// neighboring screens. + +enum { // killough 10/98: enum for y-offset info + weap_recoil, + weap_bobbing, + weap_bfg, + weap_stub1, + weap_pref1, + weap_pref2, + weap_pref3, + weap_pref4, + weap_pref5, + weap_pref6, + weap_pref7, + weap_pref8, + weap_pref9, + weap_stub2, + weap_toggle, + weap_toggle2, +}; + +setup_menu_t weap_settings1[]; + +setup_menu_t* weap_settings[] = +{ + weap_settings1, + NULL +}; + +setup_menu_t weap_settings1[] = // Weapons Settings screen +{ + {"ENABLE RECOIL", S_YESNO,m_null,WP_X, WP_Y+ weap_recoil*8, {"weapon_recoil"}}, + {"ENABLE BOBBING",S_YESNO,m_null,WP_X, WP_Y+weap_bobbing*8, {"player_bobbing"}}, + + {"1ST CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref1*8, {"weapon_choice_1"}}, + {"2nd CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref2*8, {"weapon_choice_2"}}, + {"3rd CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref3*8, {"weapon_choice_3"}}, + {"4th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref4*8, {"weapon_choice_4"}}, + {"5th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref5*8, {"weapon_choice_5"}}, + {"6th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref6*8, {"weapon_choice_6"}}, + {"7th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref7*8, {"weapon_choice_7"}}, + {"8th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref8*8, {"weapon_choice_8"}}, + {"9th CHOICE WEAPON",S_WEAP,m_null,WP_X,WP_Y+weap_pref9*8, {"weapon_choice_9"}}, + + {"Enable Fist/Chainsaw\n& SG/SSG toggle", S_YESNO, m_null, WP_X, + WP_Y+ weap_toggle*8, {"doom_weapon_toggles"}}, + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON}, + + // Final entry + {0,S_SKIP|S_END,m_null} + +}; + +// Setting up for the Weapons screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_Weapons(int choice) +{ + M_SetupNextMenu(&WeaponDef); + + setup_active = true; + setup_screen = ss_weap; + set_weapon_active = true; + setup_select = false; + default_verify = false; + setup_gather = false; + mult_screens_index = 0; + current_setup_menu = weap_settings[0]; + set_menu_itemon = 0; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + + +// The drawing part of the Weapons Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawWeapons(void) +{ + inhelpscreens = true; // killough 4/6/98: Force status bar redraw + + M_DrawBackground("FLOOR4_6", 0); // Draw background + // proff/nicolas 09/20/98 -- changed for hi-res + V_DrawNamePatch(109, 2, 0, "M_WEAP", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + + // If the Reset Button has been selected, an "Are you sure?" message + // is overlayed across everything else. + + if (default_verify) + M_DrawDefVerify(); +} + +///////////////////////////// +// +// The Status Bar / HUD tables. + +#define ST_X 203 +#define ST_Y 31 + +// Screen table definitions + +setup_menu_t stat_settings1[]; + +setup_menu_t* stat_settings[] = +{ + stat_settings1, + NULL +}; + +setup_menu_t stat_settings1[] = // Status Bar and HUD Settings screen +{ + {"STATUS BAR" ,S_SKIP|S_TITLE,m_null,ST_X,ST_Y+ 1*8 }, + + {"USE RED NUMBERS" ,S_YESNO, m_null,ST_X,ST_Y+ 2*8, {"sts_always_red"}}, + {"GRAY %" ,S_YESNO, m_null,ST_X,ST_Y+ 3*8, {"sts_pct_always_gray"}}, + {"SINGLE KEY DISPLAY",S_YESNO, m_null,ST_X,ST_Y+ 4*8, {"sts_traditional_keys"}}, + + {"HEADS-UP DISPLAY" ,S_SKIP|S_TITLE,m_null,ST_X,ST_Y+ 6*8}, + + {"HIDE SECRETS" ,S_YESNO ,m_null,ST_X,ST_Y+ 7*8, {"hud_nosecrets"}}, + {"HEALTH LOW/OK" ,S_NUM ,m_null,ST_X,ST_Y+ 8*8, {"health_red"}}, + {"HEALTH OK/GOOD" ,S_NUM ,m_null,ST_X,ST_Y+ 9*8, {"health_yellow"}}, + {"HEALTH GOOD/EXTRA" ,S_NUM ,m_null,ST_X,ST_Y+10*8, {"health_green"}}, + {"ARMOR LOW/OK" ,S_NUM ,m_null,ST_X,ST_Y+11*8, {"armor_red"}}, + {"ARMOR OK/GOOD" ,S_NUM ,m_null,ST_X,ST_Y+12*8, {"armor_yellow"}}, + {"ARMOR GOOD/EXTRA" ,S_NUM ,m_null,ST_X,ST_Y+13*8, {"armor_green"}}, + {"AMMO LOW/OK" ,S_NUM ,m_null,ST_X,ST_Y+14*8, {"ammo_red"}}, + {"AMMO OK/GOOD" ,S_NUM ,m_null,ST_X,ST_Y+15*8, {"ammo_yellow"}}, + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON}, + + // Final entry + {0,S_SKIP|S_END,m_null} +}; + +// Setting up for the Status Bar / HUD screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_StatusBar(int choice) +{ + M_SetupNextMenu(&StatusHUDDef); + + setup_active = true; + setup_screen = ss_stat; + set_status_active = true; + setup_select = false; + default_verify = false; + setup_gather = false; + mult_screens_index = 0; + current_setup_menu = stat_settings[0]; + set_menu_itemon = 0; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + + +// The drawing part of the Status Bar / HUD Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawStatusHUD(void) + +{ + inhelpscreens = true; // killough 4/6/98: Force status bar redraw + + M_DrawBackground("FLOOR4_6", 0); // Draw background + // proff/nicolas 09/20/98 -- changed for hi-res + V_DrawNamePatch(59, 2, 0, "M_STAT", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + + // If the Reset Button has been selected, an "Are you sure?" message + // is overlayed across everything else. + + if (default_verify) + M_DrawDefVerify(); +} + + +///////////////////////////// +// +// The Automap tables. + +#define AU_X 250 +#define AU_Y 31 +#define AU_PREV KB_PREV +#define AU_NEXT KB_NEXT + +setup_menu_t auto_settings1[]; +setup_menu_t auto_settings2[]; + +setup_menu_t* auto_settings[] = +{ + auto_settings1, + auto_settings2, + NULL +}; + +setup_menu_t auto_settings1[] = // 1st AutoMap Settings screen +{ + {"background", S_COLOR, m_null, AU_X, AU_Y, {"mapcolor_back"}}, + {"grid lines", S_COLOR, m_null, AU_X, AU_Y + 1*8, {"mapcolor_grid"}}, + {"normal 1s wall", S_COLOR, m_null,AU_X,AU_Y+ 2*8, {"mapcolor_wall"}}, + {"line at floor height change", S_COLOR, m_null, AU_X, AU_Y+ 3*8, {"mapcolor_fchg"}}, + {"line at ceiling height change" ,S_COLOR,m_null,AU_X,AU_Y+ 4*8, {"mapcolor_cchg"}}, + {"line at sector with floor = ceiling",S_COLOR,m_null,AU_X,AU_Y+ 5*8, {"mapcolor_clsd"}}, + {"red key" ,S_COLOR,m_null,AU_X,AU_Y+ 6*8, {"mapcolor_rkey"}}, + {"blue key" ,S_COLOR,m_null,AU_X,AU_Y+ 7*8, {"mapcolor_bkey"}}, + {"yellow key" ,S_COLOR,m_null,AU_X,AU_Y+ 8*8, {"mapcolor_ykey"}}, + {"red door" ,S_COLOR,m_null,AU_X,AU_Y+ 9*8, {"mapcolor_rdor"}}, + {"blue door" ,S_COLOR,m_null,AU_X,AU_Y+10*8, {"mapcolor_bdor"}}, + {"yellow door" ,S_COLOR,m_null,AU_X,AU_Y+11*8, {"mapcolor_ydor"}}, + + {"AUTOMAP LEVEL TITLE COLOR" ,S_CRITEM,m_null,AU_X,AU_Y+13*8, {"hudcolor_titl"}}, + {"AUTOMAP COORDINATES COLOR" ,S_CRITEM,m_null,AU_X,AU_Y+14*8, {"hudcolor_xyco"}}, + + {"Show Secrets only after entering",S_YESNO,m_null,AU_X,AU_Y+15*8, {"map_secret_after"}}, + + {"Show coordinates of automap pointer",S_YESNO,m_null,AU_X,AU_Y+16*8, {"map_point_coord"}}, // killough 10/98 + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON}, + + {"NEXT ->",S_SKIP|S_NEXT,m_null,AU_NEXT,AU_Y+20*8, {auto_settings2}}, + + // Final entry + {0,S_SKIP|S_END,m_null} + +}; + +setup_menu_t auto_settings2[] = // 2nd AutoMap Settings screen +{ + {"teleporter line" ,S_COLOR ,m_null,AU_X,AU_Y, {"mapcolor_tele"}}, + {"secret sector boundary" ,S_COLOR ,m_null,AU_X,AU_Y+ 1*8, {"mapcolor_secr"}}, + //jff 4/23/98 add exit line to automap + {"exit line" ,S_COLOR ,m_null,AU_X,AU_Y+ 2*8, {"mapcolor_exit"}}, + {"computer map unseen line" ,S_COLOR ,m_null,AU_X,AU_Y+ 3*8, {"mapcolor_unsn"}}, + {"line w/no floor/ceiling changes",S_COLOR ,m_null,AU_X,AU_Y+ 4*8, {"mapcolor_flat"}}, + {"general sprite" ,S_COLOR ,m_null,AU_X,AU_Y+ 5*8, {"mapcolor_sprt"}}, + {"countable enemy sprite" ,S_COLOR ,m_null,AU_X,AU_Y+ 6*8, {"mapcolor_enemy"}}, // cph 2006/06/30 + {"countable item sprite" ,S_COLOR ,m_null,AU_X,AU_Y+ 7*8, {"mapcolor_item"}}, // mead 3/4/2003 + {"crosshair" ,S_COLOR ,m_null,AU_X,AU_Y+ 8*8, {"mapcolor_hair"}}, + {"single player arrow" ,S_COLOR ,m_null,AU_X,AU_Y+ 9*8, {"mapcolor_sngl"}}, + {"your colour in multiplayer" ,S_COLOR ,m_null,AU_X,AU_Y+10*8, {"mapcolor_me"}}, + + {"friends" ,S_COLOR ,m_null,AU_X,AU_Y+12*8, {"mapcolor_frnd"}}, // killough 8/8/98 + + {"<- PREV",S_SKIP|S_PREV,m_null,AU_PREV,AU_Y+20*8, {auto_settings1}}, + + // Final entry + + {0,S_SKIP|S_END,m_null} + +}; + + +// Setting up for the Automap screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_Automap(int choice) +{ + M_SetupNextMenu(&AutoMapDef); + + setup_active = true; + setup_screen = ss_auto; + set_auto_active = true; + setup_select = false; + colorbox_active = false; + default_verify = false; + setup_gather = false; + set_menu_itemon = 0; + mult_screens_index = 0; + current_setup_menu = auto_settings[0]; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + +// Data used by the color palette that is displayed for the player to +// select colors. + +int color_palette_x; // X position of the cursor on the color palette +int color_palette_y; // Y position of the cursor on the color palette +byte palette_background[16*(CHIP_SIZE+1)+8]; + +// M_DrawColPal() draws the color palette when the user needs to select a +// color. + +// phares 4/1/98: now uses a single lump for the palette instead of +// building the image out of individual paint chips. + +static void M_DrawColPal(void) +{ + int cpx, cpy; + + // Draw a background, border, and paint chips + + // proff/nicolas 09/20/98 -- changed for hi-res + // CPhipps - patch drawing updated + V_DrawNamePatch(COLORPALXORIG-5, COLORPALYORIG-5, 0, "M_COLORS", CR_DEFAULT, VPT_STRETCH); + + // Draw the cursor around the paint chip + // (cpx,cpy) is the upper left-hand corner of the paint chip + + cpx = COLORPALXORIG+color_palette_x*(CHIP_SIZE+1)-1; + cpy = COLORPALYORIG+color_palette_y*(CHIP_SIZE+1)-1; + // proff 12/6/98: Drawing of colorchips completly changed for hi-res, it now uses a patch + V_DrawNamePatch(cpx,cpy,0,"M_PALSEL",CR_DEFAULT,VPT_STRETCH); // PROFF_GL_FIX +} + +// The drawing part of the Automap Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawAutoMap(void) + +{ + inhelpscreens = true; // killough 4/6/98: Force status bar redraw + + M_DrawBackground("FLOOR4_6", 0); // Draw background + // CPhipps - patch drawing updated + V_DrawNamePatch(109, 2, 0, "M_AUTO", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + + // If a color is being selected, need to show color paint chips + + if (colorbox_active) + M_DrawColPal(); + + // If the Reset Button has been selected, an "Are you sure?" message + // is overlayed across everything else. + + else if (default_verify) + M_DrawDefVerify(); +} + + +///////////////////////////// +// +// The Enemies table. + +#define E_X 250 +#define E_Y 31 + +setup_menu_t enem_settings1[]; + +setup_menu_t* enem_settings[] = +{ + enem_settings1, + NULL +}; + +enum { + enem_infighting, + + enem_remember = 1, + + enem_backing, + enem_monkeys, + enem_avoid_hazards, + enem_friction, + enem_help_friends, + +#ifdef DOGS + enem_helpers, +#endif + + enem_distfriend, + +#ifdef DOGS + enem_dog_jumping, +#endif + + enem_end +}; + +setup_menu_t enem_settings1[] = // Enemy Settings screen +{ + // killough 7/19/98 + {"Monster Infighting When Provoked",S_YESNO,m_null,E_X,E_Y+ enem_infighting*8, {"monster_infighting"}}, + + {"Remember Previous Enemy",S_YESNO,m_null,E_X,E_Y+ enem_remember*8, {"monsters_remember"}}, + + // killough 9/8/98 + {"Monster Backing Out",S_YESNO,m_null,E_X,E_Y+ enem_backing*8, {"monster_backing"}}, + + {"Climb Steep Stairs", S_YESNO,m_null,E_X,E_Y+enem_monkeys*8, {"monkeys"}}, + + // killough 9/9/98 + {"Intelligently Avoid Hazards",S_YESNO,m_null,E_X,E_Y+ enem_avoid_hazards*8, {"monster_avoid_hazards"}}, + + // killough 10/98 + {"Affected by Friction",S_YESNO,m_null,E_X,E_Y+ enem_friction*8, {"monster_friction"}}, + + {"Rescue Dying Friends",S_YESNO,m_null,E_X,E_Y+ enem_help_friends*8, {"help_friends"}}, + +#ifdef DOGS + // killough 7/19/98 + {"Number Of Single-Player Helper Dogs",S_NUM|S_LEVWARN,m_null,E_X,E_Y+ enem_helpers*8, {"player_helpers"}}, + + // killough 8/8/98 + {"Distance Friends Stay Away",S_NUM,m_null,E_X,E_Y+ enem_distfriend*8, {"friend_distance"}}, + + {"Allow dogs to jump down",S_YESNO,m_null,E_X,E_Y+ enem_dog_jumping*8, {"dog_jumping"}}, +#endif + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON}, + + // Final entry + {0,S_SKIP|S_END,m_null} + +}; + +///////////////////////////// + +// Setting up for the Enemies screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_Enemy(int choice) +{ + M_SetupNextMenu(&EnemyDef); + + setup_active = true; + setup_screen = ss_enem; + set_enemy_active = true; + setup_select = false; + default_verify = false; + setup_gather = false; + mult_screens_index = 0; + current_setup_menu = enem_settings[0]; + set_menu_itemon = 0; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + +// The drawing part of the Enemies Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawEnemy(void) + +{ + inhelpscreens = true; + + M_DrawBackground("FLOOR4_6", 0); // Draw background + // proff/nicolas 09/20/98 -- changed for hi-res + V_DrawNamePatch(114, 2, 0, "M_ENEM", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + + // If the Reset Button has been selected, an "Are you sure?" message + // is overlayed across everything else. + + if (default_verify) + M_DrawDefVerify(); +} + + +///////////////////////////// +// +// The General table. +// killough 10/10/98 + +extern int usejoystick, usemouse, default_mus_card, default_snd_card; +extern int detect_voices, realtic_clock_rate, tran_filter_pct; + +setup_menu_t gen_settings1[], gen_settings2[], gen_settings3[]; + +setup_menu_t* gen_settings[] = +{ + gen_settings1, + gen_settings2, + gen_settings3, + NULL +}; + +enum { + general_trans, + general_transpct, + general_fullscreen, + general_videomode, +// general_pcx, +// general_diskicon, + general_uncapped, +}; + +enum { + general_gl_texfilter, + general_gl_texformat, + general_flooroffset, +}; + +enum { +// general_sndcard, +// general_muscard, +// general_detvoices, + general_sndchan, + general_pitch +}; + +#define G_X 250 +#define G_YA 44 +#define G_YA2 (G_YA+9*8) +#define G_YA3 (G_YA2+5*8) +#define GF_X 76 + +static const char *videomodes[] = {"8bit","15bit","16bit", + "32bit","OpenGL", NULL}; + +static const char *gltexfilters[] = {"GL_NEAREST","GL_LINEAR", + "GL_LINEAR_MIPMAP_LINEAR", + NULL}; + +static const char *gltexformats[] = {"GL_RGBA","GL_RGB5_A1", + "GL_RGBA4", NULL}; + +setup_menu_t gen_settings1[] = { // General Settings screen1 + + {"Video" ,S_SKIP|S_TITLE, m_null, G_X, G_YA - 12}, + + {"Enable Translucency", S_YESNO, m_null, G_X, + G_YA + general_trans*8, {"translucency"}, 0, 0, M_Trans}, + + {"Translucency filter percentage", S_NUM, m_null, G_X, + G_YA + general_transpct*8, {"tran_filter_pct"}, 0, 0, M_Trans}, + + {"Fullscreen Video mode", S_YESNO|S_PRGWARN, m_null, G_X, + G_YA + general_fullscreen*8, {"use_fullscreen"}, 0, 0, NULL}, + + {"Video mode", S_CHOICE|S_PRGWARN, m_null, G_X, + G_YA + general_videomode*8, {"videomode"}, 0, 0, NULL, videomodes}, + + {"Uncapped Framerate", S_YESNO, m_null, G_X, + G_YA + general_uncapped*8, {"uncapped_framerate"}}, + +#ifdef GL_DOOM + {"OpenGL", S_SKIP|S_TITLE, m_null, G_X, G_YA2 - 12}, + + {"Texture filter", S_CHOICE|S_PRGWARN, m_null, G_X, + G_YA2 + general_gl_texfilter*8, {"gl_tex_filter_string"}, 0, 0, NULL, gltexfilters}, + + {"Texture format", S_CHOICE|S_PRGWARN, m_null, G_X, + G_YA2 + general_gl_texformat*8, {"gl_tex_format_string"}, 0, 0, NULL, gltexformats}, + + {"Item out of Floor offset", S_NUM, m_null, G_X, + G_YA2 + general_flooroffset*8, {"gl_sprite_offset"}}, +#endif + +#if 0 + {"PCX instead of BMP for screenshots", S_YESNO, m_null, G_X, + G_YA + general_pcx*8, {"screenshot_pcx"}}, +#endif + +#if 0 // MBF + {"Flash Icon During Disk IO", S_YESNO, m_null, G_X, + G_YA + general_diskicon*8, {"disk_icon"}}, +#endif + + {"Sound & Music", S_SKIP|S_TITLE, m_null, G_X, G_YA3 - 12}, +#if 0 // MBF + {"Sound Card", S_NUM|S_PRGWARN, m_null, G_X, + G_YA2 + general_sndcard*8, {"sound_card"}}, + + {"Music Card", S_NUM|S_PRGWARN, m_null, G_X, + G_YA2 + general_muscard*8, {"music_card"}}, + + {"Autodetect Number of Voices", S_YESNO|S_PRGWARN, m_null, G_X, + G_YA2 + general_detvoices*8, {"detect_voices"}}, +#endif + + {"Number of Sound Channels", S_NUM|S_PRGWARN, m_null, G_X, + G_YA3 + general_sndchan*8, {"snd_channels"}}, + + {"Enable v1.1 Pitch Effects", S_YESNO, m_null, G_X, + G_YA3 + general_pitch*8, {"pitched_sounds"}}, + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON}, + + {"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {gen_settings2}}, + + // Final entry + {0,S_SKIP|S_END,m_null} +}; + +enum { + general_mouse, + general_joy, + general_leds +}; + +enum { + general_wad1, + general_wad2, + general_deh1, + general_deh2 +}; + +enum { + general_corpse, + general_realtic, + general_smooth, + general_smoothfactor, + general_defskill, +}; + +#define G_YB 44 +#define G_YB1 (G_YB+44) +#define G_YB2 (G_YB1+52) + +static const char *gen_skillstrings[] = { + // Dummy first option because defaultskill is 1-based + "", "ITYTD", "HNTR", "HMP", "UV", "NM", NULL +}; + +setup_menu_t gen_settings2[] = { // General Settings screen2 + + {"Input Devices" ,S_SKIP|S_TITLE, m_null, G_X, G_YB - 12}, + + {"Enable Mouse", S_YESNO, m_null, G_X, + G_YB + general_mouse*8, {"use_mouse"}}, + + {"Enable Joystick", S_YESNO, m_null, G_X, + G_YB + general_joy*8, {"use_joystick"}}, + + {"Files Preloaded at Game Startup",S_SKIP|S_TITLE, m_null, G_X, + G_YB1 - 12}, + + {"WAD # 1", S_FILE, m_null, GF_X, G_YB1 + general_wad1*8, {"wadfile_1"}}, + + {"WAD #2", S_FILE, m_null, GF_X, G_YB1 + general_wad2*8, {"wadfile_2"}}, + + {"DEH/BEX # 1", S_FILE, m_null, GF_X, G_YB1 + general_deh1*8, {"dehfile_1"}}, + + {"DEH/BEX #2", S_FILE, m_null, GF_X, G_YB1 + general_deh2*8, {"dehfile_2"}}, + + {"Miscellaneous" ,S_SKIP|S_TITLE, m_null, G_X, G_YB2 - 12}, + + {"Maximum number of player corpses", S_NUM|S_PRGWARN, m_null, G_X, + G_YB2 + general_corpse*8, {"max_player_corpse"}}, + + {"Game speed, percentage of normal", S_NUM|S_PRGWARN, m_null, G_X, + G_YB2 + general_realtic*8, {"realtic_clock_rate"}}, + + {"Smooth Demo Playback", S_YESNO, m_null, G_X, + G_YB2 + general_smooth*8, {"demo_smoothturns"}, 0, 0, M_ChangeDemoSmoothTurns}, + + {"Smooth Demo Playback Factor", S_NUM, m_null, G_X, + G_YB2 + general_smoothfactor*8, {"demo_smoothturnsfactor"}, 0, 0, M_ChangeDemoSmoothTurns}, + + {"Default skill level", S_CHOICE, m_null, G_X, + G_YB2 + general_defskill*8, {"default_skill"}, 0, 0, NULL, gen_skillstrings}, + + {"<- PREV",S_SKIP|S_PREV, m_null, KB_PREV, KB_Y+20*8, {gen_settings1}}, + + {"NEXT ->",S_SKIP|S_NEXT,m_null,KB_NEXT,KB_Y+20*8, {gen_settings3}}, + + // Final entry + + {0,S_SKIP|S_END,m_null} +}; + +enum { + general_filterwall, + general_filterfloor, + general_filtersprite, + general_filterpatch, + general_filterz, + general_filter_threshold, + general_spriteedges, + general_patchedges, + general_hom, +}; + +#define G_YC 44 + +static const char *renderfilters[] = {"none", "point", "linear", "rounded"}; +static const char *edgetypes[] = {"jagged", "sloped"}; + +setup_menu_t gen_settings3[] = { // General Settings screen2 + + {"Renderer settings" ,S_SKIP|S_TITLE, m_null, G_X, G_YB - 12}, + + {"Filter for walls", S_CHOICE, m_null, G_X, + G_YC + general_filterwall*8, {"filter_wall"}, 0, 0, NULL, renderfilters}, + + {"Filter for floors/ceilings", S_CHOICE, m_null, G_X, + G_YC + general_filterfloor*8, {"filter_floor"}, 0, 0, NULL, renderfilters}, + + {"Filter for sprites", S_CHOICE, m_null, G_X, + G_YC + general_filtersprite*8, {"filter_sprite"}, 0, 0, NULL, renderfilters}, + + {"Filter for patches", S_CHOICE, m_null, G_X, + G_YC + general_filterpatch*8, {"filter_patch"}, 0, 0, NULL, renderfilters}, + + {"Filter for lighting", S_CHOICE, m_null, G_X, + G_YC + general_filterz*8, {"filter_z"}, 0, 0, NULL, renderfilters}, + + {"Drawing of sprite edges", S_CHOICE, m_null, G_X, + G_YC + general_spriteedges*8, {"sprite_edges"}, 0, 0, NULL, edgetypes}, + + {"Drawing of patch edges", S_CHOICE, m_null, G_X, + G_YC + general_patchedges*8, {"patch_edges"}, 0, 0, NULL, edgetypes}, + + {"Flashing HOM indicator", S_YESNO, m_null, G_X, + G_YC + general_hom*8, {"flashing_hom"}}, + + {"<- PREV",S_SKIP|S_PREV, m_null, KB_PREV, KB_Y+20*8, {gen_settings2}}, + + // Final entry + + {0,S_SKIP|S_END,m_null} +}; + +void M_Trans(void) // To reset translucency after setting it in menu +{ + general_translucency = default_translucency; //e6y: Fix for "translucency won't change until you restart the engine" + + if (general_translucency) + R_InitTranMap(0); +} + +void M_FullScreen(void) // To (un)set fullscreen video after menu changes +{ + I_UpdateVideoMode(); + V_SetPalette(0); +} + +void M_ChangeDemoSmoothTurns(void) +{ + if (demo_smoothturns) + gen_settings2[12].m_flags &= ~(S_SKIP|S_SELECT); + else + gen_settings2[12].m_flags |= (S_SKIP|S_SELECT); + + R_SmoothPlaying_Reset(NULL); +} + +// Setting up for the General screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_General(int choice) +{ + M_SetupNextMenu(&GeneralDef); + + setup_active = true; + setup_screen = ss_gen; + set_general_active = true; + setup_select = false; + default_verify = false; + setup_gather = false; + mult_screens_index = 0; + current_setup_menu = gen_settings[0]; + set_menu_itemon = 0; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + +// The drawing part of the General Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawGeneral(void) +{ + inhelpscreens = true; + + M_DrawBackground("FLOOR4_6", 0); // Draw background + // proff/nicolas 09/20/98 -- changed for hi-res + V_DrawNamePatch(114, 2, 0, "M_GENERL", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + + // If the Reset Button has been selected, an "Are you sure?" message + // is overlayed across everything else. + + if (default_verify) + M_DrawDefVerify(); +} + +///////////////////////////// +// +// The Compatibility table. +// killough 10/10/98 + +#define C_X 284 +#define C_Y 32 +#define COMP_SPC 12 +#define C_NEXTPREV 131 + +setup_menu_t comp_settings1[], comp_settings2[], comp_settings3[]; + +setup_menu_t* comp_settings[] = +{ + comp_settings1, + comp_settings2, + comp_settings3, + NULL +}; + +enum +{ + compat_telefrag, + compat_dropoff, + compat_falloff, + compat_staylift, + compat_doorstuck, + compat_pursuit, + compat_vile, + compat_pain, + compat_skull, + compat_blazing, + compat_doorlight = 0, + compat_god, + compat_infcheat, + compat_zombie, + compat_skymap, + compat_stairs, + compat_floors, + compat_moveblock, + compat_model, + compat_zerotags, + compat_666 = 0, + compat_soul, + compat_maskedanim, +}; + +setup_menu_t comp_settings1[] = // Compatibility Settings screen #1 +{ + {"Any monster can telefrag on MAP30", S_YESNO, m_null, C_X, + C_Y + compat_telefrag * COMP_SPC, {"comp_telefrag"}}, + + {"Some objects never hang over tall ledges", S_YESNO, m_null, C_X, + C_Y + compat_dropoff * COMP_SPC, {"comp_dropoff"}}, + + {"Objects don't fall under their own weight", S_YESNO, m_null, C_X, + C_Y + compat_falloff * COMP_SPC, {"comp_falloff"}}, + + {"Monsters randomly walk off of moving lifts", S_YESNO, m_null, C_X, + C_Y + compat_staylift * COMP_SPC, {"comp_staylift"}}, + + {"Monsters get stuck on doortracks", S_YESNO, m_null, C_X, + C_Y + compat_doorstuck * COMP_SPC, {"comp_doorstuck"}}, + + {"Monsters don't give up pursuit of targets", S_YESNO, m_null, C_X, + C_Y + compat_pursuit * COMP_SPC, {"comp_pursuit"}}, + + {"Arch-Vile resurrects invincible ghosts", S_YESNO, m_null, C_X, + C_Y + compat_vile * COMP_SPC, {"comp_vile"}}, + + {"Pain Elementals limited to 21 lost souls", S_YESNO, m_null, C_X, + C_Y + compat_pain * COMP_SPC, {"comp_pain"}}, + + {"Lost souls get stuck behind walls", S_YESNO, m_null, C_X, + C_Y + compat_skull * COMP_SPC, {"comp_skull"}}, + + {"Blazing doors make double closing sounds", S_YESNO, m_null, C_X, + C_Y + compat_blazing * COMP_SPC, {"comp_blazing"}}, + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON}, + + {"NEXT ->",S_SKIP|S_NEXT, m_null, KB_NEXT, C_Y+C_NEXTPREV, {comp_settings2}}, + + // Final entry + {0,S_SKIP|S_END,m_null} +}; + +setup_menu_t comp_settings2[] = // Compatibility Settings screen #2 +{ + {"Tagged doors don't trigger special lighting", S_YESNO, m_null, C_X, + C_Y + compat_doorlight * COMP_SPC, {"comp_doorlight"}}, + + {"God mode isn't absolute", S_YESNO, m_null, C_X, + C_Y + compat_god * COMP_SPC, {"comp_god"}}, + + {"Powerup cheats are not infinite duration", S_YESNO, m_null, C_X, + C_Y + compat_infcheat * COMP_SPC, {"comp_infcheat"}}, + + {"Zombie players can exit levels", S_YESNO, m_null, C_X, + C_Y + compat_zombie * COMP_SPC, {"comp_zombie"}}, + + {"Sky is unaffected by invulnerability", S_YESNO, m_null, C_X, + C_Y + compat_skymap * COMP_SPC, {"comp_skymap"}}, + + {"Use exactly Doom's stairbuilding method", S_YESNO, m_null, C_X, + C_Y + compat_stairs * COMP_SPC, {"comp_stairs"}}, + + {"Use exactly Doom's floor motion behavior", S_YESNO, m_null, C_X, + C_Y + compat_floors * COMP_SPC, {"comp_floors"}}, + + {"Use exactly Doom's movement clipping code", S_YESNO, m_null, C_X, + C_Y + compat_moveblock * COMP_SPC, {"comp_moveblock"}}, + + {"Use exactly Doom's linedef trigger model", S_YESNO, m_null, C_X, + C_Y + compat_model * COMP_SPC, {"comp_model"}}, + + {"Linedef effects work with sector tag = 0", S_YESNO, m_null, C_X, + C_Y + compat_zerotags * COMP_SPC, {"comp_zerotags"}}, + + {"<- PREV", S_SKIP|S_PREV, m_null, KB_PREV, C_Y+C_NEXTPREV,{comp_settings1}}, + + {"NEXT ->",S_SKIP|S_NEXT, m_null, KB_NEXT, C_Y+C_NEXTPREV, {comp_settings3}}, + + // Final entry + + {0,S_SKIP|S_END,m_null} +}; + +setup_menu_t comp_settings3[] = // Compatibility Settings screen #2 +{ + {"All boss types can trigger tag 666 at ExM8", S_YESNO, m_null, C_X, + C_Y + compat_666 * COMP_SPC, {"comp_666"}}, + + {"Lost souls don't bounce off flat surfaces", S_YESNO, m_null, C_X, + C_Y + compat_soul * COMP_SPC, {"comp_soul"}}, + + {"2S middle textures do not animate", S_YESNO, m_null, C_X, + C_Y + compat_maskedanim * COMP_SPC, {"comp_maskedanim"}}, + + {"<- PREV", S_SKIP|S_PREV, m_null, KB_PREV, C_Y+C_NEXTPREV,{comp_settings2}}, + + // Final entry + + {0,S_SKIP|S_END,m_null} +}; + +// Setting up for the Compatibility screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_Compat(int choice) +{ + M_SetupNextMenu(&CompatDef); + + setup_active = true; + setup_screen = ss_comp; + set_general_active = true; + setup_select = false; + default_verify = false; + setup_gather = false; + mult_screens_index = 0; + current_setup_menu = comp_settings[0]; + set_menu_itemon = 0; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + +// The drawing part of the Compatibility Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawCompat(void) +{ + inhelpscreens = true; + + M_DrawBackground("FLOOR4_6", 0); // Draw background + V_DrawNamePatch(52,2,0,"M_COMPAT", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + + // If the Reset Button has been selected, an "Are you sure?" message + // is overlayed across everything else. + + if (default_verify) + M_DrawDefVerify(); +} + +///////////////////////////// +// +// The Messages table. + +#define M_X 230 +#define M_Y 39 + +// killough 11/98: enumerated + +enum { + mess_color_play, + mess_timer, + mess_color_chat, + mess_chat_timer, + mess_color_review, + mess_timed, + mess_hud_timer, + mess_lines, + mess_scrollup, + mess_background, +}; + +setup_menu_t mess_settings1[]; + +setup_menu_t* mess_settings[] = +{ + mess_settings1, + NULL +}; + +setup_menu_t mess_settings1[] = // Messages screen +{ + {"Message Color During Play", S_CRITEM, m_null, M_X, + M_Y + mess_color_play*8, {"hudcolor_mesg"}}, + +#if 0 + {"Message Duration During Play (ms)", S_NUM, m_null, M_X, + M_Y + mess_timer*8, {"message_timer"}}, +#endif + + {"Chat Message Color", S_CRITEM, m_null, M_X, + M_Y + mess_color_chat*8, {"hudcolor_chat"}}, + +#if 0 + {"Chat Message Duration (ms)", S_NUM, m_null, M_X, + M_Y + mess_chat_timer*8, {"chat_msg_timer"}}, +#endif + + {"Message Review Color", S_CRITEM, m_null, M_X, + M_Y + mess_color_review*8, {"hudcolor_list"}}, + +#if 0 + {"Message Listing Review is Temporary", S_YESNO, m_null, M_X, + M_Y + mess_timed*8, {"hud_msg_timed"}}, + + {"Message Review Duration (ms)", S_NUM, m_null, M_X, + M_Y + mess_hud_timer*8, {"hud_msg_timer"}}, +#endif + + {"Number of Review Message Lines", S_NUM, m_null, M_X, + M_Y + mess_lines*8, {"hud_msg_lines"}}, + +#if 0 + {"Message Listing Scrolls Upwards", S_YESNO, m_null, M_X, + M_Y + mess_scrollup*8, {"hud_msg_scrollup"}}, +#endif + + {"Message Background", S_YESNO, m_null, M_X, + M_Y + mess_background*8, {"hud_list_bgon"}}, + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON}, + + // Final entry + + {0,S_SKIP|S_END,m_null} +}; + + +// Setting up for the Messages screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_Messages(int choice) +{ + M_SetupNextMenu(&MessageDef); + + setup_active = true; + setup_screen = ss_mess; + set_mess_active = true; + setup_select = false; + default_verify = false; + setup_gather = false; + mult_screens_index = 0; + current_setup_menu = mess_settings[0]; + set_menu_itemon = 0; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + + +// The drawing part of the Messages Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawMessages(void) + +{ + inhelpscreens = true; + M_DrawBackground("FLOOR4_6", 0); // Draw background + // CPhipps - patch drawing updated + V_DrawNamePatch(103, 2, 0, "M_MESS", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + if (default_verify) + M_DrawDefVerify(); +} + + +///////////////////////////// +// +// The Chat Strings table. + +#define CS_X 20 +#define CS_Y (31+8) + +setup_menu_t chat_settings1[]; + +setup_menu_t* chat_settings[] = +{ + chat_settings1, + NULL +}; + +setup_menu_t chat_settings1[] = // Chat Strings screen +{ + {"1",S_CHAT,m_null,CS_X,CS_Y+ 1*8, {"chatmacro1"}}, + {"2",S_CHAT,m_null,CS_X,CS_Y+ 2*8, {"chatmacro2"}}, + {"3",S_CHAT,m_null,CS_X,CS_Y+ 3*8, {"chatmacro3"}}, + {"4",S_CHAT,m_null,CS_X,CS_Y+ 4*8, {"chatmacro4"}}, + {"5",S_CHAT,m_null,CS_X,CS_Y+ 5*8, {"chatmacro5"}}, + {"6",S_CHAT,m_null,CS_X,CS_Y+ 6*8, {"chatmacro6"}}, + {"7",S_CHAT,m_null,CS_X,CS_Y+ 7*8, {"chatmacro7"}}, + {"8",S_CHAT,m_null,CS_X,CS_Y+ 8*8, {"chatmacro8"}}, + {"9",S_CHAT,m_null,CS_X,CS_Y+ 9*8, {"chatmacro9"}}, + {"0",S_CHAT,m_null,CS_X,CS_Y+10*8, {"chatmacro0"}}, + + // Button for resetting to defaults + {0,S_RESET,m_null,X_BUTTON,Y_BUTTON}, + + // Final entry + {0,S_SKIP|S_END,m_null} + +}; + +// Setting up for the Chat Strings screen. Turn on flags, set pointers, +// locate the first item on the screen where the cursor is allowed to +// land. + +void M_ChatStrings(int choice) +{ + M_SetupNextMenu(&ChatStrDef); + setup_active = true; + setup_screen = ss_chat; + set_chat_active = true; + setup_select = false; + default_verify = false; + setup_gather = false; + mult_screens_index = 0; + current_setup_menu = chat_settings[0]; + set_menu_itemon = 0; + while (current_setup_menu[set_menu_itemon++].m_flags & S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; +} + +// The drawing part of the Chat Strings Setup initialization. Draw the +// background, title, instruction line, and items. + +void M_DrawChatStrings(void) + +{ + inhelpscreens = true; + M_DrawBackground("FLOOR4_6", 0); // Draw background + // CPhipps - patch drawing updated + V_DrawNamePatch(83, 2, 0, "M_CHAT", CR_DEFAULT, VPT_STRETCH); + M_DrawInstructions(); + M_DrawScreenItems(current_setup_menu); + + // If the Reset Button has been selected, an "Are you sure?" message + // is overlayed across everything else. + + if (default_verify) + M_DrawDefVerify(); +} + +///////////////////////////// +// +// General routines used by the Setup screens. +// + +static boolean shiftdown = false; // phares 4/10/98: SHIFT key down or not + +// phares 4/17/98: +// M_SelectDone() gets called when you have finished entering your +// Setup Menu item change. + +static void M_SelectDone(setup_menu_t* ptr) +{ + ptr->m_flags &= ~S_SELECT; + ptr->m_flags |= S_HILITE; + S_StartSound(NULL,sfx_itemup); + setup_select = false; + colorbox_active = false; + if (print_warning_about_changes) // killough 8/15/98 + print_warning_about_changes--; +} + +// phares 4/21/98: +// Array of setup screens used by M_ResetDefaults() + +static setup_menu_t **setup_screens[] = +{ + keys_settings, + weap_settings, + stat_settings, + auto_settings, + enem_settings, + mess_settings, + chat_settings, + gen_settings, // killough 10/98 + comp_settings, +}; + +// phares 4/19/98: +// M_ResetDefaults() resets all values for a setup screen to default values +// +// killough 10/98: rewritten to fix bugs and warn about pending changes + +static void M_ResetDefaults(void) +{ + int i; //e6y + + default_t *dp; + int warn = 0; + + // Look through the defaults table and reset every variable that + // belongs to the group we're interested in. + // + // killough: However, only reset variables whose field in the + // current setup screen is the same as in the defaults table. + // i.e. only reset variables really in the current setup screen. + + // e6y + // Fixed crash while trying to read data past array end + // All previous versions of prboom worked only by a lucky accident + // old code: for (dp = defaults; dp->name; dp++) + for (i = 0; i < numdefaults ; i++) + { + dp = &defaults[i]; + + if (dp->setupscreen == setup_screen) + { + setup_menu_t **l, *p; + for (l = setup_screens[setup_screen-1]; *l; l++) + for (p = *l; !(p->m_flags & S_END); p++) + if (p->m_flags & S_HASDEFPTR ? p->var.def == dp : + p->var.m_key == dp->location.pi || + p->m_mouse == dp->location.pi || + p->m_joy == dp->location.pi) + { + if (IS_STRING(*dp)) + free((char*)*dp->location.ppsz), + *dp->location.ppsz = strdup(dp->defaultvalue.psz); + else + *dp->location.pi = dp->defaultvalue.i; + +#if 0 + if (p->m_flags & (S_LEVWARN | S_PRGWARN)) + warn |= p->m_flags & (S_LEVWARN | S_PRGWARN); + else + if (dp->current) + if (allow_changes()) + *dp->current = *dp->location.pi; + else + warn |= S_LEVWARN; +#endif + if (p->action) + p->action(); + + goto end; + } + end:; + } + } + + if (warn) + warn_about_changes(warn); +} + +// +// M_InitDefaults() +// +// killough 11/98: +// +// This function converts all setup menu entries consisting of cfg +// variable names, into pointers to the corresponding default[] +// array entry. var.name becomes converted to var.def. +// + +static void M_InitDefaults(void) +{ + setup_menu_t *const *p, *t; + default_t *dp; + int i; + for (i = 0; i < ss_max-1; i++) + for (p = setup_screens[i]; *p; p++) + for (t = *p; !(t->m_flags & S_END); t++) + if (t->m_flags & S_HASDEFPTR) { + if (!(dp = M_LookupDefault(t->var.name))) + I_Error("M_InitDefaults: Couldn't find config variable %s", t->var.name); + else + (t->var.def = dp)->setup_menu = t; + } +} + +// +// End of Setup Screens. +// +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// +// Start of Extended HELP screens // phares 3/30/98 +// +// The wad designer can define a set of extended HELP screens for their own +// information display. These screens should be 320x200 graphic lumps +// defined in a separate wad. They should be named "HELP01" through "HELP99". +// "HELP01" is shown after the regular BOOM Dynamic HELP screen, and ENTER +// and BACKSPACE keys move the player through the HELP set. +// +// Rather than define a set of menu definitions for each of the possible +// HELP screens, one definition is used, and is altered on the fly +// depending on what HELPnn lumps the game finds. + +// phares 3/30/98: +// Extended Help Screen variables + +int extended_help_count; // number of user-defined help screens found +int extended_help_index; // index of current extended help screen + +menuitem_t ExtHelpMenu[] = +{ + {1,"",M_ExtHelpNextScreen,0} +}; + +menu_t ExtHelpDef = +{ + 1, // # of menu items + &ReadDef1, // previous menu + ExtHelpMenu, // menuitem_t -> + M_DrawExtHelp, // drawing routine -> + 330,181, // x,y + 0 // lastOn +}; + +// M_ExtHelpNextScreen establishes the number of the next HELP screen in +// the series. + +void M_ExtHelpNextScreen(int choice) +{ + choice = 0; + if (++extended_help_index > extended_help_count) + { + + // when finished with extended help screens, return to Main Menu + + extended_help_index = 1; + M_SetupNextMenu(&MainDef); + } +} + +// phares 3/30/98: +// Routine to look for HELPnn screens and create a menu +// definition structure that defines extended help screens. + +void M_InitExtendedHelp(void) + +{ + int index,i; + char namebfr[] = { "HELPnn"} ; + + extended_help_count = 0; + for (index = 1 ; index < 100 ; index++) { + namebfr[4] = index/10 + 0x30; + namebfr[5] = index%10 + 0x30; + i = W_CheckNumForName(namebfr); + if (i == -1) { + if (extended_help_count) { + if (gamemode == commercial) { + ExtHelpDef.prevMenu = &ReadDef1; /* previous menu */ + ReadMenu1[0].routine = M_ExtHelp; + } else { + ExtHelpDef.prevMenu = &ReadDef2; /* previous menu */ + ReadMenu2[0].routine = M_ExtHelp; + } + } + return; + } + extended_help_count++; + } + +} + +// Initialization for the extended HELP screens. + +void M_ExtHelp(int choice) +{ + choice = 0; + extended_help_index = 1; // Start with first extended help screen + M_SetupNextMenu(&ExtHelpDef); +} + +// Initialize the drawing part of the extended HELP screens. + +void M_DrawExtHelp(void) +{ + char namebfr[10] = { "HELPnn" }; // CPhipps - make it local & writable + + inhelpscreens = true; // killough 5/1/98 + namebfr[4] = extended_help_index/10 + 0x30; + namebfr[5] = extended_help_index%10 + 0x30; + // CPhipps - patch drawing updated + V_DrawNamePatch(0, 0, 0, namebfr, CR_DEFAULT, VPT_STRETCH); +} + +// +// End of Extended HELP screens // phares 3/30/98 +// +//////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////// +// +// Dynamic HELP screen // phares 3/2/98 +// +// Rather than providing the static HELP screens from DOOM and its versions, +// BOOM provides the player with a dynamic HELP screen that displays the +// current settings of major key bindings. +// +// The Dynamic HELP screen is defined in a manner similar to that used for +// the Setup Screens above. +// +// M_GetKeyString finds the correct string to represent the key binding +// for the current item being drawn. + +int M_GetKeyString(int c,int offset) +{ + const char* s; + + if (c >= 33 && c <= 126) { + + // The '=', ',', and '.' keys originally meant the shifted + // versions of those keys, but w/o having to shift them in + // the game. Any actions that are mapped to these keys will + // still mean their shifted versions. Could be changed later + // if someone can come up with a better way to deal with them. + + if (c == '=') // probably means the '+' key? + c = '+'; + else if (c == ',') // probably means the '<' key? + c = '<'; + else if (c == '.') // probably means the '>' key? + c = '>'; + menu_buffer[offset++] = c; // Just insert the ascii key + menu_buffer[offset] = 0; + + } else { + + // Retrieve 4-letter (max) string representing the key + + // cph - Keypad keys, general code reorganisation to + // make this smaller and neater. + if ((0x100 <= c) && (c < 0x200)) { + if (c == KEYD_KEYPADENTER) + s = "PADE"; + else { + strcpy(&menu_buffer[offset], "PAD"); + offset+=4; + menu_buffer[offset-1] = c & 0xff; + menu_buffer[offset] = 0; + } + } else if ((KEYD_F1 <= c) && (c < KEYD_F10)) { + menu_buffer[offset++] = 'F'; + menu_buffer[offset++] = '1' + c - KEYD_F1; + menu_buffer[offset] = 0; + } else { + switch(c) { + case KEYD_TAB: s = "TAB"; break; + case KEYD_ENTER: s = "ENTR"; break; + case KEYD_ESCAPE: s = "ESC"; break; + case KEYD_SPACEBAR: s = "SPAC"; break; + case KEYD_BACKSPACE: s = "BACK"; break; + case KEYD_RCTRL: s = "CTRL"; break; + case KEYD_LEFTARROW: s = "LARR"; break; + case KEYD_UPARROW: s = "UARR"; break; + case KEYD_RIGHTARROW: s = "RARR"; break; + case KEYD_DOWNARROW: s = "DARR"; break; + case KEYD_RSHIFT: s = "SHFT"; break; + case KEYD_RALT: s = "ALT"; break; + case KEYD_CAPSLOCK: s = "CAPS"; break; + case KEYD_SCROLLLOCK: s = "SCRL"; break; + case KEYD_HOME: s = "HOME"; break; + case KEYD_PAGEUP: s = "PGUP"; break; + case KEYD_END: s = "END"; break; + case KEYD_PAGEDOWN: s = "PGDN"; break; + case KEYD_INSERT: s = "INST"; break; + case KEYD_DEL: s = "DEL"; break; + case KEYD_F10: s = "F10"; break; + case KEYD_F11: s = "F11"; break; + case KEYD_F12: s = "F12"; break; + case KEYD_PAUSE: s = "PAUS"; break; + default: s = "JUNK"; break; + } + + if (s) { // cph - Slight code change + strcpy(&menu_buffer[offset],s); // string to display + offset += strlen(s); + } + } + } + return offset; +} + +// +// The Dynamic HELP screen table. + +#define KT_X1 283 +#define KT_X2 172 +#define KT_X3 87 + +#define KT_Y1 2 +#define KT_Y2 118 +#define KT_Y3 102 + +setup_menu_t helpstrings[] = // HELP screen strings +{ + {"SCREEN" ,S_SKIP|S_TITLE,m_null,KT_X1,KT_Y1}, + {"HELP" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 1*8,{&key_help}}, + {"MENU" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 2*8,{&key_escape}}, + {"SETUP" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 3*8,{&key_setup}}, + {"PAUSE" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 4*8,{&key_pause}}, + {"AUTOMAP" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 5*8,{&key_map}}, + {"SOUND VOLUME",S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 6*8,{&key_soundvolume}}, + {"HUD" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 7*8,{&key_hud}}, + {"MESSAGES" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 8*8,{&key_messages}}, + {"GAMMA FIX" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+ 9*8,{&key_gamma}}, + {"SPY" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+10*8,{&key_spy}}, + {"LARGER VIEW" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+11*8,{&key_zoomin}}, + {"SMALLER VIEW",S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+12*8,{&key_zoomout}}, + {"SCREENSHOT" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y1+13*8,{&key_screenshot}}, + + {"AUTOMAP" ,S_SKIP|S_TITLE,m_null,KT_X1,KT_Y2}, + {"FOLLOW MODE" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 1*8,{&key_map_follow}}, + {"ZOOM IN" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 2*8,{&key_map_zoomin}}, + {"ZOOM OUT" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 3*8,{&key_map_zoomout}}, + {"MARK PLACE" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 4*8,{&key_map_mark}}, + {"CLEAR MARKS" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 5*8,{&key_map_clear}}, + {"FULL/ZOOM" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 6*8,{&key_map_gobig}}, + {"GRID" ,S_SKIP|S_KEY,m_null,KT_X1,KT_Y2+ 7*8,{&key_map_grid}}, + + {"WEAPONS" ,S_SKIP|S_TITLE,m_null,KT_X3,KT_Y1}, + {"FIST" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 1*8,{&key_weapon1}}, + {"PISTOL" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 2*8,{&key_weapon2}}, + {"SHOTGUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 3*8,{&key_weapon3}}, + {"CHAINGUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 4*8,{&key_weapon4}}, + {"ROCKET" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 5*8,{&key_weapon5}}, + {"PLASMA" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 6*8,{&key_weapon6}}, + {"BFG 9000" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 7*8,{&key_weapon7}}, + {"CHAINSAW" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 8*8,{&key_weapon8}}, + {"SSG" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+ 9*8,{&key_weapon9}}, + {"BEST" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+10*8,{&key_weapontoggle}}, + {"FIRE" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y1+11*8,{&key_fire},&mousebfire,&joybfire}, + + {"MOVEMENT" ,S_SKIP|S_TITLE,m_null,KT_X3,KT_Y3}, + {"FORWARD" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 1*8,{&key_up},&mousebforward}, + {"BACKWARD" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 2*8,{&key_down}}, + {"TURN LEFT" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 3*8,{&key_left}}, + {"TURN RIGHT" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 4*8,{&key_right}}, + {"RUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 5*8,{&key_speed},0,&joybspeed}, + {"STRAFE LEFT" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 6*8,{&key_strafeleft}}, + {"STRAFE RIGHT",S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 7*8,{&key_straferight}}, + {"STRAFE" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 8*8,{&key_strafe},&mousebstrafe,&joybstrafe}, + {"AUTORUN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+ 9*8,{&key_autorun}}, + {"180 TURN" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+10*8,{&key_reverse}}, + {"USE" ,S_SKIP|S_KEY,m_null,KT_X3,KT_Y3+11*8,{&key_use},&mousebforward,&joybuse}, + + {"GAME" ,S_SKIP|S_TITLE,m_null,KT_X2,KT_Y1}, + {"SAVE" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 1*8,{&key_savegame}}, + {"LOAD" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 2*8,{&key_loadgame}}, + {"QUICKSAVE" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 3*8,{&key_quicksave}}, + {"END GAME" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 4*8,{&key_endgame}}, + {"QUICKLOAD" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 5*8,{&key_quickload}}, + {"QUIT" ,S_SKIP|S_KEY,m_null,KT_X2,KT_Y1+ 6*8,{&key_quit}}, + + // Final entry + + {0,S_SKIP|S_END,m_null} +}; + +#define SPACEWIDTH 4 + +/* cph 2006/08/06 + * M_DrawString() is the old M_DrawMenuString, except that it is not tied to + * menu_buffer - no reason to force all the callers to write into one array! */ + +static void M_DrawString(int cx, int cy, int color, const char* ch) +{ + int w; + int c; + + while (*ch) { + c = *ch++; // get next char + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c> HU_FONTSIZE) + { + cx += SPACEWIDTH; // space + continue; + } + w = hu_font[c].width; + if (cx + w > 320) + break; + + // V_DrawpatchTranslated() will draw the string in the + // desired color, colrngs[color] + + // CPhipps - patch drawing updated + V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, color, VPT_STRETCH | VPT_TRANS); + // The screen is cramped, so trim one unit from each + // character so they butt up against each other. + cx += w - 1; + } +} + +// M_DrawMenuString() draws the string in menu_buffer[] + +static void M_DrawMenuString(int cx, int cy, int color) +{ + M_DrawString(cx, cy, color, menu_buffer); +} + +// M_GetPixelWidth() returns the number of pixels in the width of +// the string, NOT the number of chars in the string. + +static int M_GetPixelWidth(const char* ch) +{ + int len = 0; + int c; + + while (*ch) { + c = *ch++; // pick up next char + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c > HU_FONTSIZE) + { + len += SPACEWIDTH; // space + continue; + } + len += hu_font[c].width; + len--; // adjust so everything fits + } + len++; // replace what you took away on the last char only + return len; +} + +static void M_DrawStringCentered(int cx, int cy, int color, const char* ch) +{ + M_DrawString(cx - M_GetPixelWidth(ch)/2, cy, color, ch); +} + +// +// M_DrawHelp +// +// This displays the help screen + +void M_DrawHelp (void) +{ + inhelpscreens = true; // killough 10/98 + M_DrawBackground("FLOOR4_6", 0); + + M_DrawScreenItems(helpstrings); +} + +// +// End of Dynamic HELP screen // phares 3/2/98 +// +//////////////////////////////////////////////////////////////////////////// + +enum { + prog, + prog_stub, + prog_stub1, + prog_stub2, + adcr +}; + +enum { + cr_prog=0, + cr_adcr=2, +}; + +#define CR_S 9 +#define CR_X 20 +#define CR_X2 50 +#define CR_Y 32 +#define CR_SH 9 + +setup_menu_t cred_settings[]={ + + {"Programmers",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X, CR_Y + CR_S*prog + CR_SH*cr_prog}, + {"Florian 'Proff' Schulze",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+1) + CR_SH*cr_prog}, + {"Colin Phipps",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+2) + CR_SH*cr_prog}, + {"Neil Stevens",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+3) + CR_SH*cr_prog}, + {"Andrey Budko",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(prog+4) + CR_SH*cr_prog}, + + {"Additional Credit To",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X, CR_Y + CR_S*adcr + CR_SH*cr_adcr}, + {"id Software for DOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+1)+CR_SH*cr_adcr}, + {"TeamTNT for BOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+2)+CR_SH*cr_adcr}, + {"Lee Killough for MBF",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+3)+CR_SH*cr_adcr}, + {"The DOSDoom-Team for DOSDOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+4)+CR_SH*cr_adcr}, + {"Randy Heit for ZDOOM",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+5)+CR_SH*cr_adcr}, + {"Michael 'Kodak' Ryssen for DOOMGL",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+6)+CR_SH*cr_adcr}, + {"Jess Haas for lSDLDoom",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+7) + CR_SH*cr_adcr}, + {"all others who helped (see AUTHORS file)",S_SKIP|S_CREDIT|S_LEFTJUST,m_null, CR_X2, CR_Y + CR_S*(adcr+8)+CR_SH*cr_adcr}, + + {0,S_SKIP|S_END,m_null} +}; + +void M_DrawCredits(void) // killough 10/98: credit screen +{ + inhelpscreens = true; + M_DrawBackground(gamemode==shareware ? "CEIL5_1" : "MFLR8_4", 0); + V_DrawNamePatch(115,9,0, "PRBOOM",CR_GOLD, VPT_TRANS | VPT_STRETCH); + M_DrawScreenItems(cred_settings); +} + +static int M_IndexInChoices(const char *str, const char **choices) { + int i = 0; + + while (*choices != NULL) { + if (!strcmp(str, *choices)) + return i; + i++; + choices++; + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////// +// +// M_Responder +// +// Examines incoming keystrokes and button pushes and determines some +// action based on the state of the system. +// + +boolean M_Responder (event_t* ev) { + int ch; + int i; + static int joywait = 0; + static int mousewait = 0; + static int mousey = 0; + static int lasty = 0; + static int mousex = 0; + static int lastx = 0; + + ch = -1; // will be changed to a legit char if we're going to use it here + + // Process joystick input + + if (ev->type == ev_joystick && joywait < I_GetTime()) { + if (ev->data3 == -1) + { + ch = key_menu_up; // phares 3/7/98 + joywait = I_GetTime() + 5; + } + else if (ev->data3 == 1) + { + ch = key_menu_down; // phares 3/7/98 + joywait = I_GetTime() + 5; + } + + if (ev->data2 == -1) + { + ch = key_menu_left; // phares 3/7/98 + joywait = I_GetTime() + 2; + } + else if (ev->data2 == 1) + { + ch = key_menu_right; // phares 3/7/98 + joywait = I_GetTime() + 2; + } + + if (ev->data1&1) + { + ch = key_menu_enter; // phares 3/7/98 + joywait = I_GetTime() + 5; + } + + if (ev->data1&2) + { + ch = key_menu_backspace; // phares 3/7/98 + joywait = I_GetTime() + 5; + } + + // phares 4/4/98: + // Handle joystick buttons 3 and 4, and allow them to pass down + // to where key binding can eat them. + + if (setup_active && set_keybnd_active) { + if (ev->data1&4) { + ch = 0; // meaningless, just to get you past the check for -1 + joywait = I_GetTime() + 5; + } + if (ev->data1&8) { + ch = 0; // meaningless, just to get you past the check for -1 + joywait = I_GetTime() + 5; + } + } + + } else { + // Mouse input processing removed + + // Process keyboard input + + if (ev->type == ev_keydown) + { + ch = ev->data1; // phares 4/11/98: + if (ch == KEYD_RSHIFT) // For chat string processing, need + shiftdown = true; // to know when shift key is up or + } // down so you can get at the !,#, + else if (ev->type == ev_keyup) // etc. keys. Keydowns are allowed + if (ev->data1 == KEYD_RSHIFT) // past this point, but keyups aren't + shiftdown = false; // so we need to note the difference + } // here using the 'shiftdown' boolean. + + if (ch == -1) + return false; // we can't use the event here + + // Save Game string input + + if (saveStringEnter) { + if (ch == key_menu_backspace) // phares 3/7/98 + { + if (saveCharIndex > 0) + { + saveCharIndex--; + savegamestrings[saveSlot][saveCharIndex] = 0; + } + } + + else if (ch == key_menu_escape) // phares 3/7/98 + { + saveStringEnter = 0; + strcpy(&savegamestrings[saveSlot][0],saveOldString); + } + + else if (ch == key_menu_enter) // phares 3/7/98 + { + saveStringEnter = 0; + if (savegamestrings[saveSlot][0]) + M_DoSave(saveSlot); + } + + else + { + ch = toupper(ch); + if (ch >= 32 && ch <= 127 && + saveCharIndex < SAVESTRINGSIZE-1 && + M_StringWidth(savegamestrings[saveSlot]) < (SAVESTRINGSIZE-2)*8) + { + savegamestrings[saveSlot][saveCharIndex++] = ch; + savegamestrings[saveSlot][saveCharIndex] = 0; + } + } + return true; + } + + // Take care of any messages that need input + + if (messageToPrint) { + if (messageNeedsInput == true && + !(ch == ' ' || ch == 'n' || ch == 'y' || ch == key_escape)) // phares + return false; + + menuactive = messageLastMenuActive; + messageToPrint = 0; + if (messageRoutine) + messageRoutine(ch); + + menuactive = false; + S_StartSound(NULL,sfx_swtchx); + return true; + } + + /* killough 2/22/98: add support for screenshot key: + * cph 2001/02/04: no need for this to be a gameaction, just do it + */ + if (ch == key_screenshot) + { + M_ScreenShot (); + // Don't eat the keypress in this case. See sf bug #1843280. + } + + // If there is no active menu displayed... + + if (!menuactive) { // phares + if (ch == key_autorun) // Autorun // V + { + autorun = !autorun; + return true; + } + + if (ch == key_help) // Help key + { + M_StartControlPanel (); + + currentMenu = &HelpDef; // killough 10/98: new help screen + + itemOn = 0; + S_StartSound(NULL,sfx_swtchn); + return true; + } + + if (ch == key_savegame) // Save Game + { + M_StartControlPanel(); + S_StartSound(NULL,sfx_swtchn); + M_SaveGame(0); + return true; + } + + if (ch == key_loadgame) // Load Game + { + M_StartControlPanel(); + S_StartSound(NULL,sfx_swtchn); + M_LoadGame(0); + return true; + } + + if (ch == key_soundvolume) // Sound Volume + { + M_StartControlPanel (); + currentMenu = &SoundDef; + itemOn = sfx_vol; + S_StartSound(NULL,sfx_swtchn); + return true; + } + + if (ch == key_quicksave) // Quicksave + { + S_StartSound(NULL,sfx_swtchn); + M_QuickSave(); + return true; + } + + if (ch == key_endgame) // End game + { + S_StartSound(NULL,sfx_swtchn); + M_EndGame(0); + return true; + } + + if (ch == key_messages) // Toggle messages + { + M_ChangeMessages(0); + S_StartSound(NULL,sfx_swtchn); + return true; + } + + if (ch == key_quickload) // Quickload + { + S_StartSound(NULL,sfx_swtchn); + M_QuickLoad(); + return true; + } + + if (ch == key_quit) // Quit DOOM + { + S_StartSound(NULL,sfx_swtchn); + M_QuitDOOM(0); + return true; + } + + if (ch == key_gamma) // gamma toggle + { + usegamma++; + if (usegamma > 4) + usegamma = 0; + players[consoleplayer].message = + usegamma == 0 ? s_GAMMALVL0 : + usegamma == 1 ? s_GAMMALVL1 : + usegamma == 2 ? s_GAMMALVL2 : + usegamma == 3 ? s_GAMMALVL3 : + s_GAMMALVL4; + V_SetPalette(0); + return true; + } + + + if (ch == key_zoomout) // zoom out + { + if ((automapmode & am_active) || chat_on) + return false; + M_SizeDisplay(0); + S_StartSound(NULL,sfx_stnmov); + return true; + } + + if (ch == key_zoomin) // zoom in + { // jff 2/23/98 + if ((automapmode & am_active) || chat_on) // allow + return false; // key_hud==key_zoomin + M_SizeDisplay(1); // ^ + S_StartSound(NULL,sfx_stnmov); // | + return true; // phares + } + + if (ch == key_hud) // heads-up mode + { + if ((automapmode & am_active) || chat_on) // jff 2/22/98 + return false; // HUD mode control + if (screenSize<8) // function on default F5 + while (screenSize<8 || !hud_displayed) // make hud visible + M_SizeDisplay(1); // when configuring it + else + { + hud_displayed = 1; //jff 3/3/98 turn hud on + hud_active = (hud_active+1)%3; // cycle hud_active + if (!hud_active) //jff 3/4/98 add distributed + { + hud_distributed = !hud_distributed; // to cycle + HU_MoveHud(); //jff 3/9/98 move it now to avoid glitch + } + } + return true; + } + + /* killough 10/98: allow key shortcut into Setup menu */ + if (ch == key_setup) { + M_StartControlPanel(); + S_StartSound(NULL,sfx_swtchn); + M_SetupNextMenu(&SetupDef); + return true; + } + } + // Pop-up Main menu? + + if (!menuactive) + { + if (ch == key_escape) // phares + { + M_StartControlPanel (); + S_StartSound(NULL,sfx_swtchn); + return true; + } + return false; + } + + // phares 3/26/98 - 4/11/98: + // Setup screen key processing + + if (setup_active) { + setup_menu_t* ptr1= current_setup_menu + set_menu_itemon; + setup_menu_t* ptr2 = NULL; + + // phares 4/19/98: + // Catch the response to the 'reset to default?' verification + // screen + + if (default_verify) + { + if (toupper(ch) == 'Y') { + M_ResetDefaults(); + default_verify = false; + M_SelectDone(ptr1); + } + else if (toupper(ch) == 'N') { + default_verify = false; + M_SelectDone(ptr1); + } + return true; + } + + // Common processing for some items + + if (setup_select) { // changing an entry + if (ch == key_menu_escape) // Exit key = no change + { + M_SelectDone(ptr1); // phares 4/17/98 + setup_gather = false; // finished gathering keys, if any + return true; + } + + if (ptr1->m_flags & S_YESNO) // yes or no setting? + { + if (ch == key_menu_enter) { + *ptr1->var.def->location.pi = !*ptr1->var.def->location.pi; // killough 8/15/98 + + // phares 4/14/98: + // If not in demoplayback, demorecording, or netgame, + // and there's a second variable in var2, set that + // as well + + // killough 8/15/98: add warning messages + + if (ptr1->m_flags & (S_LEVWARN | S_PRGWARN)) + warn_about_changes(ptr1->m_flags & // killough 10/98 + (S_LEVWARN | S_PRGWARN)); + else + M_UpdateCurrent(ptr1->var.def); + + if (ptr1->action) // killough 10/98 + ptr1->action(); + } + M_SelectDone(ptr1); // phares 4/17/98 + return true; + } + + if (ptr1->m_flags & S_CRITEM) + { + if (ch != key_menu_enter) + { + ch -= 0x30; // out of ascii + if (ch < 0 || ch > 9) + return true; // ignore + *ptr1->var.def->location.pi = ch; + } + if (ptr1->action) // killough 10/98 + ptr1->action(); + M_SelectDone(ptr1); // phares 4/17/98 + return true; + } + + if (ptr1->m_flags & S_NUM) // number? + { + if (setup_gather) { // gathering keys for a value? + /* killough 10/98: Allow negatives, and use a more + * friendly input method (e.g. don't clear value early, + * allow backspace, and return to original value if bad + * value is entered). + */ + if (ch == key_menu_enter) { + if (gather_count) { // Any input? + int value; + + gather_buffer[gather_count] = 0; + value = atoi(gather_buffer); // Integer value + + if ((ptr1->var.def->minvalue != UL && + value < ptr1->var.def->minvalue) || + (ptr1->var.def->maxvalue != UL && + value > ptr1->var.def->maxvalue)) + warn_about_changes(S_BADVAL); + else { + *ptr1->var.def->location.pi = value; + + /* killough 8/9/98: fix numeric vars + * killough 8/15/98: add warning message + */ + if (ptr1->m_flags & (S_LEVWARN | S_PRGWARN)) + warn_about_changes(ptr1->m_flags & + (S_LEVWARN | S_PRGWARN)); + else + M_UpdateCurrent(ptr1->var.def); + + if (ptr1->action) // killough 10/98 + ptr1->action(); + } + } + M_SelectDone(ptr1); // phares 4/17/98 + setup_gather = false; // finished gathering keys + return true; + } + + if (ch == key_menu_backspace && gather_count) { + gather_count--; + return true; + } + + if (gather_count >= MAXGATHER) + return true; + + if (!isdigit(ch) && ch != '-') + return true; // ignore + + /* killough 10/98: character-based numerical input */ + gather_buffer[gather_count++] = ch; + } + return true; + } + + if (ptr1->m_flags & S_CHOICE) // selection of choices? + { + if (ch == key_menu_left) { + if (ptr1->var.def->type == def_int) { + int value = *ptr1->var.def->location.pi; + + value = value - 1; + if ((ptr1->var.def->minvalue != UL && + value < ptr1->var.def->minvalue)) + value = ptr1->var.def->minvalue; + if ((ptr1->var.def->maxvalue != UL && + value > ptr1->var.def->maxvalue)) + value = ptr1->var.def->maxvalue; + if (*ptr1->var.def->location.pi != value) + S_StartSound(NULL,sfx_pstop); + *ptr1->var.def->location.pi = value; + } + if (ptr1->var.def->type == def_str) { + int old_value, value; + + old_value = M_IndexInChoices(*ptr1->var.def->location.ppsz, + ptr1->selectstrings); + value = old_value - 1; + if (value < 0) + value = 0; + if (old_value != value) + S_StartSound(NULL,sfx_pstop); + *ptr1->var.def->location.ppsz = ptr1->selectstrings[value]; + } + } + if (ch == key_menu_right) { + if (ptr1->var.def->type == def_int) { + int value = *ptr1->var.def->location.pi; + + value = value + 1; + if ((ptr1->var.def->minvalue != UL && + value < ptr1->var.def->minvalue)) + value = ptr1->var.def->minvalue; + if ((ptr1->var.def->maxvalue != UL && + value > ptr1->var.def->maxvalue)) + value = ptr1->var.def->maxvalue; + if (*ptr1->var.def->location.pi != value) + S_StartSound(NULL,sfx_pstop); + *ptr1->var.def->location.pi = value; + } + if (ptr1->var.def->type == def_str) { + int old_value, value; + + old_value = M_IndexInChoices(*ptr1->var.def->location.ppsz, + ptr1->selectstrings); + value = old_value + 1; + if (ptr1->selectstrings[value] == NULL) + value = old_value; + if (old_value != value) + S_StartSound(NULL,sfx_pstop); + *ptr1->var.def->location.ppsz = ptr1->selectstrings[value]; + } + } + if (ch == key_menu_enter) { + // phares 4/14/98: + // If not in demoplayback, demorecording, or netgame, + // and there's a second variable in var2, set that + // as well + + // killough 8/15/98: add warning messages + + if (ptr1->m_flags & (S_LEVWARN | S_PRGWARN)) + warn_about_changes(ptr1->m_flags & // killough 10/98 + (S_LEVWARN | S_PRGWARN)); + else + M_UpdateCurrent(ptr1->var.def); + + if (ptr1->action) // killough 10/98 + ptr1->action(); + M_SelectDone(ptr1); // phares 4/17/98 + } + return true; + } + + } + + // Key Bindings + + if (set_keybnd_active) // on a key binding setup screen + if (setup_select) // incoming key or button gets bound + { + if (ev->type == ev_joystick) + { + int oldbutton,group; + boolean search = true; + + if (!ptr1->m_joy) + return true; // not a legal action here (yet) + + // see if the button is already bound elsewhere. if so, you + // have to swap bindings so the action where it's currently + // bound doesn't go dead. Since there is more than one + // keybinding screen, you have to search all of them for + // any duplicates. You're only interested in the items + // that belong to the same group as the one you're changing. + + oldbutton = *ptr1->m_joy; + group = ptr1->m_group; + if (ev->data1 & 1) + ch = 0; + else if (ev->data1 & 2) + ch = 1; + else if (ev->data1 & 4) + ch = 2; + else if (ev->data1 & 8) + ch = 3; + else + return true; + for (i = 0 ; keys_settings[i] && search ; i++) + for (ptr2 = keys_settings[i] ; !(ptr2->m_flags & S_END) ; ptr2++) + if (ptr2->m_group == group && ptr1 != ptr2) + if (ptr2->m_flags & S_KEY && ptr2->m_joy) + if (*ptr2->m_joy == ch) + { + *ptr2->m_joy = oldbutton; + search = false; + break; + } + *ptr1->m_joy = ch; + } + else if (ev->type == ev_mouse) + { + int i,oldbutton,group; + boolean search = true; + + if (!ptr1->m_mouse) + return true; // not a legal action here (yet) + + // see if the button is already bound elsewhere. if so, you + // have to swap bindings so the action where it's currently + // bound doesn't go dead. Since there is more than one + // keybinding screen, you have to search all of them for + // any duplicates. You're only interested in the items + // that belong to the same group as the one you're changing. + + oldbutton = *ptr1->m_mouse; + group = ptr1->m_group; + if (ev->data1 & 1) + ch = 0; + else if (ev->data1 & 2) + ch = 1; + else if (ev->data1 & 4) + ch = 2; + else + return true; + for (i = 0 ; keys_settings[i] && search ; i++) + for (ptr2 = keys_settings[i] ; !(ptr2->m_flags & S_END) ; ptr2++) + if (ptr2->m_group == group && ptr1 != ptr2) + if (ptr2->m_flags & S_KEY && ptr2->m_mouse) + if (*ptr2->m_mouse == ch) + { + *ptr2->m_mouse = oldbutton; + search = false; + break; + } + *ptr1->m_mouse = ch; + } + else // keyboard key + { + int i,oldkey,group; + boolean search = true; + + // see if 'ch' is already bound elsewhere. if so, you have + // to swap bindings so the action where it's currently + // bound doesn't go dead. Since there is more than one + // keybinding screen, you have to search all of them for + // any duplicates. You're only interested in the items + // that belong to the same group as the one you're changing. + + // if you find that you're trying to swap with an action + // that has S_KEEP set, you can't bind ch; it's already + // bound to that S_KEEP action, and that action has to + // keep that key. + + oldkey = *ptr1->var.m_key; + group = ptr1->m_group; + for (i = 0 ; keys_settings[i] && search ; i++) + for (ptr2 = keys_settings[i] ; !(ptr2->m_flags & S_END) ; ptr2++) + if (ptr2->m_flags & (S_KEY|S_KEEP) && + ptr2->m_group == group && + ptr1 != ptr2) + if (*ptr2->var.m_key == ch) + { + if (ptr2->m_flags & S_KEEP) + return true; // can't have it! + *ptr2->var.m_key = oldkey; + search = false; + break; + } + *ptr1->var.m_key = ch; + } + + M_SelectDone(ptr1); // phares 4/17/98 + return true; + } + + // Weapons + + if (set_weapon_active) // on the weapons setup screen + if (setup_select) // changing an entry + { + if (ch != key_menu_enter) + { + ch -= '0'; // out of ascii + if (ch < 1 || ch > 9) + return true; // ignore + + // Plasma and BFG don't exist in shareware + // killough 10/98: allow it anyway, since this + // isn't the game itself, just setting preferences + + // see if 'ch' is already assigned elsewhere. if so, + // you have to swap assignments. + + // killough 11/98: simplified + + for (i = 0; (ptr2 = weap_settings[i]); i++) + for (; !(ptr2->m_flags & S_END); ptr2++) + if (ptr2->m_flags & S_WEAP && + *ptr2->var.def->location.pi == ch && ptr1 != ptr2) + { + *ptr2->var.def->location.pi = *ptr1->var.def->location.pi; + goto end; + } + end: + *ptr1->var.def->location.pi = ch; + } + + M_SelectDone(ptr1); // phares 4/17/98 + return true; + } + + // Automap + + if (set_auto_active) // on the automap setup screen + if (setup_select) // incoming key + { + if (ch == key_menu_down) + { + if (++color_palette_y == 16) + color_palette_y = 0; + S_StartSound(NULL,sfx_itemup); + return true; + } + + if (ch == key_menu_up) + { + if (--color_palette_y < 0) + color_palette_y = 15; + S_StartSound(NULL,sfx_itemup); + return true; + } + + if (ch == key_menu_left) + { + if (--color_palette_x < 0) + color_palette_x = 15; + S_StartSound(NULL,sfx_itemup); + return true; + } + + if (ch == key_menu_right) + { + if (++color_palette_x == 16) + color_palette_x = 0; + S_StartSound(NULL,sfx_itemup); + return true; + } + + if (ch == key_menu_enter) + { + *ptr1->var.def->location.pi = color_palette_x + 16*color_palette_y; + M_SelectDone(ptr1); // phares 4/17/98 + colorbox_active = false; + return true; + } + } + + // killough 10/98: consolidate handling into one place: + if (setup_select && + set_enemy_active | set_general_active | set_chat_active | + set_mess_active | set_status_active | set_compat_active) + { + if (ptr1->m_flags & S_STRING) // creating/editing a string? + { + if (ch == key_menu_backspace) // backspace and DEL + { + if (chat_string_buffer[chat_index] == 0) + { + if (chat_index > 0) + chat_string_buffer[--chat_index] = 0; + } + // shift the remainder of the text one char left + else + strcpy(&chat_string_buffer[chat_index], + &chat_string_buffer[chat_index+1]); + } + else if (ch == key_menu_left) // move cursor left + { + if (chat_index > 0) + chat_index--; + } + else if (ch == key_menu_right) // move cursor right + { + if (chat_string_buffer[chat_index] != 0) + chat_index++; + } + else if ((ch == key_menu_enter) || + (ch == key_menu_escape)) + { + *ptr1->var.def->location.ppsz = chat_string_buffer; + M_SelectDone(ptr1); // phares 4/17/98 + } + + // Adding a char to the text. Has to be a printable + // char, and you can't overrun the buffer. If the + // chat string gets larger than what the screen can hold, + // it is dealt with when the string is drawn (above). + + else if ((ch >= 32) && (ch <= 126)) + if ((chat_index+1) < CHAT_STRING_BFR_SIZE) + { + if (shiftdown) + ch = shiftxform[ch]; + if (chat_string_buffer[chat_index] == 0) + { + chat_string_buffer[chat_index++] = ch; + chat_string_buffer[chat_index] = 0; + } + else + chat_string_buffer[chat_index++] = ch; + } + return true; + } + + M_SelectDone(ptr1); // phares 4/17/98 + return true; + } + + // Not changing any items on the Setup screens. See if we're + // navigating the Setup menus or selecting an item to change. + + if (ch == key_menu_down) + { + ptr1->m_flags &= ~S_HILITE; // phares 4/17/98 + do + if (ptr1->m_flags & S_END) + { + set_menu_itemon = 0; + ptr1 = current_setup_menu; + } + else + { + set_menu_itemon++; + ptr1++; + } + while (ptr1->m_flags & S_SKIP); + M_SelectDone(ptr1); // phares 4/17/98 + return true; + } + + if (ch == key_menu_up) + { + ptr1->m_flags &= ~S_HILITE; // phares 4/17/98 + do + { + if (set_menu_itemon == 0) + do + set_menu_itemon++; + while(!((current_setup_menu + set_menu_itemon)->m_flags & S_END)); + set_menu_itemon--; + } + while((current_setup_menu + set_menu_itemon)->m_flags & S_SKIP); + M_SelectDone(current_setup_menu + set_menu_itemon); // phares 4/17/98 + return true; + } + + if (ch == key_menu_enter) + { + int flags = ptr1->m_flags; + + // You've selected an item to change. Highlight it, post a new + // message about what to do, and get ready to process the + // change. + // + // killough 10/98: use friendlier char-based input buffer + + if (flags & S_NUM) + { + setup_gather = true; + print_warning_about_changes = false; + gather_count = 0; + } + else if (flags & S_COLOR) + { + int color = *ptr1->var.def->location.pi; + + if (color < 0 || color > 255) // range check the value + color = 0; // 'no show' if invalid + + color_palette_x = *ptr1->var.def->location.pi & 15; + color_palette_y = *ptr1->var.def->location.pi >> 4; + colorbox_active = true; + } + else if (flags & S_STRING) + { + // copy chat string into working buffer; trim if needed. + // free the old chat string memory and replace it with + // the (possibly larger) new memory for editing purposes + // + // killough 10/98: fix bugs, simplify + + chat_string_buffer = malloc(CHAT_STRING_BFR_SIZE); + strncpy(chat_string_buffer, + *ptr1->var.def->location.ppsz, CHAT_STRING_BFR_SIZE); + + // guarantee null delimiter + chat_string_buffer[CHAT_STRING_BFR_SIZE-1] = 0; + + // set chat table pointer to working buffer + // and free old string's memory. + + free((char*)*ptr1->var.def->location.ppsz); + *ptr1->var.def->location.ppsz = chat_string_buffer; + chat_index = 0; // current cursor position in chat_string_buffer + } + else if (flags & S_RESET) + default_verify = true; + + ptr1->m_flags |= S_SELECT; + setup_select = true; + S_StartSound(NULL,sfx_itemup); + return true; + } + + if ((ch == key_menu_escape) || (ch == key_menu_backspace)) + { + if (ch == key_menu_escape) // Clear all menus + M_ClearMenus(); + else // key_menu_backspace = return to Setup Menu + if (currentMenu->prevMenu) + { + currentMenu = currentMenu->prevMenu; + itemOn = currentMenu->lastOn; + S_StartSound(NULL,sfx_swtchn); + } + ptr1->m_flags &= ~(S_HILITE|S_SELECT);// phares 4/19/98 + setup_active = false; + set_keybnd_active = false; + set_weapon_active = false; + set_status_active = false; + set_auto_active = false; + set_enemy_active = false; + set_mess_active = false; + set_chat_active = false; + colorbox_active = false; + default_verify = false; // phares 4/19/98 + set_general_active = false; // killough 10/98 + set_compat_active = false; // killough 10/98 + HU_Start(); // catch any message changes // phares 4/19/98 + S_StartSound(NULL,sfx_swtchx); + return true; + } + + // Some setup screens may have multiple screens. + // When there are multiple screens, m_prev and m_next items need to + // be placed on the appropriate screen tables so the user can + // move among the screens using the left and right arrow keys. + // The m_var1 field contains a pointer to the appropriate screen + // to move to. + + if (ch == key_menu_left) + { + ptr2 = ptr1; + do + { + ptr2++; + if (ptr2->m_flags & S_PREV) + { + ptr1->m_flags &= ~S_HILITE; + mult_screens_index--; + current_setup_menu = ptr2->var.menu; + set_menu_itemon = 0; + print_warning_about_changes = false; // killough 10/98 + while (current_setup_menu[set_menu_itemon++].m_flags&S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; + S_StartSound(NULL,sfx_pstop); // killough 10/98 + return true; + } + } + while (!(ptr2->m_flags & S_END)); + } + + if (ch == key_menu_right) + { + ptr2 = ptr1; + do + { + ptr2++; + if (ptr2->m_flags & S_NEXT) + { + ptr1->m_flags &= ~S_HILITE; + mult_screens_index++; + current_setup_menu = ptr2->var.menu; + set_menu_itemon = 0; + print_warning_about_changes = false; // killough 10/98 + while (current_setup_menu[set_menu_itemon++].m_flags&S_SKIP); + current_setup_menu[--set_menu_itemon].m_flags |= S_HILITE; + S_StartSound(NULL,sfx_pstop); // killough 10/98 + return true; + } + } + while (!(ptr2->m_flags & S_END)); + } + + } // End of Setup Screen processing + + // From here on, these navigation keys are used on the BIG FONT menus + // like the Main Menu. + + if (ch == key_menu_down) // phares 3/7/98 + { + do + { + if (itemOn+1 > currentMenu->numitems-1) + itemOn = 0; + else + itemOn++; + S_StartSound(NULL,sfx_pstop); + } + while(currentMenu->menuitems[itemOn].status==-1); + return true; + } + + if (ch == key_menu_up) // phares 3/7/98 + { + do + { + if (!itemOn) + itemOn = currentMenu->numitems-1; + else + itemOn--; + S_StartSound(NULL,sfx_pstop); + } + while(currentMenu->menuitems[itemOn].status==-1); + return true; + } + + if (ch == key_menu_left) // phares 3/7/98 + { + if (currentMenu->menuitems[itemOn].routine && + currentMenu->menuitems[itemOn].status == 2) + { + S_StartSound(NULL,sfx_stnmov); + currentMenu->menuitems[itemOn].routine(0); + } + return true; + } + + if (ch == key_menu_right) // phares 3/7/98 + { + if (currentMenu->menuitems[itemOn].routine && + currentMenu->menuitems[itemOn].status == 2) + { + S_StartSound(NULL,sfx_stnmov); + currentMenu->menuitems[itemOn].routine(1); + } + return true; + } + + if (ch == key_menu_enter) // phares 3/7/98 + { + if (currentMenu->menuitems[itemOn].routine && + currentMenu->menuitems[itemOn].status) + { + currentMenu->lastOn = itemOn; + if (currentMenu->menuitems[itemOn].status == 2) + { + currentMenu->menuitems[itemOn].routine(1); // right arrow + S_StartSound(NULL,sfx_stnmov); + } + else + { + currentMenu->menuitems[itemOn].routine(itemOn); + S_StartSound(NULL,sfx_pistol); + } + } + //jff 3/24/98 remember last skill selected + // killough 10/98 moved to skill-specific functions + return true; + } + + if (ch == key_menu_escape) // phares 3/7/98 + { + currentMenu->lastOn = itemOn; + M_ClearMenus (); + S_StartSound(NULL,sfx_swtchx); + return true; + } + + if (ch == key_menu_backspace) // phares 3/7/98 + { + currentMenu->lastOn = itemOn; + + // phares 3/30/98: + // add checks to see if you're in the extended help screens + // if so, stay with the same menu definition, but bump the + // index back one. if the index bumps back far enough ( == 0) + // then you can return to the Read_Thisn menu definitions + + if (currentMenu->prevMenu) + { + if (currentMenu == &ExtHelpDef) + { + if (--extended_help_index == 0) + { + currentMenu = currentMenu->prevMenu; + extended_help_index = 1; // reset + } + } + else + currentMenu = currentMenu->prevMenu; + itemOn = currentMenu->lastOn; + S_StartSound(NULL,sfx_swtchn); + } + return true; + } + + else + { + 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; + } + } + return false; +} + +// +// End of M_Responder +// +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// +// General Routines +// +// This displays the Main menu and gets the menu screens rolling. +// Plus a variety of routines that control the Big Font menu display. +// Plus some initialization for game-dependant situations. + +void M_StartControlPanel (void) +{ + // intro might call this repeatedly + + if (menuactive) + return; + + //jff 3/24/98 make default skill menu choice follow -skill or defaultskill + //from command line or config file + // + // killough 10/98: + // Fix to make "always floating" with menu selections, and to always follow + // defaultskill, instead of -skill. + + NewDef.lastOn = defaultskill - 1; + + default_verify = 0; // killough 10/98 + menuactive = 1; + currentMenu = &MainDef; // JDC + itemOn = currentMenu->lastOn; // JDC + print_warning_about_changes = false; // killough 11/98 +} + +// +// M_Drawer +// Called after the view has been rendered, +// but before it has been blitted. +// +// killough 9/29/98: Significantly reformatted source +// + +void M_Drawer (void) +{ + inhelpscreens = false; + + // Horiz. & Vertically center string and print it. + // killough 9/29/98: simplified code, removed 40-character width limit + if (messageToPrint) + { + /* cph - strdup string to writable memory */ + char *ms = strdup(messageString); + char *p = ms; + + int y = 100 - M_StringHeight(messageString)/2; + while (*p) + { + char *string = p, c; + while ((c = *p) && *p != '\n') + p++; + *p = 0; + M_WriteText(160 - M_StringWidth(string)/2, y, string); + y += hu_font[0].height; + if ((*p = c)) + p++; + } + free(ms); + } + else + if (menuactive) + { + int x,y,max,i; + + if (currentMenu->routine) + currentMenu->routine(); // call Draw routine + + // DRAW MENU + + x = currentMenu->x; + y = currentMenu->y; + max = currentMenu->numitems; + + for (i=0;imenuitems[i].name[0]) + V_DrawNamePatch(x,y,0,currentMenu->menuitems[i].name, + CR_DEFAULT, VPT_STRETCH); + y += LINEHEIGHT; + } + + // DRAW SKULL + + // CPhipps - patch drawing updated + V_DrawNamePatch(x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT,0, + skullName[whichSkull], CR_DEFAULT, VPT_STRETCH); + } +} + +// +// M_ClearMenus +// +// Called when leaving the menu screens for the real world + +void M_ClearMenus (void) +{ + menuactive = 0; + print_warning_about_changes = 0; // killough 8/15/98 + default_verify = 0; // killough 10/98 + + // if (!netgame && usergame && paused) + // sendpause = true; +} + +// +// M_SetupNextMenu +// +void M_SetupNextMenu(menu_t *menudef) +{ + currentMenu = menudef; + itemOn = currentMenu->lastOn; +} + +///////////////////////////// +// +// M_Ticker +// +void M_Ticker (void) +{ + if (--skullAnimCounter <= 0) + { + whichSkull ^= 1; + skullAnimCounter = 8; + } +} + +///////////////////////////// +// +// Message Routines +// + +void M_StartMessage (const char* string,void* routine,boolean input) +{ + messageLastMenuActive = menuactive; + messageToPrint = 1; + messageString = string; + messageRoutine = routine; + messageNeedsInput = input; + menuactive = true; + return; +} + +void M_StopMessage(void) +{ + menuactive = messageLastMenuActive; + messageToPrint = 0; +} + +///////////////////////////// +// +// Thermometer Routines +// + +// +// M_DrawThermo draws the thermometer graphic for Mouse Sensitivity, +// Sound Volume, etc. +// +// proff/nicolas 09/20/98 -- changed for hi-res +// CPhipps - patch drawing updated +// +void M_DrawThermo(int x,int y,int thermWidth,int thermDot ) + { + int xx; + int i; + /* + * Modification By Barry Mead to allow the Thermometer to have vastly + * larger ranges. (the thermWidth parameter can now have a value as + * large as 200. Modified 1-9-2000 Originally I used it to make + * the sensitivity range for the mouse better. It could however also + * be used to improve the dynamic range of music and sound affect + * volume controls for example. + */ + int horizScaler; //Used to allow more thermo range for mouse sensitivity. + thermWidth = (thermWidth > 200) ? 200 : thermWidth; //Clamp to 200 max + horizScaler = (thermWidth > 23) ? (200 / thermWidth) : 8; //Dynamic range + xx = x; + V_DrawNamePatch(xx, y, 0, "M_THERML", CR_DEFAULT, VPT_STRETCH); + xx += 8; + for (i=0;ix - 10, menu->y+item*LINEHEIGHT - 1, 0, + "M_CELL1", CR_DEFAULT, VPT_STRETCH); +} + +// +// Draw a full cell in the thermometer +// + +void M_DrawSelCell (menu_t* menu,int item) +{ + // CPhipps - patch drawing updated + V_DrawNamePatch(menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0, + "M_CELL2", CR_DEFAULT, VPT_STRETCH); +} + +///////////////////////////// +// +// String-drawing Routines +// + +// +// Find string width from hu_font chars +// + +int M_StringWidth(const char* string) +{ + int i, c, w = 0; + for (i = 0;(size_t)i < strlen(string);i++) + w += (c = toupper(string[i]) - HU_FONTSTART) < 0 || c >= HU_FONTSIZE ? + 4 : hu_font[c].width; + return w; +} + +// +// Find string height from hu_font chars +// + +int M_StringHeight(const char* string) +{ + int i, h, height = h = hu_font[0].height; + for (i = 0;string[i];i++) // killough 1/31/98 + if (string[i] == '\n') + h += height; + return h; +} + +// +// Write a string using the hu_font +// +void M_WriteText (int x,int y,const char* string) +{ + int w; + const char* ch; + int c; + int cx; + int cy; + + ch = string; + cx = x; + cy = y; + + while(1) { + c = *ch++; + if (!c) + break; + if (c == '\n') { + cx = x; + cy += 12; + continue; + } + + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c>= HU_FONTSIZE) { + cx += 4; + continue; + } + + w = hu_font[c].width; + if (cx+w > SCREENWIDTH) + break; + // proff/nicolas 09/20/98 -- changed for hi-res + // CPhipps - patch drawing updated + V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH); + cx+=w; + } +} + +///////////////////////////// +// +// Initialization Routines to take care of one-time setup +// + +// phares 4/08/98: +// M_InitHelpScreen() clears the weapons from the HELP +// screen that don't exist in this version of the game. + +void M_InitHelpScreen(void) +{ + setup_menu_t* src; + + src = helpstrings; + while (!(src->m_flags & S_END)) { + + if ((strncmp(src->m_text,"PLASMA",6) == 0) && (gamemode == shareware)) + src->m_flags = S_SKIP; // Don't show setting or item + if ((strncmp(src->m_text,"BFG",3) == 0) && (gamemode == shareware)) + src->m_flags = S_SKIP; // Don't show setting or item + if ((strncmp(src->m_text,"SSG",3) == 0) && (gamemode != commercial)) + src->m_flags = S_SKIP; // Don't show setting or item + src++; + } +} + +// +// M_Init +// +void M_Init(void) +{ + M_InitDefaults(); // killough 11/98 + currentMenu = &MainDef; + menuactive = 0; + itemOn = currentMenu->lastOn; + whichSkull = 0; + skullAnimCounter = 10; + screenSize = screenblocks - 3; + messageToPrint = 0; + messageString = NULL; + messageLastMenuActive = menuactive; + quickSaveSlot = -1; + + // Here we could catch other version dependencies, + // like HELP1/2, and four episodes. + + 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. + 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 registered: + // Episode 2 and 3 are handled, + // branching to an ad screen. + + // killough 2/21/98: Fix registered Doom help screen + // killough 10/98: moved to second screen, moved up to the top + ReadDef2.y = 15; + + case shareware: + // We need to remove the fourth episode. + EpiDef.numitems--; + break; + case retail: + // We are fine. + default: + break; + } + + M_InitHelpScreen(); // init the help screen // phares 4/08/98 + M_InitExtendedHelp(); // init extended help screens // phares 3/30/98 + + M_ChangeDemoSmoothTurns(); +} + +// +// End of General Routines +// +///////////////////////////////////////////////////////////////////////////// diff --git a/src/m_menu.h b/src/m_menu.h new file mode 100644 index 0000000..7a391fd --- /dev/null +++ b/src/m_menu.h @@ -0,0 +1,182 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Menu widget stuff, episode selection and such. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __M_MENU__ +#define __M_MENU__ + +#include "d_event.h" + +// +// MENUS +// +// Called by main loop, +// saves config file and calls I_Quit when user exits. +// Even when the menu is not displayed, +// this can resize the view and change game parameters. +// Does all the real work of the menu interaction. + +boolean M_Responder (event_t *ev); + +// Called by main loop, +// only used for menu (skull cursor) animation. + +void M_Ticker (void); + +// Called by main loop, +// draws the menus directly into the screen buffer. + +void M_Drawer (void); + +// Called by D_DoomMain, +// loads the config file. + +void M_Init (void); + +// Called by intro code to force menu up upon a keypress, +// does nothing if menu is already up. + +void M_StartControlPanel (void); + +void M_ForcedLoadGame(const char *msg); // killough 5/15/98: forced loadgames + +void M_Trans(void); // killough 11/98: reset translucency + +void M_ResetMenu(void); // killough 11/98: reset main menu ordering + +void M_DrawCredits(void); // killough 11/98 + +/* killough 8/15/98: warn about changes not being committed until next game */ +#define warn_about_changes(x) (warning_about_changes=(x), \ + print_warning_about_changes = 2) + +extern int warning_about_changes, print_warning_about_changes; + +/**************************** + * + * The following #defines are for the m_flags field of each item on every + * Setup Screen. They can be OR'ed together where appropriate + */ + +#define S_HILITE 0x1 // Cursor is sitting on this item +#define S_SELECT 0x2 // We're changing this item +#define S_TITLE 0x4 // Title item +#define S_YESNO 0x8 // Yes or No item +#define S_CRITEM 0x10 // Message color +#define S_COLOR 0x20 // Automap color +#define S_CHAT 0x40 // Chat String +#define S_RESET 0x80 // Reset to Defaults Button +#define S_PREV 0x100 // Previous menu exists +#define S_NEXT 0x200 // Next menu exists +#define S_KEY 0x400 // Key Binding +#define S_WEAP 0x800 // Weapon # +#define S_NUM 0x1000 // Numerical item +#define S_SKIP 0x2000 // Cursor can't land here +#define S_KEEP 0x4000 // Don't swap key out +#define S_END 0x8000 // Last item in list (dummy) +#define S_LEVWARN 0x10000// killough 8/30/98: Always warn about pending change +#define S_PRGWARN 0x20000// killough 10/98: Warn about change until next run +#define S_BADVAL 0x40000// killough 10/98: Warn about bad value +#define S_FILE 0x80000// killough 10/98: Filenames +#define S_LEFTJUST 0x100000 // killough 10/98: items which are left-justified +#define S_CREDIT 0x200000 // killough 10/98: credit +#define S_BADVID 0x400000 // killough 12/98: video mode change error +#define S_CHOICE 0x800000 // this item has several values + +/* S_SHOWDESC = the set of items whose description should be displayed + * S_SHOWSET = the set of items whose setting should be displayed + * S_STRING = the set of items whose settings are strings -- killough 10/98: + * S_HASDEFPTR = the set of items whose var field points to default array + */ + +#define S_SHOWDESC (S_TITLE|S_YESNO|S_CRITEM|S_COLOR|S_CHAT|S_RESET|S_PREV|S_NEXT|S_KEY|S_WEAP|S_NUM|S_FILE|S_CREDIT|S_CHOICE) + +#define S_SHOWSET (S_YESNO|S_CRITEM|S_COLOR|S_CHAT|S_KEY|S_WEAP|S_NUM|S_FILE|S_CHOICE) + +#define S_STRING (S_CHAT|S_FILE) + +#define S_HASDEFPTR (S_STRING|S_YESNO|S_NUM|S_WEAP|S_COLOR|S_CRITEM|S_CHOICE) + +/**************************** + * + * The setup_group enum is used to show which 'groups' keys fall into so + * that you can bind a key differently in each 'group'. + */ + +typedef enum { + m_null, // Has no meaning; not applicable + m_scrn, // A key can not be assigned to more than one action + m_map, // in the same group. A key can be assigned to one + m_menu, // action in one group, and another action in another. +} setup_group; + +/**************************** + * + * phares 4/17/98: + * State definition for each item. + * This is the definition of the structure for each setup item. Not all + * fields are used by all items. + * + * A setup screen is defined by an array of these items specific to + * that screen. + * + * killough 11/98: + * + * Restructured to allow simpler table entries, + * and to Xref with defaults[] array in m_misc.c. + * Moved from m_menu.c to m_menu.h so that m_misc.c can use it. + */ + +typedef struct setup_menu_s +{ + const char *m_text; /* text to display */ + int m_flags; /* phares 4/17/98: flag bits S_* (defined above) */ + setup_group m_group; /* Group */ + short m_x; /* screen x position (left is 0) */ + short m_y; /* screen y position (top is 0) */ + + union /* killough 11/98: The first field is a union of several types */ + { + const void *var; /* generic variable */ + int *m_key; /* key value, or 0 if not shown */ + const char *name; /* name */ + struct default_s *def; /* default[] table entry */ + struct setup_menu_s *menu; /* next or prev menu */ + } var; + + int *m_mouse; /* mouse button value, or 0 if not shown */ + int *m_joy; /* joystick button value, or 0 if not shown */ + void (*action)(void); /* killough 10/98: function to call after changing */ + const char **selectstrings; /* list of strings for choice value */ +} setup_menu_t; + +#endif diff --git a/src/m_misc.c b/src/m_misc.c new file mode 100644 index 0000000..a393587 --- /dev/null +++ b/src/m_misc.c @@ -0,0 +1,1081 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Main loop menu stuff. + * Default Config File. + * PCX Screenshots. + * + *-----------------------------------------------------------------------------*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef _MSC_VER +#include +#endif +#include +#include + +#include "doomstat.h" +#include "m_argv.h" +#include "g_game.h" +#include "m_menu.h" +#include "am_map.h" +#include "w_wad.h" +#include "i_system.h" +#include "i_sound.h" +#include "i_video.h" +#include "v_video.h" +#include "hu_stuff.h" +#include "st_stuff.h" +#include "dstrings.h" +#include "m_misc.h" +#include "s_sound.h" +#include "sounds.h" +#include "i_joy.h" +#include "lprintf.h" +#include "d_main.h" +#include "r_draw.h" +#include "r_demo.h" +#include "r_fps.h" + +/* cph - disk icon not implemented */ +static inline void I_BeginRead(void) {} +static inline void I_EndRead(void) {} + +/* + * M_WriteFile + * + * killough 9/98: rewritten to use stdio and to flash disk icon + */ + +boolean M_WriteFile(char const *name, void *source, int length) +{ + FILE *fp; + + errno = 0; + + if (!(fp = fopen(name, "wb"))) // Try opening file + return 0; // Could not open file for writing + + I_BeginRead(); // Disk icon on + length = fwrite(source, 1, length, fp) == (size_t)length; // Write data + fclose(fp); + I_EndRead(); // Disk icon off + + if (!length) // Remove partially written file + remove(name); + + return length; +} + +/* + * M_ReadFile + * + * killough 9/98: rewritten to use stdio and to flash disk icon + */ + +int M_ReadFile(char const *name, byte **buffer) +{ + FILE *fp; + + if ((fp = fopen(name, "rb"))) + { + size_t length; + + I_BeginRead(); + fseek(fp, 0, SEEK_END); + length = ftell(fp); + fseek(fp, 0, SEEK_SET); + *buffer = Z_Malloc(length, PU_STATIC, 0); + if (fread(*buffer, 1, length, fp) == length) + { + fclose(fp); + I_EndRead(); + return length; + } + fclose(fp); + } + + /* cph 2002/08/10 - this used to return 0 on error, but that's ambiguous, + * because we could have a legit 0-length file. So make it -1. */ + return -1; +} + +// +// DEFAULTS +// + +int usemouse; +boolean precache = true; /* if true, load all graphics at start */ + +extern int mousebfire; +extern int mousebstrafe; +extern int mousebforward; + +extern int viewwidth; +extern int viewheight; +#ifdef GL_DOOM +extern int gl_nearclip; +extern int gl_colorbuffer_bits; +extern int gl_depthbuffer_bits; +extern char *gl_tex_filter_string; +extern char *gl_tex_format_string; +extern int gl_drawskys; +extern int gl_sortsprites; +extern int gl_use_paletted_texture; +extern int gl_use_shared_texture_palette; +extern int gl_sprite_offset; +#endif + +extern int realtic_clock_rate; // killough 4/13/98: adjustable timer +extern int tran_filter_pct; // killough 2/21/98 + +extern int screenblocks; +extern int showMessages; + +#ifndef DJGPP +int mus_pause_opt; // 0 = kill music, 1 = pause, 2 = continue +#endif + +extern const char* chat_macros[]; + +extern int endoom_mode; + +extern const char* S_music_files[]; // cournia + +/* cph - Some MBF stuff parked here for now + * killough 10/98 + */ +int map_point_coordinates; + +default_t defaults[] = +{ + {"Misc settings",{NULL},{0},UL,UL,def_none,ss_none}, + {"default_compatibility_level",{(int*)&default_compatibility_level}, + {-1},-1,MAX_COMPATIBILITY_LEVEL-1, + def_int,ss_none}, // compatibility level" - CPhipps + {"realtic_clock_rate",{&realtic_clock_rate},{100},0,UL, + def_int,ss_none}, // percentage of normal speed (35 fps) realtic clock runs at + {"max_player_corpse", {&bodyquesize}, {32},-1,UL, // killough 2/8/98 + def_int,ss_none}, // number of dead bodies in view supported (-1 = no limit) + {"flashing_hom",{&flashing_hom},{0},0,1, + def_bool,ss_none}, // killough 10/98 - enable flashing HOM indicator + {"demo_insurance",{&default_demo_insurance},{2},0,2, // killough 3/31/98 + def_int,ss_none}, // 1=take special steps ensuring demo sync, 2=only during recordings + {"endoom_mode", {&endoom_mode},{5},0,7, // CPhipps - endoom flags + def_hex, ss_none}, // 0, +1 for colours, +2 for non-ascii chars, +4 for skip-last-line + {"level_precache",{(int*)&precache},{0},0,1, + def_bool,ss_none}, // precache level data? + {"demo_smoothturns", {&demo_smoothturns}, {0},0,1, + def_bool,ss_stat}, + {"demo_smoothturnsfactor", {&demo_smoothturnsfactor}, {6},1,SMOOTH_PLAYING_MAXFACTOR, + def_int,ss_stat}, + + {"Files",{NULL},{0},UL,UL,def_none,ss_none}, + /* cph - MBF-like wad/deh/bex autoload code */ + {"wadfile_1",{NULL,&wad_files[0]},{0,""},UL,UL,def_str,ss_none}, + {"wadfile_2",{NULL,&wad_files[1]},{0,""},UL,UL,def_str,ss_none}, + {"dehfile_1",{NULL,&deh_files[0]},{0,""},UL,UL,def_str,ss_none}, + {"dehfile_2",{NULL,&deh_files[1]},{0,""},UL,UL,def_str,ss_none}, + + {"Game settings",{NULL},{0},UL,UL,def_none,ss_none}, + {"default_skill",{&defaultskill},{3},1,5, // jff 3/24/98 allow default skill setting + def_int,ss_none}, // selects default skill 1=TYTD 2=NTR 3=HMP 4=UV 5=NM + {"weapon_recoil",{&default_weapon_recoil},{0},0,1, + def_bool,ss_weap, &weapon_recoil}, + /* killough 10/98 - toggle between SG/SSG and Fist/Chainsaw */ + {"doom_weapon_toggles",{&doom_weapon_toggles}, {1}, 0, 1, + def_bool, ss_weap }, + {"player_bobbing",{&default_player_bobbing},{1},0,1, // phares 2/25/98 + def_bool,ss_weap, &player_bobbing}, + {"monsters_remember",{&default_monsters_remember},{1},0,1, // killough 3/1/98 + def_bool,ss_enem, &monsters_remember}, + /* MBF AI enhancement options */ + {"monster_infighting",{&default_monster_infighting}, {1}, 0, 1, + def_bool, ss_enem, &monster_infighting}, + {"monster_backing",{&default_monster_backing}, {0}, 0, 1, + def_bool, ss_enem, &monster_backing}, + {"monster_avoid_hazards",{&default_monster_avoid_hazards}, {1}, 0, 1, + def_bool, ss_enem, &monster_avoid_hazards}, + {"monkeys",{&default_monkeys}, {0}, 0, 1, + def_bool, ss_enem, &monkeys}, + {"monster_friction",{&default_monster_friction}, {1}, 0, 1, + def_bool, ss_enem, &monster_friction}, + {"help_friends",{&default_help_friends}, {1}, 0, 1, + def_bool, ss_enem, &help_friends}, + {"allow_pushers",{&default_allow_pushers},{1},0,1, + def_bool,ss_weap, &allow_pushers}, + {"variable_friction",{&default_variable_friction},{1},0,1, + def_bool,ss_weap, &variable_friction}, +#ifdef DOGS + {"player_helpers",{&default_dogs}, {0}, 0, 3, + def_bool, ss_enem }, + {"friend_distance",{&default_distfriend}, {128}, 0, 999, + def_int, ss_enem, &distfriend}, + {"dog_jumping",{&default_dog_jumping}, {1}, 0, 1, + def_bool, ss_enem, &dog_jumping}, +#endif + /* End of MBF AI extras */ + + {"sts_always_red",{&sts_always_red},{1},0,1, // no color changes on status bar + def_bool,ss_stat}, + {"sts_pct_always_gray",{&sts_pct_always_gray},{0},0,1, // 2/23/98 chg default + def_bool,ss_stat}, // makes percent signs on status bar always gray + {"sts_traditional_keys",{&sts_traditional_keys},{0},0,1, // killough 2/28/98 + def_bool,ss_stat}, // disables doubled card and skull key display on status bar + {"show_messages",{&showMessages},{1},0,1, + def_bool,ss_none}, // enables message display + {"autorun",{&autorun},{0},0,1, // killough 3/6/98: preserve autorun across games + def_bool,ss_none}, + + {"Compatibility settings",{NULL},{0},UL,UL,def_none,ss_none}, + {"comp_zombie",{&default_comp[comp_zombie]},{0},0,1,def_bool,ss_comp,&comp[comp_zombie]}, + {"comp_infcheat",{&default_comp[comp_infcheat]},{0},0,1,def_bool,ss_comp,&comp[comp_infcheat]}, + {"comp_stairs",{&default_comp[comp_stairs]},{0},0,1,def_bool,ss_comp,&comp[comp_stairs]}, + {"comp_telefrag",{&default_comp[comp_telefrag]},{0},0,1,def_bool,ss_comp,&comp[comp_telefrag]}, + {"comp_dropoff",{&default_comp[comp_dropoff]},{0},0,1,def_bool,ss_comp,&comp[comp_dropoff]}, + {"comp_falloff",{&default_comp[comp_falloff]},{0},0,1,def_bool,ss_comp,&comp[comp_falloff]}, + {"comp_staylift",{&default_comp[comp_staylift]},{0},0,1,def_bool,ss_comp,&comp[comp_staylift]}, + {"comp_doorstuck",{&default_comp[comp_doorstuck]},{0},0,1,def_bool,ss_comp,&comp[comp_doorstuck]}, + {"comp_pursuit",{&default_comp[comp_pursuit]},{0},0,1,def_bool,ss_comp,&comp[comp_pursuit]}, + {"comp_vile",{&default_comp[comp_vile]},{0},0,1,def_bool,ss_comp,&comp[comp_vile]}, + {"comp_pain",{&default_comp[comp_pain]},{0},0,1,def_bool,ss_comp,&comp[comp_pain]}, + {"comp_skull",{&default_comp[comp_skull]},{0},0,1,def_bool,ss_comp,&comp[comp_skull]}, + {"comp_blazing",{&default_comp[comp_blazing]},{0},0,1,def_bool,ss_comp,&comp[comp_blazing]}, + {"comp_doorlight",{&default_comp[comp_doorlight]},{0},0,1,def_bool,ss_comp,&comp[comp_doorlight]}, + {"comp_god",{&default_comp[comp_god]},{0},0,1,def_bool,ss_comp,&comp[comp_god]}, + {"comp_skymap",{&default_comp[comp_skymap]},{0},0,1,def_bool,ss_comp,&comp[comp_skymap]}, + {"comp_floors",{&default_comp[comp_floors]},{0},0,1,def_bool,ss_comp,&comp[comp_floors]}, + {"comp_model",{&default_comp[comp_model]},{0},0,1,def_bool,ss_comp,&comp[comp_model]}, + {"comp_zerotags",{&default_comp[comp_zerotags]},{0},0,1,def_bool,ss_comp,&comp[comp_zerotags]}, + {"comp_moveblock",{&default_comp[comp_moveblock]},{0},0,1,def_bool,ss_comp,&comp[comp_moveblock]}, + {"comp_sound",{&default_comp[comp_sound]},{0},0,1,def_bool,ss_comp,&comp[comp_sound]}, + {"comp_666",{&default_comp[comp_666]},{0},0,1,def_bool,ss_comp,&comp[comp_666]}, + {"comp_soul",{&default_comp[comp_soul]},{0},0,1,def_bool,ss_comp,&comp[comp_soul]}, + {"comp_maskedanim",{&default_comp[comp_maskedanim]},{0},0,1,def_bool,ss_comp,&comp[comp_maskedanim]}, + + {"Sound settings",{NULL},{0},UL,UL,def_none,ss_none}, + {"sound_card",{&snd_card},{-1},-1,7, // jff 1/18/98 allow Allegro drivers + def_int,ss_none}, // select sounds driver (DOS), -1 is autodetect, 0 is none; in Linux, non-zero enables sound + {"music_card",{&mus_card},{-1},-1,9, // to be set, -1 = autodetect + def_int,ss_none}, // select music driver (DOS), -1 is autodetect, 0 is none"; in Linux, non-zero enables music + {"pitched_sounds",{&pitched_sounds},{0},0,1, // killough 2/21/98 + def_bool,ss_none}, // enables variable pitch in sound effects (from id's original code) + {"samplerate",{&snd_samplerate},{22050},11025,48000, def_int,ss_none}, + {"sfx_volume",{&snd_SfxVolume},{8},0,15, def_int,ss_none}, + {"music_volume",{&snd_MusicVolume},{8},0,15, def_int,ss_none}, + {"mus_pause_opt",{&mus_pause_opt},{2},0,2, // CPhipps - music pausing + def_int, ss_none}, // 0 = kill music when paused, 1 = pause music, 2 = let music continue + {"snd_channels",{&default_numChannels},{8},1,32, + def_int,ss_none}, // number of audio events simultaneously // killough + + {"Video settings",{NULL},{0},UL,UL,def_none,ss_none}, +#ifdef GL_DOOM + #ifdef _MSC_VER + {"videomode",{NULL, &default_videomode},{0,"gl"},UL,UL,def_str,ss_none}, + #else + {"videomode",{NULL, &default_videomode},{0,"8"},UL,UL,def_str,ss_none}, + #endif +#else + {"videomode",{NULL, &default_videomode},{0,"8"},UL,UL,def_str,ss_none}, +#endif + /* 640x480 default resolution */ + {"screen_width",{&desired_screenwidth},{640}, 320, MAX_SCREENWIDTH, + def_int,ss_none}, + {"screen_height",{&desired_screenheight},{480},200,MAX_SCREENHEIGHT, + def_int,ss_none}, + {"use_fullscreen",{&use_fullscreen},{1},0,1, /* proff 21/05/2000 */ + def_bool,ss_none}, +#ifndef DISABLE_DOUBLEBUFFER + {"use_doublebuffer",{&use_doublebuffer},{1},0,1, // proff 2001-7-4 + def_bool,ss_none}, // enable doublebuffer to avoid display tearing (fullscreen) +#endif + {"translucency",{&default_translucency},{1},0,1, // phares + def_bool,ss_none}, // enables translucency + {"tran_filter_pct",{&tran_filter_pct},{66},0,100, // killough 2/21/98 + def_int,ss_none}, // set percentage of foreground/background translucency mix + {"screenblocks",{&screenblocks},{10},3,11, // killough 2/21/98: default to 10 + def_int,ss_none}, + {"usegamma",{&usegamma},{3},0,4, //jff 3/6/98 fix erroneous upper limit in range + def_int,ss_none}, // gamma correction level // killough 1/18/98 + {"uncapped_framerate", {&movement_smooth}, {0},0,1, + def_bool,ss_stat}, + {"filter_wall",{(int*)&drawvars.filterwall},{RDRAW_FILTER_POINT}, + RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_none}, + {"filter_floor",{(int*)&drawvars.filterfloor},{RDRAW_FILTER_POINT}, + RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_none}, + {"filter_sprite",{(int*)&drawvars.filtersprite},{RDRAW_FILTER_POINT}, + RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_none}, + {"filter_z",{(int*)&drawvars.filterz},{RDRAW_FILTER_POINT}, + RDRAW_FILTER_POINT, RDRAW_FILTER_LINEAR, def_int,ss_none}, + {"filter_patch",{(int*)&drawvars.filterpatch},{RDRAW_FILTER_POINT}, + RDRAW_FILTER_POINT, RDRAW_FILTER_ROUNDED, def_int,ss_none}, + {"filter_threshold",{(int*)&drawvars.mag_threshold},{49152}, + 0, UL, def_int,ss_none}, + {"sprite_edges",{(int*)&drawvars.sprite_edges},{RDRAW_MASKEDCOLUMNEDGE_SQUARE}, + RDRAW_MASKEDCOLUMNEDGE_SQUARE, RDRAW_MASKEDCOLUMNEDGE_SLOPED, def_int,ss_none}, + {"patch_edges",{(int*)&drawvars.patch_edges},{RDRAW_MASKEDCOLUMNEDGE_SQUARE}, + RDRAW_MASKEDCOLUMNEDGE_SQUARE, RDRAW_MASKEDCOLUMNEDGE_SLOPED, def_int,ss_none}, + +#ifdef GL_DOOM + {"OpenGL settings",{NULL},{0},UL,UL,def_none,ss_none}, + {"gl_nearclip",{&gl_nearclip},{5},0,UL, + def_int,ss_none}, /* near clipping plane pos */ + {"gl_colorbuffer_bits",{&gl_colorbuffer_bits},{16},16,32, + def_int,ss_none}, + {"gl_depthbuffer_bits",{&gl_depthbuffer_bits},{16},16,32, + def_int,ss_none}, + {"gl_tex_filter_string", {NULL,&gl_tex_filter_string}, {0,"GL_LINEAR"},UL,UL, + def_str,ss_none}, + {"gl_tex_format_string", {NULL,&gl_tex_format_string}, {0,"GL_RGB5_A1"},UL,UL, + def_str,ss_none}, + {"gl_drawskys",{&gl_drawskys},{1},0,1, + def_bool,ss_none}, + {"gl_sortsprites",{&gl_sortsprites},{1},0,1, + def_bool,ss_none}, + {"gl_use_paletted_texture",{&gl_use_paletted_texture},{0},0,1, + def_bool,ss_none}, + {"gl_use_shared_texture_palette",{&gl_use_shared_texture_palette},{0},0,1, + def_bool,ss_none}, +#ifdef GL_DOOM + {"gl_sprite_offset",{&gl_sprite_offset},{0}, 0, 5, + def_int,ss_none}, // amount to bring items out of floor (GL) Mead 8/13/03 +#endif +#endif + + {"Mouse settings",{NULL},{0},UL,UL,def_none,ss_none}, + {"use_mouse",{&usemouse},{1},0,1, + def_bool,ss_none}, // enables use of mouse with DOOM + //jff 4/3/98 allow unlimited sensitivity + {"mouse_sensitivity_horiz",{&mouseSensitivity_horiz},{10},0,UL, + def_int,ss_none}, /* adjust horizontal (x) mouse sensitivity killough/mead */ + //jff 4/3/98 allow unlimited sensitivity + {"mouse_sensitivity_vert",{&mouseSensitivity_vert},{10},0,UL, + def_int,ss_none}, /* adjust vertical (y) mouse sensitivity killough/mead */ + //jff 3/8/98 allow -1 in mouse bindings to disable mouse function + {"mouseb_fire",{&mousebfire},{0},-1,MAX_MOUSEB, + def_int,ss_keys}, // mouse button number to use for fire + {"mouseb_strafe",{&mousebstrafe},{1},-1,MAX_MOUSEB, + def_int,ss_keys}, // mouse button number to use for strafing + {"mouseb_forward",{&mousebforward},{2},-1,MAX_MOUSEB, + def_int,ss_keys}, // mouse button number to use for forward motion + //jff 3/8/98 end of lower range change for -1 allowed in mouse binding + +// For key bindings, the values stored in the key_* variables // phares +// are the internal Doom Codes. The values stored in the default.cfg +// file are the keyboard codes. +// CPhipps - now they're the doom codes, so default.cfg can be portable + + {"Key bindings",{NULL},{0},UL,UL,def_none,ss_none}, + {"key_right", {&key_right}, {KEYD_RIGHTARROW}, + 0,MAX_KEY,def_key,ss_keys}, // key to turn right + {"key_left", {&key_left}, {KEYD_LEFTARROW} , + 0,MAX_KEY,def_key,ss_keys}, // key to turn left + {"key_up", {&key_up}, {KEYD_UPARROW} , + 0,MAX_KEY,def_key,ss_keys}, // key to move forward + {"key_down", {&key_down}, {KEYD_DOWNARROW}, + 0,MAX_KEY,def_key,ss_keys}, // key to move backward + {"key_menu_right", {&key_menu_right}, {KEYD_RIGHTARROW},// phares 3/7/98 + 0,MAX_KEY,def_key,ss_keys}, // key to move right in a menu // | + {"key_menu_left", {&key_menu_left}, {KEYD_LEFTARROW} ,// V + 0,MAX_KEY,def_key,ss_keys}, // key to move left in a menu + {"key_menu_up", {&key_menu_up}, {KEYD_UPARROW} , + 0,MAX_KEY,def_key,ss_keys}, // key to move up in a menu + {"key_menu_down", {&key_menu_down}, {KEYD_DOWNARROW} , + 0,MAX_KEY,def_key,ss_keys}, // key to move down in a menu + {"key_menu_backspace",{&key_menu_backspace},{KEYD_BACKSPACE} , + 0,MAX_KEY,def_key,ss_keys}, // delete key in a menu + {"key_menu_escape", {&key_menu_escape}, {KEYD_ESCAPE} , + 0,MAX_KEY,def_key,ss_keys}, // key to leave a menu , // phares 3/7/98 + {"key_menu_enter", {&key_menu_enter}, {KEYD_ENTER} , + 0,MAX_KEY,def_key,ss_keys}, // key to select from menu + {"key_strafeleft", {&key_strafeleft}, {','} , + 0,MAX_KEY,def_key,ss_keys}, // key to strafe left + {"key_straferight", {&key_straferight}, {'.'} , + 0,MAX_KEY,def_key,ss_keys}, // key to strafe right + + {"key_fire", {&key_fire}, {KEYD_RCTRL} , + 0,MAX_KEY,def_key,ss_keys}, // duh + {"key_use", {&key_use}, {' '} , + 0,MAX_KEY,def_key,ss_keys}, // key to open a door, use a switch + {"key_strafe", {&key_strafe}, {KEYD_RALT} , + 0,MAX_KEY,def_key,ss_keys}, // key to use with arrows to strafe + {"key_speed", {&key_speed}, {KEYD_RSHIFT} , + 0,MAX_KEY,def_key,ss_keys}, // key to run + + {"key_savegame", {&key_savegame}, {KEYD_F2} , + 0,MAX_KEY,def_key,ss_keys}, // key to save current game + {"key_loadgame", {&key_loadgame}, {KEYD_F3} , + 0,MAX_KEY,def_key,ss_keys}, // key to restore from saved games + {"key_soundvolume", {&key_soundvolume}, {KEYD_F4} , + 0,MAX_KEY,def_key,ss_keys}, // key to bring up sound controls + {"key_hud", {&key_hud}, {KEYD_F5} , + 0,MAX_KEY,def_key,ss_keys}, // key to adjust HUD + {"key_quicksave", {&key_quicksave}, {KEYD_F6} , + 0,MAX_KEY,def_key,ss_keys}, // key to to quicksave + {"key_endgame", {&key_endgame}, {KEYD_F7} , + 0,MAX_KEY,def_key,ss_keys}, // key to end the game + {"key_messages", {&key_messages}, {KEYD_F8} , + 0,MAX_KEY,def_key,ss_keys}, // key to toggle message enable + {"key_quickload", {&key_quickload}, {KEYD_F9} , + 0,MAX_KEY,def_key,ss_keys}, // key to load from quicksave + {"key_quit", {&key_quit}, {KEYD_F10} , + 0,MAX_KEY,def_key,ss_keys}, // key to quit game + {"key_gamma", {&key_gamma}, {KEYD_F11} , + 0,MAX_KEY,def_key,ss_keys}, // key to adjust gamma correction + {"key_spy", {&key_spy}, {KEYD_F12} , + 0,MAX_KEY,def_key,ss_keys}, // key to view from another coop player's view + {"key_pause", {&key_pause}, {KEYD_PAUSE} , + 0,MAX_KEY,def_key,ss_keys}, // key to pause the game + {"key_autorun", {&key_autorun}, {KEYD_CAPSLOCK} , + 0,MAX_KEY,def_key,ss_keys}, // key to toggle always run mode + {"key_chat", {&key_chat}, {'t'} , + 0,MAX_KEY,def_key,ss_keys}, // key to enter a chat message + {"key_backspace", {&key_backspace}, {KEYD_BACKSPACE} , + 0,MAX_KEY,def_key,ss_keys}, // backspace key + {"key_enter", {&key_enter}, {KEYD_ENTER} , + 0,MAX_KEY,def_key,ss_keys}, // key to select from menu or see last message + {"key_map", {&key_map}, {KEYD_TAB} , + 0,MAX_KEY,def_key,ss_keys}, // key to toggle automap display + {"key_map_right", {&key_map_right}, {KEYD_RIGHTARROW},// phares 3/7/98 + 0,MAX_KEY,def_key,ss_keys}, // key to shift automap right // | + {"key_map_left", {&key_map_left}, {KEYD_LEFTARROW} ,// V + 0,MAX_KEY,def_key,ss_keys}, // key to shift automap left + {"key_map_up", {&key_map_up}, {KEYD_UPARROW} , + 0,MAX_KEY,def_key,ss_keys}, // key to shift automap up + {"key_map_down", {&key_map_down}, {KEYD_DOWNARROW} , + 0,MAX_KEY,def_key,ss_keys}, // key to shift automap down + {"key_map_zoomin", {&key_map_zoomin}, {'='} , + 0,MAX_KEY,def_key,ss_keys}, // key to enlarge automap + {"key_map_zoomout", {&key_map_zoomout}, {'-'} , + 0,MAX_KEY,def_key,ss_keys}, // key to reduce automap + {"key_map_gobig", {&key_map_gobig}, {'0'} , + 0,MAX_KEY,def_key,ss_keys}, // key to get max zoom for automap + {"key_map_follow", {&key_map_follow}, {'f'} , + 0,MAX_KEY,def_key,ss_keys}, // key to toggle follow mode + {"key_map_mark", {&key_map_mark}, {'m'} , + 0,MAX_KEY,def_key,ss_keys}, // key to drop a marker on automap + {"key_map_clear", {&key_map_clear}, {'c'} , + 0,MAX_KEY,def_key,ss_keys}, // key to clear all markers on automap + {"key_map_grid", {&key_map_grid}, {'g'} , + 0,MAX_KEY,def_key,ss_keys}, // key to toggle grid display over automap + {"key_map_rotate", {&key_map_rotate}, {'r'} , + 0,MAX_KEY,def_key,ss_keys}, // key to toggle rotating the automap to match the player's orientation + {"key_map_overlay", {&key_map_overlay}, {'o'} , + 0,MAX_KEY,def_key,ss_keys}, // key to toggle overlaying the automap on the rendered display + {"key_reverse", {&key_reverse}, {'/'} , + 0,MAX_KEY,def_key,ss_keys}, // key to spin 180 instantly + {"key_zoomin", {&key_zoomin}, {'='} , + 0,MAX_KEY,def_key,ss_keys}, // key to enlarge display + {"key_zoomout", {&key_zoomout}, {'-'} , + 0,MAX_KEY,def_key,ss_keys}, // key to reduce display + {"key_chatplayer1", {&destination_keys[0]}, {'g'} , + 0,MAX_KEY,def_key,ss_keys}, // key to chat with player 1 + // killough 11/98: fix 'i'/'b' reversal + {"key_chatplayer2", {&destination_keys[1]}, {'i'} , + 0,MAX_KEY,def_key,ss_keys}, // key to chat with player 2 + {"key_chatplayer3", {&destination_keys[2]}, {'b'} , + 0,MAX_KEY,def_key,ss_keys}, // key to chat with player 3 + {"key_chatplayer4", {&destination_keys[3]}, {'r'} , + 0,MAX_KEY,def_key,ss_keys}, // key to chat with player 4 + {"key_weapontoggle",{&key_weapontoggle}, {'0'} , + 0,MAX_KEY,def_key,ss_keys}, // key to toggle between two most preferred weapons with ammo + {"key_weapon1", {&key_weapon1}, {'1'} , + 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 1 (fist/chainsaw) + {"key_weapon2", {&key_weapon2}, {'2'} , + 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 2 (pistol) + {"key_weapon3", {&key_weapon3}, {'3'} , + 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 3 (supershotgun/shotgun) + {"key_weapon4", {&key_weapon4}, {'4'} , + 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 4 (chaingun) + {"key_weapon5", {&key_weapon5}, {'5'} , + 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 5 (rocket launcher) + {"key_weapon6", {&key_weapon6}, {'6'} , + 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 6 (plasma rifle) + {"key_weapon7", {&key_weapon7}, {'7'} , + 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 7 (bfg9000) // ^ + {"key_weapon8", {&key_weapon8}, {'8'} , + 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 8 (chainsaw) // | + {"key_weapon9", {&key_weapon9}, {'9'} , + 0,MAX_KEY,def_key,ss_keys}, // key to switch to weapon 9 (supershotgun) // phares + + // killough 2/22/98: screenshot key + {"key_screenshot", {&key_screenshot}, {'*'} , + 0,MAX_KEY,def_key,ss_keys}, // key to take a screenshot + + {"Joystick settings",{NULL},{0},UL,UL,def_none,ss_none}, + {"use_joystick",{&usejoystick},{0},0,2, + def_int,ss_none}, // number of joystick to use (0 for none) + {"joy_left",{&joyleft},{0}, UL,UL,def_int,ss_none}, + {"joy_right",{&joyright},{0},UL,UL,def_int,ss_none}, + {"joy_up", {&joyup}, {0}, UL,UL,def_int,ss_none}, + {"joy_down",{&joydown},{0}, UL,UL,def_int,ss_none}, + {"joyb_fire",{&joybfire},{0},0,UL, + def_int,ss_keys}, // joystick button number to use for fire + {"joyb_strafe",{&joybstrafe},{1},0,UL, + def_int,ss_keys}, // joystick button number to use for strafing + {"joyb_speed",{&joybspeed},{2},0,UL, + def_int,ss_keys}, // joystick button number to use for running + {"joyb_use",{&joybuse},{3},0,UL, + def_int,ss_keys}, // joystick button number to use for use/open + + {"Chat macros",{NULL},{0},UL,UL,def_none,ss_none}, + {"chatmacro0", {0,&chat_macros[0]}, {0,HUSTR_CHATMACRO0},UL,UL, + def_str,ss_chat}, // chat string associated with 0 key + {"chatmacro1", {0,&chat_macros[1]}, {0,HUSTR_CHATMACRO1},UL,UL, + def_str,ss_chat}, // chat string associated with 1 key + {"chatmacro2", {0,&chat_macros[2]}, {0,HUSTR_CHATMACRO2},UL,UL, + def_str,ss_chat}, // chat string associated with 2 key + {"chatmacro3", {0,&chat_macros[3]}, {0,HUSTR_CHATMACRO3},UL,UL, + def_str,ss_chat}, // chat string associated with 3 key + {"chatmacro4", {0,&chat_macros[4]}, {0,HUSTR_CHATMACRO4},UL,UL, + def_str,ss_chat}, // chat string associated with 4 key + {"chatmacro5", {0,&chat_macros[5]}, {0,HUSTR_CHATMACRO5},UL,UL, + def_str,ss_chat}, // chat string associated with 5 key + {"chatmacro6", {0,&chat_macros[6]}, {0,HUSTR_CHATMACRO6},UL,UL, + def_str,ss_chat}, // chat string associated with 6 key + {"chatmacro7", {0,&chat_macros[7]}, {0,HUSTR_CHATMACRO7},UL,UL, + def_str,ss_chat}, // chat string associated with 7 key + {"chatmacro8", {0,&chat_macros[8]}, {0,HUSTR_CHATMACRO8},UL,UL, + def_str,ss_chat}, // chat string associated with 8 key + {"chatmacro9", {0,&chat_macros[9]}, {0,HUSTR_CHATMACRO9},UL,UL, + def_str,ss_chat}, // chat string associated with 9 key + + {"Automap settings",{NULL},{0},UL,UL,def_none,ss_none}, + //jff 1/7/98 defaults for automap colors + //jff 4/3/98 remove -1 in lower range, 0 now disables new map features + {"mapcolor_back", {&mapcolor_back}, {247},0,255, // black //jff 4/6/98 new black + def_colour,ss_auto}, // color used as background for automap + {"mapcolor_grid", {&mapcolor_grid}, {104},0,255, // dk gray + def_colour,ss_auto}, // color used for automap grid lines + {"mapcolor_wall", {&mapcolor_wall}, {23},0,255, // red-brown + def_colour,ss_auto}, // color used for one side walls on automap + {"mapcolor_fchg", {&mapcolor_fchg}, {55},0,255, // lt brown + def_colour,ss_auto}, // color used for lines floor height changes across + {"mapcolor_cchg", {&mapcolor_cchg}, {215},0,255, // orange + def_colour,ss_auto}, // color used for lines ceiling height changes across + {"mapcolor_clsd", {&mapcolor_clsd}, {208},0,255, // white + def_colour,ss_auto}, // color used for lines denoting closed doors, objects + {"mapcolor_rkey", {&mapcolor_rkey}, {175},0,255, // red + def_colour,ss_auto}, // color used for red key sprites + {"mapcolor_bkey", {&mapcolor_bkey}, {204},0,255, // blue + def_colour,ss_auto}, // color used for blue key sprites + {"mapcolor_ykey", {&mapcolor_ykey}, {231},0,255, // yellow + def_colour,ss_auto}, // color used for yellow key sprites + {"mapcolor_rdor", {&mapcolor_rdor}, {175},0,255, // red + def_colour,ss_auto}, // color used for closed red doors + {"mapcolor_bdor", {&mapcolor_bdor}, {204},0,255, // blue + def_colour,ss_auto}, // color used for closed blue doors + {"mapcolor_ydor", {&mapcolor_ydor}, {231},0,255, // yellow + def_colour,ss_auto}, // color used for closed yellow doors + {"mapcolor_tele", {&mapcolor_tele}, {119},0,255, // dk green + def_colour,ss_auto}, // color used for teleporter lines + {"mapcolor_secr", {&mapcolor_secr}, {252},0,255, // purple + def_colour,ss_auto}, // color used for lines around secret sectors + {"mapcolor_exit", {&mapcolor_exit}, {0},0,255, // none + def_colour,ss_auto}, // color used for exit lines + {"mapcolor_unsn", {&mapcolor_unsn}, {104},0,255, // dk gray + def_colour,ss_auto}, // color used for lines not seen without computer map + {"mapcolor_flat", {&mapcolor_flat}, {88},0,255, // lt gray + def_colour,ss_auto}, // color used for lines with no height changes + {"mapcolor_sprt", {&mapcolor_sprt}, {112},0,255, // green + def_colour,ss_auto}, // color used as things + {"mapcolor_item", {&mapcolor_item}, {231},0,255, // yellow + def_colour,ss_auto}, // color used for counted items + {"mapcolor_hair", {&mapcolor_hair}, {208},0,255, // white + def_colour,ss_auto}, // color used for dot crosshair denoting center of map + {"mapcolor_sngl", {&mapcolor_sngl}, {208},0,255, // white + def_colour,ss_auto}, // color used for the single player arrow + {"mapcolor_me", {&mapcolor_me}, {112},0,255, // green + def_colour,ss_auto}, // your (player) colour + {"mapcolor_enemy", {&mapcolor_enemy}, {177},0,255, + def_colour,ss_auto}, + {"mapcolor_frnd", {&mapcolor_frnd}, {112},0,255, + def_colour,ss_auto}, + //jff 3/9/98 add option to not show secrets til after found + {"map_secret_after", {&map_secret_after}, {0},0,1, // show secret after gotten + def_bool,ss_auto}, // prevents showing secret sectors till after entered + {"map_point_coord", {&map_point_coordinates}, {0},0,1, + def_bool,ss_auto}, + //jff 1/7/98 end additions for automap + {"automapmode", {(int*)&automapmode}, {0}, 0, 31, // CPhipps - remember automap mode + def_hex,ss_none}, // automap mode + + {"Heads-up display settings",{NULL},{0},UL,UL,def_none,ss_none}, + //jff 2/16/98 defaults for color ranges in hud and status + {"hudcolor_titl", {&hudcolor_titl}, {5},0,9, // gold range + def_int,ss_auto}, // color range used for automap level title + {"hudcolor_xyco", {&hudcolor_xyco}, {3},0,9, // green range + def_int,ss_auto}, // color range used for automap coordinates + {"hudcolor_mesg", {&hudcolor_mesg}, {6},0,9, // red range + def_int,ss_mess}, // color range used for messages during play + {"hudcolor_chat", {&hudcolor_chat}, {5},0,9, // gold range + def_int,ss_mess}, // color range used for chat messages and entry + {"hudcolor_list", {&hudcolor_list}, {5},0,9, // gold range //jff 2/26/98 + def_int,ss_mess}, // color range used for message review + {"hud_msg_lines", {&hud_msg_lines}, {1},1,16, // 1 line scrolling window + def_int,ss_mess}, // number of messages in review display (1=disable) + {"hud_list_bgon", {&hud_list_bgon}, {0},0,1, // solid window bg ena //jff 2/26/98 + def_bool,ss_mess}, // enables background window behind message review + {"hud_distributed",{&hud_distributed},{0},0,1, // hud broken up into 3 displays //jff 3/4/98 + def_bool,ss_none}, // splits HUD into three 2 line displays + + {"health_red", {&health_red} , {25},0,200, // below is red + def_int,ss_stat}, // amount of health for red to yellow transition + {"health_yellow", {&health_yellow}, {50},0,200, // below is yellow + def_int,ss_stat}, // amount of health for yellow to green transition + {"health_green", {&health_green} , {100},0,200,// below is green, above blue + def_int,ss_stat}, // amount of health for green to blue transition + {"armor_red", {&armor_red} , {25},0,200, // below is red + def_int,ss_stat}, // amount of armor for red to yellow transition + {"armor_yellow", {&armor_yellow} , {50},0,200, // below is yellow + def_int,ss_stat}, // amount of armor for yellow to green transition + {"armor_green", {&armor_green} , {100},0,200,// below is green, above blue + def_int,ss_stat}, // amount of armor for green to blue transition + {"ammo_red", {&ammo_red} , {25},0,100, // below 25% is red + def_int,ss_stat}, // percent of ammo for red to yellow transition + {"ammo_yellow", {&ammo_yellow} , {50},0,100, // below 50% is yellow, above green + def_int,ss_stat}, // percent of ammo for yellow to green transition + + //jff 2/16/98 HUD and status feature controls + {"hud_active", {&hud_active}, {2},0,2, // 0=off, 1=small, 2=full + def_int,ss_none}, // 0 for HUD off, 1 for HUD small, 2 for full HUD + //jff 2/23/98 + {"hud_displayed", {&hud_displayed}, {0},0,1, // whether hud is displayed + def_bool,ss_none}, // enables display of HUD + {"hud_nosecrets", {&hud_nosecrets}, {0},0,1, // no secrets/items/kills HUD line + def_bool,ss_stat}, // disables display of kills/items/secrets on HUD + + {"Weapon preferences",{NULL},{0},UL,UL,def_none,ss_none}, + // killough 2/8/98: weapon preferences set by user: + {"weapon_choice_1", {&weapon_preferences[0][0]}, {6}, 0,9, + def_int,ss_weap}, // first choice for weapon (best) + {"weapon_choice_2", {&weapon_preferences[0][1]}, {9}, 0,9, + def_int,ss_weap}, // second choice for weapon + {"weapon_choice_3", {&weapon_preferences[0][2]}, {4}, 0,9, + def_int,ss_weap}, // third choice for weapon + {"weapon_choice_4", {&weapon_preferences[0][3]}, {3}, 0,9, + def_int,ss_weap}, // fourth choice for weapon + {"weapon_choice_5", {&weapon_preferences[0][4]}, {2}, 0,9, + def_int,ss_weap}, // fifth choice for weapon + {"weapon_choice_6", {&weapon_preferences[0][5]}, {8}, 0,9, + def_int,ss_weap}, // sixth choice for weapon + {"weapon_choice_7", {&weapon_preferences[0][6]}, {5}, 0,9, + def_int,ss_weap}, // seventh choice for weapon + {"weapon_choice_8", {&weapon_preferences[0][7]}, {7}, 0,9, + def_int,ss_weap}, // eighth choice for weapon + {"weapon_choice_9", {&weapon_preferences[0][8]}, {1}, 0,9, + def_int,ss_weap}, // ninth choice for weapon (worst) + + // cournia - support for arbitrary music file (defaults are mp3) + {"Music", {NULL},{0},UL,UL,def_none,ss_none}, + {"mus_e1m1", {0,&S_music_files[mus_e1m1]}, {0,"e1m1.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e1m2", {0,&S_music_files[mus_e1m2]}, {0,"e1m2.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e1m3", {0,&S_music_files[mus_e1m3]}, {0,"e1m3.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e1m4", {0,&S_music_files[mus_e1m4]}, {0,"e1m4.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e1m5", {0,&S_music_files[mus_e1m5]}, {0,"e1m5.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e1m6", {0,&S_music_files[mus_e1m6]}, {0,"e1m6.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e1m7", {0,&S_music_files[mus_e1m7]}, {0,"e1m7.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e1m8", {0,&S_music_files[mus_e1m8]}, {0,"e1m8.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e1m9", {0,&S_music_files[mus_e1m9]}, {0,"e1m9.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e2m1", {0,&S_music_files[mus_e2m1]}, {0,"e2m1.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e2m2", {0,&S_music_files[mus_e2m2]}, {0,"e2m2.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e2m3", {0,&S_music_files[mus_e2m3]}, {0,"e2m3.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e2m4", {0,&S_music_files[mus_e2m4]}, {0,"e2m4.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e2m5", {0,&S_music_files[mus_e2m5]}, {0,"e1m7.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e2m6", {0,&S_music_files[mus_e2m6]}, {0,"e2m6.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e2m7", {0,&S_music_files[mus_e2m7]}, {0,"e2m7.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e2m8", {0,&S_music_files[mus_e2m8]}, {0,"e2m8.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e2m9", {0,&S_music_files[mus_e2m9]}, {0,"e3m1.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e3m1", {0,&S_music_files[mus_e3m1]}, {0,"e3m1.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e3m2", {0,&S_music_files[mus_e3m2]}, {0,"e3m2.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e3m3", {0,&S_music_files[mus_e3m3]}, {0,"e3m3.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e3m4", {0,&S_music_files[mus_e3m4]}, {0,"e1m8.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e3m5", {0,&S_music_files[mus_e3m5]}, {0,"e1m7.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e3m6", {0,&S_music_files[mus_e3m6]}, {0,"e1m6.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e3m7", {0,&S_music_files[mus_e3m7]}, {0,"e2m7.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e3m8", {0,&S_music_files[mus_e3m8]}, {0,"e3m8.mp3"},UL,UL, + def_str,ss_none}, + {"mus_e3m9", {0,&S_music_files[mus_e3m9]}, {0,"e1m9.mp3"},UL,UL, + def_str,ss_none}, + {"mus_inter", {0,&S_music_files[mus_inter]}, {0,"e2m3.mp3"},UL,UL, + def_str,ss_none}, + {"mus_intro", {0,&S_music_files[mus_intro]}, {0,"intro.mp3"},UL,UL, + def_str,ss_none}, + {"mus_bunny", {0,&S_music_files[mus_bunny]}, {0,"bunny.mp3"},UL,UL, + def_str,ss_none}, + {"mus_victor", {0,&S_music_files[mus_victor]}, {0,"victor.mp3"},UL,UL, + def_str,ss_none}, + {"mus_introa", {0,&S_music_files[mus_introa]}, {0,"intro.mp3"},UL,UL, + def_str,ss_none}, + {"mus_runnin", {0,&S_music_files[mus_runnin]}, {0,"runnin.mp3"},UL,UL, + def_str,ss_none}, + {"mus_stalks", {0,&S_music_files[mus_stalks]}, {0,"stalks.mp3"},UL,UL, + def_str,ss_none}, + {"mus_countd", {0,&S_music_files[mus_countd]}, {0,"countd.mp3"},UL,UL, + def_str,ss_none}, + {"mus_betwee", {0,&S_music_files[mus_betwee]}, {0,"betwee.mp3"},UL,UL, + def_str,ss_none}, + {"mus_doom", {0,&S_music_files[mus_doom]}, {0,"doom.mp3"},UL,UL, + def_str,ss_none}, + {"mus_the_da", {0,&S_music_files[mus_the_da]}, {0,"the_da.mp3"},UL,UL, + def_str,ss_none}, + {"mus_shawn", {0,&S_music_files[mus_shawn]}, {0,"shawn.mp3"},UL,UL, + def_str,ss_none}, + {"mus_ddtblu", {0,&S_music_files[mus_ddtblu]}, {0,"ddtblu.mp3"},UL,UL, + def_str,ss_none}, + {"mus_in_cit", {0,&S_music_files[mus_in_cit]}, {0,"in_cit.mp3"},UL,UL, + def_str,ss_none}, + {"mus_dead", {0,&S_music_files[mus_dead]}, {0,"dead.mp3"},UL,UL, + def_str,ss_none}, + {"mus_stlks2", {0,&S_music_files[mus_stlks2]}, {0,"stalks.mp3"},UL,UL, + def_str,ss_none}, + {"mus_theda2", {0,&S_music_files[mus_theda2]}, {0,"the_da.mp3"},UL,UL, + def_str,ss_none}, + {"mus_doom2", {0,&S_music_files[mus_doom2]}, {0,"doom.mp3"},UL,UL, + def_str,ss_none}, + {"mus_ddtbl2", {0,&S_music_files[mus_ddtbl2]}, {0,"ddtblu.mp3"},UL,UL, + def_str,ss_none}, + {"mus_runni2", {0,&S_music_files[mus_runni2]}, {0,"runnin.mp3"},UL,UL, + def_str,ss_none}, + {"mus_dead2", {0,&S_music_files[mus_dead2]}, {0,"dead.mp3"},UL,UL, + def_str,ss_none}, + {"mus_stlks3", {0,&S_music_files[mus_stlks3]}, {0,"stalks.mp3"},UL,UL, + def_str,ss_none}, + {"mus_romero", {0,&S_music_files[mus_romero]}, {0,"romero.mp3"},UL,UL, + def_str,ss_none}, + {"mus_shawn2", {0,&S_music_files[mus_shawn2]}, {0,"shawn.mp3"},UL,UL, + def_str,ss_none}, + {"mus_messag", {0,&S_music_files[mus_messag]}, {0,"messag.mp3"},UL,UL, + def_str,ss_none}, + {"mus_count2", {0,&S_music_files[mus_count2]}, {0,"countd.mp3"},UL,UL, + def_str,ss_none}, + {"mus_ddtbl3", {0,&S_music_files[mus_ddtbl3]}, {0,"ddtblu.mp3"},UL,UL, + def_str,ss_none}, + {"mus_ampie", {0,&S_music_files[mus_ampie]}, {0,"ampie.mp3"},UL,UL, + def_str,ss_none}, + {"mus_theda3", {0,&S_music_files[mus_theda3]}, {0,"the_da.mp3"},UL,UL, + def_str,ss_none}, + {"mus_adrian", {0,&S_music_files[mus_adrian]}, {0,"adrian.mp3"},UL,UL, + def_str,ss_none}, + {"mus_messg2", {0,&S_music_files[mus_messg2]}, {0,"messag.mp3"},UL,UL, + def_str,ss_none}, + {"mus_romer2", {0,&S_music_files[mus_romer2]}, {0,"romero.mp3"},UL,UL, + def_str,ss_none}, + {"mus_tense", {0,&S_music_files[mus_tense]}, {0,"tense.mp3"},UL,UL, + def_str,ss_none}, + {"mus_shawn3", {0,&S_music_files[mus_shawn3]}, {0,"shawn.mp3"},UL,UL, + def_str,ss_none}, + {"mus_openin", {0,&S_music_files[mus_openin]}, {0,"openin.mp3"},UL,UL, + def_str,ss_none}, + {"mus_evil", {0,&S_music_files[mus_evil]}, {0,"evil.mp3"},UL,UL, + def_str,ss_none}, + {"mus_ultima", {0,&S_music_files[mus_ultima]}, {0,"ultima.mp3"},UL,UL, + def_str,ss_none}, + {"mus_read_m", {0,&S_music_files[mus_read_m]}, {0,"read_m.mp3"},UL,UL, + def_str,ss_none}, + {"mus_dm2ttl", {0,&S_music_files[mus_dm2ttl]}, {0,"dm2ttl.mp3"},UL,UL, + def_str,ss_none}, + {"mus_dm2int", {0,&S_music_files[mus_dm2int]}, {0,"dm2int.mp3"},UL,UL, + def_str,ss_none}, +}; + +int numdefaults; +static const char* defaultfile; // CPhipps - static, const + +// +// M_SaveDefaults +// + +void M_SaveDefaults (void) + { + int i; + FILE* f; + + f = fopen (defaultfile, "w"); + if (!f) + return; // can't write the file, but don't complain + + // 3/3/98 explain format of file + + fprintf(f,"# Doom config file\n"); + fprintf(f,"# Format:\n"); + fprintf(f,"# variable value\n"); + + for (i = 0 ; i < numdefaults ; i++) { + if (defaults[i].type == def_none) { + // CPhipps - pure headers + fprintf(f, "\n# %s\n", defaults[i].name); + } else + // CPhipps - modified for new default_t form + if (!IS_STRING(defaults[i])) //jff 4/10/98 kill super-hack on pointer value + { + // CPhipps - remove keycode hack + // killough 3/6/98: use spaces instead of tabs for uniform justification + if (defaults[i].type == def_hex) + fprintf (f,"%-25s 0x%x\n",defaults[i].name,*(defaults[i].location.pi)); + else + fprintf (f,"%-25s %5i\n",defaults[i].name,*(defaults[i].location.pi)); + } + else + { + fprintf (f,"%-25s \"%s\"\n",defaults[i].name,*(defaults[i].location.ppsz)); + } + } + + fclose (f); + } + +/* + * M_LookupDefault + * + * cph - mimic MBF function for now. Yes it's crap. + */ + +struct default_s *M_LookupDefault(const char *name) +{ + int i; + for (i = 0 ; i < numdefaults ; i++) + if ((defaults[i].type != def_none) && !strcmp(name, defaults[i].name)) + return &defaults[i]; + I_Error("M_LookupDefault: %s not found",name); + return NULL; +} + +// +// M_LoadDefaults +// + +#define NUMCHATSTRINGS 10 // phares 4/13/98 + +void M_LoadDefaults (void) +{ + int i; + int len; + FILE* f; + char def[80]; + char strparm[100]; + char* newstring = NULL; // killough + int parm; + boolean isstring; + + // set everything to base values + + numdefaults = sizeof(defaults)/sizeof(defaults[0]); + for (i = 0 ; i < numdefaults ; i++) { + if (defaults[i].location.ppsz) + *defaults[i].location.ppsz = strdup(defaults[i].defaultvalue.psz); + if (defaults[i].location.pi) + *defaults[i].location.pi = defaults[i].defaultvalue.i; + } + + // check for a custom default file + + i = M_CheckParm ("-config"); + if (i && i < myargc-1) + defaultfile = myargv[i+1]; + else { + const char* exedir = I_DoomExeDir(); + defaultfile = malloc(PATH_MAX+1); + /* get config file from same directory as executable */ +#ifdef HAVE_SNPRINTF + snprintf((char *)defaultfile, PATH_MAX, +#else + sprintf ((char *)defaultfile, +#endif + "%s%s%sboom.cfg", exedir, HasTrailingSlash(exedir) ? "" : "/", +#if ((defined GL_DOOM) && (defined _MSC_VER)) + "gl"); +#else + "pr"); +#endif + } + + lprintf (LO_CONFIRM, " default file: %s\n",defaultfile); + + // 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) + { + + //jff 3/3/98 skip lines not starting with an alphanum + + if (!isalnum(def[0])) + continue; + + if (strparm[0] == '"') { + // get a string default + + isstring = true; + len = strlen(strparm); + newstring = (char *) malloc(len); + strparm[len-1] = 0; // clears trailing double-quote mark + strcpy(newstring, strparm+1); // clears leading double-quote mark + } else if ((strparm[0] == '0') && (strparm[1] == 'x')) { + // CPhipps - allow ints to be specified in hex + sscanf(strparm+2, "%x", &parm); + } else { + sscanf(strparm, "%i", &parm); + // Keycode hack removed + } + + for (i = 0 ; i < numdefaults ; i++) + if ((defaults[i].type != def_none) && !strcmp(def, defaults[i].name)) + { + // CPhipps - safety check + if (isstring != IS_STRING(defaults[i])) { + lprintf(LO_WARN, "M_LoadDefaults: Type mismatch reading %s\n", defaults[i].name); + continue; + } + if (!isstring) + { + + //jff 3/4/98 range check numeric parameters + + if ((defaults[i].minvalue==UL || defaults[i].minvalue<=parm) && + (defaults[i].maxvalue==UL || defaults[i].maxvalue>=parm)) + *(defaults[i].location.pi) = parm; + } + else + { + free((char*)*(defaults[i].location.ppsz)); /* phares 4/13/98 */ + *(defaults[i].location.ppsz) = newstring; + } + break; + } + } + } + + fclose (f); + } + //jff 3/4/98 redundant range checks for hud deleted here + /* proff 2001/7/1 - added prboom.wad as last entry so it's always loaded and + doesn't overlap with the cfg settings */ + wad_files[MAXLOADFILES-1]="prboom.wad"; +} + + +// +// SCREEN SHOTS +// + +// +// M_ScreenShot +// +// Modified by Lee Killough so that any number of shots can be taken, +// the code is faster, and no annoying "screenshot" message appears. + +// CPhipps - modified to use its own buffer for the image +// - checks for the case where no file can be created (doesn't occur on POSIX systems, would on DOS) +// - track errors better +// - split into 2 functions + +// +// M_DoScreenShot +// Takes a screenshot into the names file + +void M_DoScreenShot (const char* fname) +{ + if (I_ScreenShot(fname) != 0) + doom_printf("M_ScreenShot: Error writing screenshot\n"); +} + +#ifndef SCREENSHOT_DIR +#define SCREENSHOT_DIR "." +#endif + +#ifdef HAVE_LIBPNG +#define SCREENSHOT_EXT ".png" +#else +#define SCREENSHOT_EXT ".bmp" +#endif + +void M_ScreenShot(void) +{ + static int shot; + char lbmname[PATH_MAX + 1]; + int startshot; + + if (!access(SCREENSHOT_DIR,2)) + { + startshot = shot; // CPhipps - prevent infinite loop + + do { + sprintf(lbmname,"%s/doom%02d" SCREENSHOT_EXT, SCREENSHOT_DIR, shot++); + } while (!access(lbmname,0) && (shot != startshot) && (shot < 10000)); + + if (access(lbmname,0)) + { + S_StartSound(NULL,gamemode==commercial ? sfx_radio : sfx_tink); + M_DoScreenShot(lbmname); // cph + return; + } + } + + doom_printf ("M_ScreenShot: Couldn't create screenshot"); + return; +} diff --git a/src/m_misc.h b/src/m_misc.h new file mode 100644 index 0000000..2e4d545 --- /dev/null +++ b/src/m_misc.h @@ -0,0 +1,111 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * External non-system-specific stuff, like storing config settings, + * simple file handling, and saving screnshots. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __M_MISC__ +#define __M_MISC__ + + +#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_DoScreenShot (const char*); // cph + +void M_LoadDefaults (void); + +void M_SaveDefaults (void); + +struct default_s *M_LookupDefault(const char *name); /* killough 11/98 */ + +// phares 4/21/98: +// Moved from m_misc.c so m_menu.c could see it. + +// CPhipps - struct to hold a value in a config file +// Cannot be a union, as it must be initialised +typedef struct default_s +{ + const char* name; + /* cph - + * The location struct holds the pointer to the variable holding the + * setting. For int's we do nothing special. + * For strings, the string is actually stored on our heap with Z_Strdup() + * BUT we don't want the rest of the program to be able to modify them, + * so we declare it const. It's not really const though, and m_misc.c and + * m_menu.c cast it back when they need to change it. Possibly this is + * more trouble than it's worth. + */ + struct { + int* pi; + const char** ppsz; + } location; + struct { + int i; + const char* psz; + } defaultvalue; // CPhipps - default value + // Limits (for an int) + int minvalue; // jff 3/3/98 minimum allowed value + int maxvalue; // jff 3/3/98 maximum allowed value + enum { + def_none, // Dummy entry + def_str, // A string + def_int, // Integer + def_hex, // Integer (write in hex) + def_bool = def_int, // Boolean + def_key = def_hex, // Key code (byte) + def_mouseb = def_int,// Mouse button + def_colour = def_hex // Colour (256 colour palette entry) + } type; // CPhipps - type of entry + int setupscreen; // phares 4/19/98: setup screen where this appears + int *current; /* cph - MBF-like pointer to current value */ + // cph - removed the help strings from the config file + // const char* help; // jff 3/3/98 description of parameter + // CPhipps - remove unused "lousy hack" code + struct setup_menu_s *setup_menu; /* Xref to setup menu item, if any */ +} default_t; + +#define IS_STRING(dv) ((dv).type == def_str) +// CPhipps - What is the max. key code that X will send us? +#define MAX_KEY 65536 +#define MAX_MOUSEB 2 + +#define UL (-123456789) /* magic number for no min or max for parameter */ + +#endif diff --git a/src/m_random.c b/src/m_random.c new file mode 100644 index 0000000..bd0c7bc --- /dev/null +++ b/src/m_random.c @@ -0,0 +1,147 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Random number LUT. + * + * 1/19/98 killough: Rewrote random number generator for better randomness, + * while at the same time maintaining demo sync and backward compatibility. + * + * 2/16/98 killough: Made each RNG local to each control-equivalent block, + * to reduce the chances of demo sync problems. + * + *-----------------------------------------------------------------------------*/ + + +#include "doomstat.h" +#include "m_random.h" +#include "lprintf.h" + +// +// M_Random +// Returns a 0-255 number +// +static const unsigned char rndtable[256] = { // 1/19/98 killough -- made const + 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 , + 52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224 , + 149, 104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242 , + 145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0 , + 175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235 , + 25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113 , + 94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75 , + 136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196 , + 135, 106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113 , + 80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241 , + 24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224 , + 145, 224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95 , + 28, 139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226 , + 71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36 , + 17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106 , + 197, 242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136 , + 120, 163, 236, 249 +}; + +rng_t rng; // the random number state + +unsigned long rngseed = 1993; // killough 3/26/98: The seed + +int (P_Random)(pr_class_t pr_class +#ifdef INSTRUMENTED + , const char *file, int line +#endif +) +{ + // killough 2/16/98: We always update both sets of random number + // generators, to ensure repeatability if the demo_compatibility + // flag is changed while the program is running. Changing the + // demo_compatibility flag does not change the sequences generated, + // only which one is selected from. + // + // All of this RNG stuff is tricky as far as demo sync goes -- + // it's like playing with explosives :) Lee + +#ifdef INSTRUMENTED + //lprintf(LO_DEBUG, "%.10d: %.10d - %s:%.5d\n", gametic, pr_class, file, line); +#endif + + int compat = pr_class == pr_misc ? + (rng.prndindex = (rng.prndindex + 1) & 255) : + (rng. rndindex = (rng. rndindex + 1) & 255) ; + + unsigned long boom; + + // killough 3/31/98: + // If demo sync insurance is not requested, use + // much more unstable method by putting everything + // except pr_misc into pr_all_in_one + + if (pr_class != pr_misc && !demo_insurance) // killough 3/31/98 + pr_class = pr_all_in_one; + + boom = rng.seed[pr_class]; + + // killough 3/26/98: add pr_class*2 to addend + + rng.seed[pr_class] = boom * 1664525ul + 221297ul + pr_class*2; + + if (demo_compatibility) + return rndtable[compat]; + + boom >>= 20; + + /* killough 3/30/98: use gametic-levelstarttic to shuffle RNG + * killough 3/31/98: but only if demo insurance requested, + * since it's unnecessary for random shuffling otherwise + * killough 9/29/98: but use basetic now instead of levelstarttic + * cph - DEMOSYNC - this change makes MBF demos work, + * but does it break Boom ones? + */ + + if (demo_insurance) + boom += (gametic-basetic)*7; + + return boom & 255; +} + +// Initialize all the seeds +// +// This initialization method is critical to maintaining demo sync. +// Each seed is initialized according to its class, so if new classes +// are added they must be added to end of pr_class_t list. killough +// + +void M_ClearRandom (void) +{ + int i; + unsigned long seed = rngseed*2+1; // add 3/26/98: add rngseed + for (i=0; i +#ifdef __arch__swab16 +#define doom_swap_s (signed short)__arch__swab16 +#endif +#ifdef __arch__swab32 +#define doom_swap_l (signed long)__arch__swab32 +#endif +#endif /* HAVE_ASM_BYTEORDER_H */ + +#ifdef HAVE_LIBKERN_OSBYTEORDER_H +#include + +#define doom_swap_s (short)OSSwapInt16 +#define doom_swap_l (long)OSSwapInt32 +#endif + +#ifndef doom_swap_l +#define doom_swap_l(x) \ + ((long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \ + (((unsigned long int)(x) & 0x0000ff00U) << 8) | \ + (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \ + (((unsigned long int)(x) & 0xff000000U) >> 24))) +#endif + +#ifndef doom_swap_s +#define doom_swap_s(x) \ + ((short int)((((unsigned short int)(x) & 0x00ff) << 8) | \ + (((unsigned short int)(x) & 0xff00) >> 8))) +#endif + +/* Macros are named doom_XtoYT, where + * X is thing to convert from, Y is thing to convert to, chosen from + * n for network, h for host (i.e our machine's), w for WAD (Doom data files) + * and T is the type, l or s for long or short + * + * CPhipps - all WADs and network packets will be little endian for now + * Use separate macros so network could be converted to big-endian later. + */ + +#ifdef WORDS_BIGENDIAN + +#define doom_wtohl(x) doom_swap_l(x) +#define doom_htowl(x) doom_swap_l(x) +#define doom_wtohs(x) doom_swap_s(x) +#define doom_htows(x) doom_swap_s(x) + +#define doom_ntohl(x) doom_swap_l(x) +#define doom_htonl(x) doom_swap_l(x) +#define doom_ntohs(x) doom_swap_s(x) +#define doom_htons(x) doom_swap_s(x) + +#else + +#define doom_wtohl(x) (long int)(x) +#define doom_htowl(x) (long int)(x) +#define doom_wtohs(x) (short int)(x) +#define doom_htows(x) (short int)(x) + +#define doom_ntohl(x) (long int)(x) +#define doom_htonl(x) (long int)(x) +#define doom_ntohs(x) (short int)(x) +#define doom_htons(x) (short int)(x) + +#endif + +/* CPhipps - Boom's old LONG and SHORT endianness macros are for WAD stuff */ + +#define LONG(x) doom_wtohl(x) +#define SHORT(x) doom_htows(x) + +#endif diff --git a/src/md5.c b/src/md5.c new file mode 100644 index 0000000..d69ec0c --- /dev/null +++ b/src/md5.c @@ -0,0 +1,240 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson . + * Still in the public domain. + */ +#include "config.h" + +#include /* for memcpy() */ +#include /* for stupid systems */ + +#include "md5.h" + +#ifdef WORDS_BIGENDIAN +void +byteSwap(UWORD32 *buf, unsigned words) +{ + md5byte *p = (md5byte *)buf; + + do { + *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} +#else +#define byteSwap(buf,words) +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len) +{ + UWORD32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((md5byte *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((md5byte *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +MD5Final(md5byte digest[16], struct MD5Context *ctx) +{ + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + md5byte *p = (md5byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (md5byte *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<>(32-s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void +MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) +{ + register UWORD32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif diff --git a/src/md5.h b/src/md5.h new file mode 100644 index 0000000..3ebeb36 --- /dev/null +++ b/src/md5.h @@ -0,0 +1,47 @@ +/* + * This is the header file for the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' + * header definitions; now uses stuff from dpkg's config.h + * - Ian Jackson . + * Still in the public domain. + */ + +#ifndef MD5_H +#define MD5_H + +#ifdef _MSC_VER +#define WIN32_LEAN_AND_MEAN +#include +#define UWORD32 DWORD +#else +#include +#define UWORD32 uint32_t +#endif +#define md5byte unsigned char + +struct MD5Context { + UWORD32 buf[4]; + UWORD32 bytes[2]; + UWORD32 in[16]; +}; + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len); +void MD5Final(unsigned char digest[16], struct MD5Context *context); +void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); + +#endif /* !MD5_H */ diff --git a/src/mmus2mid.c b/src/mmus2mid.c new file mode 100644 index 0000000..3669c36 --- /dev/null +++ b/src/mmus2mid.c @@ -0,0 +1,866 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * This file supports conversion of MUS format music in memory + * to MIDI format 1 music in memory. + * + * The primary routine, mmus2mid, converts a block of memory in MUS format + * to an Allegro MIDI structure. This supports playing MUS lumps in a wad + * file with BOOM. + * + * Another routine, Midi2MIDI, converts a block of memory in MIDI format 1 to + * an Allegro MIDI structure. This supports playing MIDI lumps in a wad + * file with BOOM. + * + * For testing purposes, and to make a utility if desired, if the symbol + * STANDALONE is defined by uncommenting the definition below, a main + * routine is compiled that will convert a possibly wildcarded set of MUS + * files to a similarly named set of MIDI files. + * + * Much of the code here is thanks to S. Bacquet's source for QMUS2MID.C + * + *----------------------------------------------------------------------------- + */ + + +#include +#include +#include +#include +#include +#include +#include +#ifdef MSDOS /* proff: I don't use allegro in windows */ +#include +#endif /* !MSDOS */ +#include "mmus2mid.h" +#include "lprintf.h" // jff 08/03/98 - declaration of lprintf + +//#define STANDALONE /* uncomment this to make MMUS2MID.EXE */ +#ifndef STANDALONE +#include "m_swap.h" +#include "z_zone.h" +#endif + +// some macros to decode mus event bit fields + +#define last(e) ((UBYTE)((e) & 0x80)) +#define event_type(e) ((UBYTE)(((e) & 0x7F) >> 4)) +#define channel(e) ((UBYTE)((e) & 0x0F)) + +// event types + +typedef enum +{ + RELEASE_NOTE, + PLAY_NOTE, + BEND_NOTE, + SYS_EVENT, + CNTL_CHANGE, + UNKNOWN_EVENT1, + SCORE_END, + UNKNOWN_EVENT2, +} mus_event_t; + +// MUS format header structure + +typedef struct +{ + char ID[4]; // identifier "MUS"0x1A + UWORD ScoreLength; // length of music portion + UWORD ScoreStart; // offset of music portion + UWORD channels; // count of primary channels + UWORD SecChannels; // count of secondary channels + UWORD InstrCnt; // number of instruments +} PACKEDATTR MUSheader; + +// to keep track of information in a MIDI track + +typedef struct Track +{ + char velocity; + long deltaT; + UBYTE lastEvt; + long alloced; +} TrackInfo; + +// array of info about tracks + +static TrackInfo track[MIDI_TRACKS]; + +// initial track size allocation +#define TRACKBUFFERSIZE 1024 + +// lookup table MUS -> MID controls +static UBYTE MUS2MIDcontrol[15] = +{ + 0, // Program change - not a MIDI control change + 0x00, // Bank select + 0x01, // Modulation pot + 0x07, // Volume + 0x0A, // Pan pot + 0x0B, // Expression pot + 0x5B, // Reverb depth + 0x5D, // Chorus depth + 0x40, // Sustain pedal + 0x43, // Soft pedal + 0x78, // All sounds off + 0x7B, // All notes off + 0x7E, // Mono + 0x7F, // Poly + 0x79 // Reset all controllers +}; + +// some strings of bytes used in the midi format + +static UBYTE midikey[] = +{0x00,0xff,0x59,0x02,0x00,0x00}; // C major +static UBYTE miditempo[] = +{0x00,0xff,0x51,0x03,0x09,0xa3,0x1a}; // uS/qnote +static UBYTE midihdr[] = +{'M','T','h','d',0,0,0,6,0,1,0,0,0,0}; // header (length 6, format 1) +static UBYTE trackhdr[] = +{'M','T','r','k'}; // track header + +// static routine prototypes + +static int TWriteByte(MIDI *mididata, int MIDItrack, UBYTE byte); +static int TWriteVarLen(MIDI *mididata, int MIDItrack, register ULONG value); +static ULONG ReadTime(const UBYTE **musptrp); +static int FirstChannelAvailable(int MUS2MIDchannel[]); +static UBYTE MidiEvent(MIDI *mididata,UBYTE midicode,UBYTE MIDIchannel, + UBYTE MIDItrack,int nocomp); + +// +// TWriteByte() +// +// write one byte to the selected MIDItrack, update current position +// if track allocation exceeded, double it +// if track not allocated, initially allocate TRACKBUFFERSIZE bytes +// +// Passed pointer to Allegro MIDI structure, number of the MIDI track being +// written, and the byte to write. +// +// Returns 0 on success, MEMALLOC if a memory allocation error occurs +// +static int TWriteByte(MIDI *mididata, int MIDItrack, UBYTE byte) +{ + ULONG pos ; + + pos = mididata->track[MIDItrack].len; + if (pos >= (ULONG)track[MIDItrack].alloced) + { + track[MIDItrack].alloced = // double allocation + track[MIDItrack].alloced? // or set initial TRACKBUFFERSIZE + 2*track[MIDItrack].alloced : + TRACKBUFFERSIZE; + + if (!(mididata->track[MIDItrack].data = // attempt to reallocate + realloc(mididata->track[MIDItrack].data, + track[MIDItrack].alloced))) + return MEMALLOC; + } + mididata->track[MIDItrack].data[pos] = byte; + mididata->track[MIDItrack].len++; + return 0; +} + +// +// TWriteVarLen() +// +// write the ULONG value to tracknum-th track, in midi format, which is +// big endian, 7 bits per byte, with all bytes but the last flagged by +// bit 8 being set, allowing the length to vary. +// +// Passed the Allegro MIDI structure, the track number to write, +// and the ULONG value to encode in midi format there +// +// Returns 0 if sucessful, MEMALLOC if a memory allocation error occurs +// +static int TWriteVarLen(MIDI *mididata, int tracknum, register ULONG value) +{ + register ULONG buffer; + + buffer = value & 0x7f; + while ((value >>= 7)) // terminates because value unsigned + { + buffer <<= 8; // note first value shifted in has bit 8 clear + buffer |= 0x80; // all succeeding values do not + buffer += (value & 0x7f); + } + while (1) // write bytes out in opposite order + { + if (TWriteByte(mididata, tracknum, (UBYTE)(buffer&0xff))) // insure buffer masked + return MEMALLOC; + + if (buffer & 0x80) + buffer >>= 8; + else // terminate on the byte with bit 8 clear + break; + } + return 0; +} + +// +// ReadTime() +// +// Read a time value from the MUS buffer, advancing the position in it +// +// A time value is a variable length sequence of 8 bit bytes, with all +// but the last having bit 8 set. +// +// Passed a pointer to the pointer to the MUS buffer +// Returns the integer unsigned long time value there and advances the pointer +// +static ULONG ReadTime(const UBYTE **musptrp) +{ + register ULONG timeval = 0; + int byte; + + do // shift each byte read up in the result until a byte with bit 8 clear + { + byte = *(*musptrp)++; + timeval = (timeval << 7) + (byte & 0x7F); + } + while(byte & 0x80); + + return timeval; +} + +// +// FirstChannelAvailable() +// +// Return the next unassigned MIDI channel number +// +// The assignment for MUS channel 15 is not counted in the caculation, that +// being percussion and always assigned to MIDI channel 9 (base 0). +// +// Passed the array of MIDI channels assigned to MUS channels +// Returns the maximum channel number unassigned unless that is 9 in which +// case 10 is returned. +// +// killough 10/7/98: changed char parameter, return values to int + +static int FirstChannelAvailable(int MUS2MIDchannel[]) +{ + int i ; + int max = -1 ; + + // find the largest MIDI channel assigned so far + for (i = 0; i < 15; i++) + if (MUS2MIDchannel[i] > max) + max = MUS2MIDchannel[i]; + + return (max == 8 ? 10 : max+1); // skip MIDI channel 9 (percussion) +} + +// +// MidiEvent() +// +// Constructs a MIDI event code, and writes it to the current MIDI track +// unless its the same as the last event code and compressio is enabled +// in which case nothing is written. +// +// Passed the Allegro MIDI structure, the midi event code, the current +// MIDI channel number, the current MIDI track number, and whether compression +// (running status) is enabled. +// +// Returns the new event code if successful, 0 if a memory allocation error +// +static UBYTE MidiEvent(MIDI *mididata,UBYTE midicode,UBYTE MIDIchannel, + UBYTE MIDItrack,int nocomp) +{ + UBYTE newevent; + + newevent = midicode | MIDIchannel; + if ((newevent != track[MIDItrack].lastEvt) || nocomp) + { + if (TWriteByte(mididata,MIDItrack, newevent)) + return 0; // indicates MEMALLOC error + track[MIDItrack].lastEvt = newevent; + } + return newevent; +} + +// +// mmus2mid() +// +// Convert a memory buffer contain MUS data to an Allegro MIDI structure +// with specified time division and compression. +// +// Passed a pointer to the buffer containing MUS data, a pointer to the +// Allegro MIDI structure, the divisions, and a flag whether to compress. +// +// Returns 0 if successful, otherwise an error code (see mmus2mid.h). +// +int mmus2mid(const UBYTE *mus, MIDI *mididata, UWORD division, int nocomp) +{ + UWORD TrackCnt = 0; + UBYTE evt, MUSchannel, MIDIchannel, MIDItrack=0, NewEvent; + int i, event, data; + const UBYTE *musptr; + size_t muslen; + static MUSheader MUSh; + UBYTE MIDIchan2track[MIDI_TRACKS]; // killough 10/7/98: fix too small array + int MUS2MIDchannel[MIDI_TRACKS]; // killough 10/7/98: fix too small array + + // copy the MUS header from the MUS buffer to the MUSh header structure + + memcpy(&MUSh,mus,sizeof(MUSheader)); + MUSh.ScoreLength = doom_wtohs(MUSh.ScoreLength); + MUSh.ScoreStart = doom_wtohs(MUSh.ScoreStart); + MUSh.channels = doom_wtohs(MUSh.channels); + MUSh.SecChannels = doom_wtohs(MUSh.SecChannels); + MUSh.InstrCnt = doom_wtohs(MUSh.InstrCnt); + + // check some things and set length of MUS buffer from internal data + + if (!(muslen = MUSh.ScoreLength + MUSh.ScoreStart)) + return MUSDATAMT; // MUS file empty + + if (MUSh.channels > 15) // MUSchannels + drum channel > 16 + return TOOMCHAN ; + + musptr = mus+MUSh.ScoreStart; // init musptr to start of score + + for (i = 0; i < MIDI_TRACKS; i++) // init the track structure's tracks + { + MUS2MIDchannel[i] = -1; // flag for channel not used yet + track[i].velocity = 64; + track[i].deltaT = 0; + track[i].lastEvt = 0; + //free(mididata->track[i].data);//jff 3/5/98 remove old allocations + mididata->track[i].data=NULL; + track[i].alloced = 0; + mididata->track[i].len = 0; + } + + if (!division) + division = 70; + + // allocate the first track which is a special tempo/key track + // note multiple tracks means midi format 1 + + // set the divisions (ticks per quarter note) + mididata->divisions = division; + + // allocate for midi tempo/key track, allow for end of track + if (!(mididata->track[0].data = + realloc(mididata->track[0].data,sizeof(midikey)+sizeof(miditempo)+4))) + return MEMALLOC; + + // key C major + memcpy(mididata->track[0].data,midikey,sizeof(midikey)); + // tempo uS/qnote + memcpy(mididata->track[0].data+sizeof(midikey),miditempo,sizeof(miditempo)); + mididata->track[0].len = sizeof(midikey)+sizeof(miditempo); + + TrackCnt++; // music tracks start at 1 + + // process the MUS events in the MUS buffer + + do + { + // get a mus event, decode its type and channel fields + + event = *musptr++; + if ((evt = event_type(event)) == SCORE_END) //jff 1/23/98 use symbol + break; // if end of score event, leave + MUSchannel = channel(event); + + // if this channel not initialized, do so + + if (MUS2MIDchannel[MUSchannel] == -1) + { + // set MIDIchannel and MIDItrack + + MIDIchannel = MUS2MIDchannel[MUSchannel] = + (MUSchannel == 15 ? 9 : FirstChannelAvailable(MUS2MIDchannel)); + MIDItrack = MIDIchan2track[MIDIchannel] = (UBYTE)TrackCnt++; + } + else // channel already allocated as a track, use those values + { + MIDIchannel = MUS2MIDchannel[MUSchannel]; + MIDItrack = MIDIchan2track[MIDIchannel]; + } + + if (TWriteVarLen(mididata, MIDItrack, track[MIDItrack].deltaT)) + return MEMALLOC; + track[MIDItrack].deltaT = 0; + + switch(evt) + { + case RELEASE_NOTE: + // killough 10/7/98: Fix noise problems by not allowing compression + if (!(NewEvent=MidiEvent(mididata,0x90,MIDIchannel,MIDItrack,1))) + return MEMALLOC; + + data = *musptr++; + if (TWriteByte(mididata, MIDItrack, (UBYTE)(data & 0x7F))) + return MEMALLOC; + if (TWriteByte(mididata, MIDItrack, 0)) + return MEMALLOC; + break; + + case PLAY_NOTE: + if (!(NewEvent=MidiEvent(mididata,0x90,MIDIchannel,MIDItrack,nocomp))) + return MEMALLOC; + + data = *musptr++; + if (TWriteByte(mididata, MIDItrack, (UBYTE)(data & 0x7F))) + return MEMALLOC; + if( data & 0x80 ) + track[MIDItrack].velocity = (*musptr++) & 0x7f; + if (TWriteByte(mididata, MIDItrack, track[MIDItrack].velocity)) + return MEMALLOC; + break; + + case BEND_NOTE: + if (!(NewEvent=MidiEvent(mididata,0xE0,MIDIchannel,MIDItrack,nocomp))) + return MEMALLOC; + + data = *musptr++; + if (TWriteByte(mididata, MIDItrack, (UBYTE)((data & 1) << 6))) + return MEMALLOC; + if (TWriteByte(mididata, MIDItrack, (UBYTE)(data >> 1))) + return MEMALLOC; + break; + + case SYS_EVENT: + if (!(NewEvent=MidiEvent(mididata,0xB0,MIDIchannel,MIDItrack,nocomp))) + return MEMALLOC; + + data = *musptr++; + if (data<10 || data>14) + return BADSYSEVT; + + if (TWriteByte(mididata, MIDItrack, MUS2MIDcontrol[data])) + return MEMALLOC; + if (data == 12) + { + if (TWriteByte(mididata, MIDItrack, (UBYTE)(MUSh.channels+1))) + return MEMALLOC; + } + else + if (TWriteByte(mididata, MIDItrack, 0)) + return MEMALLOC; + break; + + case CNTL_CHANGE: + data = *musptr++; + if (data>9) + return BADCTLCHG; + + if (data) + { + if (!(NewEvent=MidiEvent(mididata,0xB0,MIDIchannel,MIDItrack,nocomp))) + return MEMALLOC; + + if (TWriteByte(mididata, MIDItrack, MUS2MIDcontrol[data])) + return MEMALLOC; + } + else + { + if (!(NewEvent=MidiEvent(mididata,0xC0,MIDIchannel,MIDItrack,nocomp))) + return MEMALLOC; + } + data = *musptr++; + if (TWriteByte(mididata, MIDItrack, (UBYTE)(data & 0x7F))) + return MEMALLOC; + break; + + case UNKNOWN_EVENT1: // mus events 5 and 7 + case UNKNOWN_EVENT2: // meaning not known + return BADMUSCTL; + + case SCORE_END: + break; + + default: + return BADMUSCTL; // exit with error + } + if (last(event)) + { + ULONG DeltaTime = ReadTime(&musptr); // killough 10/7/98: make local + for (i = 0;i < MIDI_TRACKS; i++) //jff 3/13/98 update all tracks + track[i].deltaT += DeltaTime; //whether allocated yet or not + } + + } + while ((evt != SCORE_END) && ((size_t)(musptr-mus) < muslen)); + + if (evt!=SCORE_END) + return MUSDATACOR; + + // Now add an end of track to each mididata track, correct allocation + + for (i = 0; i < MIDI_TRACKS; i++) + if (mididata->track[i].len) + { // killough 10/7/98: simplify code + if (TWriteByte(mididata, i, 0x00) || // midi end of track code + TWriteByte(mididata, i, 0xFF) || + TWriteByte(mididata, i, 0x2F) || + TWriteByte(mididata, i, 0x00)) + return MEMALLOC; + + // jff 1/23/98 fix failure to set data NULL, len 0 for unused tracks + // shorten allocation to proper length (important for Allegro) + if (!(mididata->track[i].data = + realloc(mididata->track[i].data,mididata->track[i].len))) + return MEMALLOC; + } + else + { + free(mididata->track[i].data); + mididata->track[i].data = NULL; + } + + return 0; +} + +void free_mididata(MIDI *mid) +{ + int i; + + for (i = 0; i < MIDI_TRACKS; i++) + if (mid->track[i].data) + free(mid->track[i].data); +} + +// +// ReadLength() +// +// Reads the length of a chunk in a midi buffer, advancing the pointer +// 4 bytes, bigendian +// +// Passed a pointer to the pointer to a MIDI buffer +// Returns the chunk length at the pointer position +// +static size_t ReadLength(UBYTE **mid) +{ + UBYTE *midptr = *mid; + + size_t length = (*midptr++)<<24; + length += (*midptr++)<<16; + length += (*midptr++)<<8; + length += *midptr++; + *mid = midptr; + return length; +} + +// +// MidiToMIDI() +// +// Convert an in-memory copy of a MIDI format 0 or 1 file to +// an Allegro MIDI structure, that is valid or has been zeroed +// +// Passed a pointer to a memory buffer with MIDI format music in it and a +// pointer to an Allegro MIDI structure. +// +// Returns 0 if successful, BADMIDHDR if the buffer is not MIDI format +// +int MidiToMIDI(UBYTE *mid,MIDI *mididata) +{ + int i; + int ntracks; + + // read the midi header + + if (memcmp(mid,midihdr,4)) + return BADMIDHDR; + + mididata->divisions = (mid[12]<<8)+mid[13]; + ntracks = (mid[10]<<8)+mid[11]; + + if (ntracks>=MIDI_TRACKS) + return BADMIDHDR; + + mid += 4; + { // killough 10/7/98: fix mid from being modified twice before sequence pt. + size_t t = ReadLength(&mid); // seek past header + mid += t; + } + + // now read each track + + for (i=0;itrack[i].len = ReadLength(&mid); // get length, move mid past it + + // read a track + mididata->track[i].data = realloc(mididata->track[i].data,mididata->track[i].len); + memcpy(mididata->track[i].data,mid,mididata->track[i].len); + mid += mididata->track[i].len; + } + for (;itrack[i].len) + { + free(mididata->track[i].data); + mididata->track[i].data = NULL; + mididata->track[i].len = 0; + } + return 0; +} + +//#ifdef STANDALONE /* this code unused by BOOM provided for future portability */ +// /* it also provides a MUS to MID file converter*/ +// proff: I moved this down, because I need MIDItoMidi + +static void FreeTracks(MIDI *mididata); +static void TWriteLength(UBYTE **midiptr,ULONG length); + +// +// FreeTracks() +// +// Free all track allocations in the MIDI structure +// +// Passed a pointer to an Allegro MIDI structure +// Returns nothing +// +static void FreeTracks(MIDI *mididata) +{ + int i; + + for (i=0; itrack[i].data); + mididata->track[i].data = NULL; + mididata->track[i].len = 0; + } +} + +// +// TWriteLength() +// +// Write the length of a MIDI chunk to a midi buffer. The length is four +// bytes and is written byte-reversed for bigendian. The pointer to the +// midi buffer is advanced. +// +// Passed a pointer to the pointer to a midi buffer, and the length to write +// Returns nothing +// +static void TWriteLength(UBYTE **midiptr,ULONG length) +{ +// proff: Added typecast to avoid warning + *(*midiptr)++ = (unsigned char)((length>>24)&0xff); + *(*midiptr)++ = (unsigned char)((length>>16)&0xff); + *(*midiptr)++ = (unsigned char)((length>>8)&0xff); + *(*midiptr)++ = (unsigned char)((length)&0xff); +} + +// +// MIDIToMidi() +// +// This routine converts an Allegro MIDI structure to a midi 1 format file +// in memory. It is used to support memory MUS -> MIDI conversion +// +// Passed a pointer to an Allegro MIDI structure, a pointer to a pointer to +// a buffer containing midi data, and a pointer to a length return. +// Returns 0 if successful, MEMALLOC if a memory allocation error occurs +// +int MIDIToMidi(MIDI *mididata,UBYTE **mid,int *midlen) +{ + size_t total; + int i,ntrks; + UBYTE *midiptr; + + // calculate how long the mid buffer must be, and allocate + + total = sizeof(midihdr); + for (i=0,ntrks=0;itrack[i].len) + { + total += 8 + mididata->track[i].len; // Track hdr + track length + ntrks++; + } + if ((*mid = malloc(total))==NULL) + return MEMALLOC; + + + // fill in number of tracks and bigendian divisions (ticks/qnote) + + midihdr[10] = 0; + midihdr[11] = (UBYTE)ntrks; // set number of tracks in header + midihdr[12] = (mididata->divisions>>8) & 0x7f; + midihdr[13] = (mididata->divisions) & 0xff; + + // write the midi header + + midiptr = *mid; + memcpy(midiptr,midihdr,sizeof(midihdr)); + midiptr += sizeof(midihdr); + + // write the tracks + + for (i=0;itrack[i].len) + { + memcpy(midiptr,trackhdr,sizeof(trackhdr)); // header + midiptr += sizeof(trackhdr); + TWriteLength(&midiptr,mididata->track[i].len); // track length + // data + memcpy(midiptr,mididata->track[i].data,mididata->track[i].len); + midiptr += mididata->track[i].len; + } + } + + // return length information + + *midlen = midiptr - *mid; + + return 0; +} + +#ifdef STANDALONE /* this code unused by BOOM provided for future portability */ + /* it also provides a MUS to MID file converter*/ +// proff: I moved this down, because I need MIDItoMidi + +// +// main() +// +// Main routine that will convert a globbed set of MUS files to the +// correspondingly named MID files using mmus2mid(). Only compiled +// if the STANDALONE symbol is defined. +// +// Passed the command line arguments, returns 0 if successful +// +int main(int argc,char **argv) +{ + FILE *musst,*midst; + char musfile[FILENAME_MAX],midfile[FILENAME_MAX]; + MUSheader MUSh; + UBYTE *mus,*mid; + static MIDI mididata; + int err,midlen; + char *p,*q; + int i; + + if (argc<2) + { + //jff 8/3/98 use logical output routine + lprintf(LO_INFO,"Usage: MMUS2MID musfile[.MUS]\n"); + lprintf(LO_INFO,"writes musfile.MID as output\n"); + lprintf(LO_INFO,"musfile may contain wildcards\n"); + exit(1); + } + + for (i=1;idirection) + { + case 0: + // If ceiling in stasis, do nothing + break; + + case 1: + // Ceiling is moving up + res = T_MovePlane + ( + ceiling->sector, + ceiling->speed, + ceiling->topheight, + false, + 1, + ceiling->direction + ); + + // if not a silent crusher, make moving sound + if (!(leveltime&7)) + { + switch(ceiling->type) + { + case silentCrushAndRaise: + case genSilentCrusher: + break; + default: + S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_stnmov); + break; + } + } + + // handle reaching destination height + if (res == pastdest) + { + switch(ceiling->type) + { + // plain movers are just removed + case raiseToHighest: + case genCeiling: + P_RemoveActiveCeiling(ceiling); + break; + + // movers with texture change, change the texture then get removed + case genCeilingChgT: + case genCeilingChg0: + ceiling->sector->special = ceiling->newspecial; + //jff 3/14/98 transfer old special field as well + ceiling->sector->oldspecial = ceiling->oldspecial; + case genCeilingChg: + ceiling->sector->ceilingpic = ceiling->texture; + P_RemoveActiveCeiling(ceiling); + break; + + // crushers reverse direction at the top + case silentCrushAndRaise: + S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_pstop); + case genSilentCrusher: + case genCrusher: + case fastCrushAndRaise: + case crushAndRaise: + ceiling->direction = -1; + break; + + default: + break; + } + } + break; + + case -1: + // Ceiling moving down + res = T_MovePlane + ( + ceiling->sector, + ceiling->speed, + ceiling->bottomheight, + ceiling->crush, + 1, + ceiling->direction + ); + + // if not silent crusher type make moving sound + if (!(leveltime&7)) + { + switch(ceiling->type) + { + case silentCrushAndRaise: + case genSilentCrusher: + break; + default: + S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_stnmov); + } + } + + // handle reaching destination height + if (res == pastdest) + { + switch(ceiling->type) + { + // 02/09/98 jff change slow crushers' speed back to normal + // start back up + case genSilentCrusher: + case genCrusher: + if (ceiling->oldspeedspeed = ceiling->oldspeed; + ceiling->direction = 1; //jff 2/22/98 make it go back up! + break; + + // make platform stop at bottom of all crusher strokes + // except generalized ones, reset speed, start back up + case silentCrushAndRaise: + S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_pstop); + case crushAndRaise: + ceiling->speed = CEILSPEED; + case fastCrushAndRaise: + ceiling->direction = 1; + break; + + // in the case of ceiling mover/changer, change the texture + // then remove the active ceiling + case genCeilingChgT: + case genCeilingChg0: + ceiling->sector->special = ceiling->newspecial; + //jff add to fix bug in special transfers from changes + ceiling->sector->oldspecial = ceiling->oldspecial; + case genCeilingChg: + ceiling->sector->ceilingpic = ceiling->texture; + P_RemoveActiveCeiling(ceiling); + break; + + // all other case, just remove the active ceiling + case lowerAndCrush: + case lowerToFloor: + case lowerToLowest: + case lowerToMaxFloor: + case genCeiling: + P_RemoveActiveCeiling(ceiling); + break; + + default: + break; + } + } + else // ( res != pastdest ) + { + // handle the crusher encountering an obstacle + if (res == crushed) + { + switch(ceiling->type) + { + //jff 02/08/98 slow down slow crushers on obstacle + case genCrusher: + case genSilentCrusher: + if (ceiling->oldspeed < CEILSPEED*3) + ceiling->speed = CEILSPEED / 8; + break; + case silentCrushAndRaise: + case crushAndRaise: + case lowerAndCrush: + ceiling->speed = CEILSPEED / 8; + break; + + default: + break; + } + } + } + break; + } +} + + +// +// EV_DoCeiling +// +// Move a ceiling up/down or start a crusher +// +// Passed the linedef activating the function and the type of function desired +// returns true if a thinker started +// +int EV_DoCeiling +( line_t* line, + ceiling_e type ) +{ + int secnum; + int rtn; + sector_t* sec; + ceiling_t* ceiling; + + secnum = -1; + rtn = 0; + + // Reactivate in-stasis ceilings...for certain types. + // This restarts a crusher after it has been stopped + switch(type) + { + case fastCrushAndRaise: + case silentCrushAndRaise: + case crushAndRaise: + //jff 4/5/98 return if activated + rtn = P_ActivateInStasisCeiling(line); + default: + break; + } + + // affects all sectors with the same tag as the linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + + // if ceiling already moving, don't start a second function on it + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + continue; + + // create a new ceiling thinker + rtn = 1; + ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0); + memset(ceiling, 0, sizeof(*ceiling)); + P_AddThinker (&ceiling->thinker); + sec->ceilingdata = ceiling; //jff 2/22/98 + ceiling->thinker.function = T_MoveCeiling; + ceiling->sector = sec; + ceiling->crush = false; + + // setup ceiling structure according to type of function + switch(type) + { + case fastCrushAndRaise: + ceiling->crush = true; + ceiling->topheight = sec->ceilingheight; + ceiling->bottomheight = sec->floorheight + (8*FRACUNIT); + ceiling->direction = -1; + ceiling->speed = CEILSPEED * 2; + break; + + case silentCrushAndRaise: + case crushAndRaise: + ceiling->crush = true; + ceiling->topheight = sec->ceilingheight; + case lowerAndCrush: + case lowerToFloor: + ceiling->bottomheight = sec->floorheight; + if (type != lowerToFloor) + ceiling->bottomheight += 8*FRACUNIT; + ceiling->direction = -1; + ceiling->speed = CEILSPEED; + break; + + case raiseToHighest: + ceiling->topheight = P_FindHighestCeilingSurrounding(sec); + ceiling->direction = 1; + ceiling->speed = CEILSPEED; + break; + + case lowerToLowest: + ceiling->bottomheight = P_FindLowestCeilingSurrounding(sec); + ceiling->direction = -1; + ceiling->speed = CEILSPEED; + break; + + case lowerToMaxFloor: + ceiling->bottomheight = P_FindHighestFloorSurrounding(sec); + ceiling->direction = -1; + ceiling->speed = CEILSPEED; + break; + + default: + break; + } + + // add the ceiling to the active list + ceiling->tag = sec->tag; + ceiling->type = type; + P_AddActiveCeiling(ceiling); + } + return rtn; +} + +////////////////////////////////////////////////////////////////////// +// +// Active ceiling list primitives +// +///////////////////////////////////////////////////////////////////// + +// jff 2/22/98 - modified Lee's plat code to work for ceilings +// +// The following were all rewritten by Lee Killough +// to use the new structure which places no limits +// on active ceilings. It also avoids spending as much +// time searching for active ceilings. Previously a +// fixed-size array was used, with NULL indicating +// empty entries, while now a doubly-linked list +// is used. + +// +// P_ActivateInStasisCeiling() +// +// Reactivates all stopped crushers with the right tag +// +// Passed the line reactivating the crusher +// Returns true if a ceiling reactivated +// +//jff 4/5/98 return if activated +int P_ActivateInStasisCeiling(line_t *line) +{ + ceilinglist_t *cl; + int rtn=0; + + for (cl=activeceilings; cl; cl=cl->next) + { + ceiling_t *ceiling = cl->ceiling; + if (ceiling->tag == line->tag && ceiling->direction == 0) + { + ceiling->direction = ceiling->olddirection; + ceiling->thinker.function = T_MoveCeiling; + //jff 4/5/98 return if activated + rtn=1; + } + } + return rtn; +} + +// +// EV_CeilingCrushStop() +// +// Stops all active ceilings with the right tag +// +// Passed the linedef stopping the ceilings +// Returns true if a ceiling put in stasis +// +int EV_CeilingCrushStop(line_t* line) +{ + int rtn=0; + + ceilinglist_t *cl; + for (cl=activeceilings; cl; cl=cl->next) + { + ceiling_t *ceiling = cl->ceiling; + if (ceiling->direction != 0 && ceiling->tag == line->tag) + { + ceiling->olddirection = ceiling->direction; + ceiling->direction = 0; + ceiling->thinker.function = NULL; + rtn=1; + } + } + return rtn; +} + +// +// P_AddActiveCeiling() +// +// Adds a ceiling to the head of the list of active ceilings +// +// Passed the ceiling motion structure +// Returns nothing +// +void P_AddActiveCeiling(ceiling_t* ceiling) +{ + ceilinglist_t *list = malloc(sizeof *list); + list->ceiling = ceiling; + ceiling->list = list; + if ((list->next = activeceilings)) + list->next->prev = &list->next; + list->prev = &activeceilings; + activeceilings = list; +} + +// +// P_RemoveActiveCeiling() +// +// Removes a ceiling from the list of active ceilings +// +// Passed the ceiling motion structure +// Returns nothing +// +void P_RemoveActiveCeiling(ceiling_t* ceiling) +{ + ceilinglist_t *list = ceiling->list; + ceiling->sector->ceilingdata = NULL; //jff 2/22/98 + P_RemoveThinker(&ceiling->thinker); + if ((*list->prev = list->next)) + list->next->prev = list->prev; + free(list); +} + +// +// P_RemoveAllActiveCeilings() +// +// Removes all ceilings from the active ceiling list +// +// Passed nothing, returns nothing +// +void P_RemoveAllActiveCeilings(void) +{ + while (activeceilings) + { + ceilinglist_t *next = activeceilings->next; + free(activeceilings); + activeceilings = next; + } +} diff --git a/src/p_checksum.c b/src/p_checksum.c new file mode 100644 index 0000000..5fb6101 --- /dev/null +++ b/src/p_checksum.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include /* exit(), atexit() */ + +#include "p_checksum.h" +#include "md5.h" +#include "doomstat.h" /* players{,ingame} */ +#include "lprintf.h" + +/* forward decls */ +static void p_checksum_cleanup(void); +void checksum_gamestate(int tic); + +/* vars */ +static void p_checksum_nop(int tic){} /* do nothing */ +void (*P_Checksum)(int) = p_checksum_nop; + +/* + * P_RecordChecksum + * sets up the file and function pointers to write out checksum data + */ +static FILE *outfile = NULL; +static struct MD5Context md5global; + +void P_RecordChecksum(const char *file) { + size_t fnsize; + + fnsize = strlen(file); + + /* special case: write to stdout */ + if(0 == strncmp("-",file,MIN(1,fnsize))) + outfile = stdout; + else { + outfile = fopen(file,"wb"); + if(NULL == outfile) { + I_Error("cannot open %s for writing checksum:\n%s\n", + file, strerror(errno)); + } + atexit(p_checksum_cleanup); + } + + MD5Init(&md5global); + + P_Checksum = checksum_gamestate; +} + +void P_ChecksumFinal(void) { + int i; + unsigned char digest[16]; + + if (!outfile) + return; + + MD5Final(digest, &md5global); + fprintf(outfile, "final: "); + for (i=0; i<16; i++) + fprintf(outfile,"%x", digest[i]); + fprintf(outfile, "\n"); + MD5Init(&md5global); +} + +static void p_checksum_cleanup(void) { + if (outfile && (outfile != stdout)) + fclose(outfile); +} + +/* + * runs on each tic when recording checksums + */ +void checksum_gamestate(int tic) { + int i; + struct MD5Context md5ctx; + unsigned char digest[16]; + char buffer[2048]; + + fprintf(outfile,"%6d, ", tic); + + /* based on "ArchivePlayers" */ + MD5Init(&md5ctx); + for (i=0 ; idirection) + { + case 0: + // Door is waiting + if (!--door->topcountdown) // downcount and check + { + switch(door->type) + { + case blazeRaise: + case genBlazeRaise: + door->direction = -1; // time to go back down + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdcls); + break; + + case normal: + case genRaise: + door->direction = -1; // time to go back down + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_dorcls); + break; + + case close30ThenOpen: + case genCdO: + door->direction = 1; // time to go back up + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_doropn); + break; + + case genBlazeCdO: + door->direction = 1; // time to go back up + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdopn); + break; + + default: + break; + } + } + break; + + case 2: + // Special case for sector type door that opens in 5 mins + if (!--door->topcountdown) // 5 minutes up? + { + switch(door->type) + { + case raiseIn5Mins: + door->direction = 1; // time to raise then + door->type = normal; // door acts just like normal 1 DR door now + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_doropn); + break; + + default: + break; + } + } + break; + + case -1: + // Door is moving down + res = T_MovePlane + ( + door->sector, + door->speed, + door->sector->floorheight, + false, + 1, + door->direction + ); + + /* killough 10/98: implement gradual lighting effects */ + // e6y: "Tagged doors don't trigger special lighting" handled wrong + // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943 + // Old code: if (door->lighttag && door->topheight - door->sector->floorheight) + if (door->lighttag && door->topheight - door->sector->floorheight && compatibility_level >= mbf_compatibility) + EV_LightTurnOnPartway(door->line, + FixedDiv(door->sector->ceilingheight - + door->sector->floorheight, + door->topheight - + door->sector->floorheight)); + + // handle door reaching bottom + if (res == pastdest) + { + switch(door->type) + { + // regular open and close doors are all done, remove them + case blazeRaise: + case blazeClose: + case genBlazeRaise: + case genBlazeClose: + door->sector->ceilingdata = NULL; //jff 2/22/98 + P_RemoveThinker (&door->thinker); // unlink and free + // killough 4/15/98: remove double-closing sound of blazing doors + if (comp[comp_blazing]) + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdcls); + break; + + case normal: + case close: + case genRaise: + case genClose: + door->sector->ceilingdata = NULL; //jff 2/22/98 + P_RemoveThinker (&door->thinker); // unlink and free + break; + + // close then open doors start waiting + case close30ThenOpen: + door->direction = 0; + door->topcountdown = TICRATE*30; + break; + + case genCdO: + case genBlazeCdO: + door->direction = 0; + door->topcountdown = door->topwait; // jff 5/8/98 insert delay + break; + + default: + break; + } + // e6y: "Tagged doors don't trigger special lighting" handled wrong + // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943 + if (door->lighttag && door->topheight - door->sector->floorheight && compatibility_level < mbf_compatibility) + EV_LightTurnOnPartway(door->line,0); + } + /* jff 1/31/98 turn lighting off in tagged sectors of manual doors + * killough 10/98: replaced with gradual lighting code + */ + else if (res == crushed) // handle door meeting obstruction on way down + { + switch(door->type) + { + case genClose: + case genBlazeClose: + case blazeClose: + case close: // Close types do not bounce, merely wait + break; + + case blazeRaise: + case genBlazeRaise: + door->direction = 1; + if (!comp[comp_blazing]) { + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_bdopn); + break; + } + + default: // other types bounce off the obstruction + door->direction = 1; + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_doropn); + break; + } + } + break; + + case 1: + // Door is moving up + res = T_MovePlane + ( + door->sector, + door->speed, + door->topheight, + false, + 1, + door->direction + ); + + /* killough 10/98: implement gradual lighting effects */ + // e6y: "Tagged doors don't trigger special lighting" handled wrong + // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943 + // Old code: if (door->lighttag && door->topheight - door->sector->floorheight) + if (door->lighttag && door->topheight - door->sector->floorheight && compatibility_level >= mbf_compatibility) + EV_LightTurnOnPartway(door->line, + FixedDiv(door->sector->ceilingheight - + door->sector->floorheight, + door->topheight - + door->sector->floorheight)); + + // handle door reaching the top + if (res == pastdest) + { + switch(door->type) + { + case blazeRaise: // regular open/close doors start waiting + case normal: + case genRaise: + case genBlazeRaise: + door->direction = 0; // wait at top with delay + door->topcountdown = door->topwait; + break; + + case close30ThenOpen: // close and close/open doors are done + case blazeOpen: + case open: + case genBlazeOpen: + case genOpen: + case genCdO: + case genBlazeCdO: + door->sector->ceilingdata = NULL; //jff 2/22/98 + P_RemoveThinker (&door->thinker); // unlink and free + break; + + default: + break; + } + + /* jff 1/31/98 turn lighting on in tagged sectors of manual doors + * killough 10/98: replaced with gradual lighting code */ + // e6y: "Tagged doors don't trigger special lighting" handled wrong + // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943 + if (door->lighttag && door->topheight - door->sector->floorheight && compatibility_level < mbf_compatibility) + EV_LightTurnOnPartway(door->line,FRACUNIT); + } + break; + } +} + +/////////////////////////////////////////////////////////////// +// +// Door linedef handlers +// +/////////////////////////////////////////////////////////////// + +// +// EV_DoLockedDoor +// +// Handle opening a tagged locked door +// +// Passed the line activating the door, the type of door, +// and the thing that activated the line +// Returns true if a thinker created +// +int EV_DoLockedDoor +( line_t* line, + vldoor_e type, + mobj_t* thing ) +{ + player_t* p; + + // only players can open locked doors + p = thing->player; + if (!p) + return 0; + + // check type of linedef, and if key is possessed to open it + switch(line->special) + { + case 99: // Blue Lock + case 133: + if (!p->cards[it_bluecard] && !p->cards[it_blueskull]) + { + p->message = s_PD_BLUEO; // Ty 03/27/98 - externalized + S_StartSound(p->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + + case 134: // Red Lock + case 135: + if (!p->cards[it_redcard] && !p->cards[it_redskull]) + { + p->message = s_PD_REDO; // Ty 03/27/98 - externalized + S_StartSound(p->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + + case 136: // Yellow Lock + case 137: + if (!p->cards[it_yellowcard] && !p->cards[it_yellowskull]) + { + p->message = s_PD_YELLOWO; // Ty 03/27/98 - externalized + S_StartSound(p->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + } + + // got the key, so open the door + return EV_DoDoor(line,type); +} + + +// +// EV_DoDoor +// +// Handle opening a tagged door +// +// Passed the line activating the door and the type of door +// Returns true if a thinker created +// +int EV_DoDoor +( line_t* line, + vldoor_e type ) +{ + int secnum,rtn; + sector_t* sec; + vldoor_t* door; + + secnum = -1; + rtn = 0; + + // open all doors with the same tag as the activating line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + // if the ceiling already moving, don't start the door action + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + continue; + + // new door thinker + rtn = 1; + door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); + memset(door, 0, sizeof(*door)); + P_AddThinker (&door->thinker); + sec->ceilingdata = door; //jff 2/22/98 + + door->thinker.function = T_VerticalDoor; + door->sector = sec; + door->type = type; + door->topwait = VDOORWAIT; + door->speed = VDOORSPEED; + door->line = line; // jff 1/31/98 remember line that triggered us + door->lighttag = 0; /* killough 10/98: no light effects with tagged doors */ + + // setup door parameters according to type of door + switch(type) + { + case 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); + break; + + case close: + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + door->direction = -1; + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_dorcls); + break; + + case close30ThenOpen: + door->topheight = sec->ceilingheight; + door->direction = -1; + S_StartSound((mobj_t *)&door->sector->soundorg,sfx_dorcls); + break; + + case blazeRaise: + case 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); + break; + + case normal: + case 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); + break; + + default: + break; + } + } + return rtn; +} + + +// +// EV_VerticalDoor +// +// Handle opening a door manually, no tag value +// +// Passed the line activating the door and the thing activating it +// Returns true if a thinker created +// +// jff 2/12/98 added int return value, fixed all returns +// +int EV_VerticalDoor +( line_t* line, + mobj_t* thing ) +{ + player_t* player; + int secnum; + sector_t* sec; + vldoor_t* door; + + // Check for locks + player = thing->player; + + switch(line->special) + { + case 26: // Blue Lock + case 32: + if ( !player ) + return 0; + if (!player->cards[it_bluecard] && !player->cards[it_blueskull]) + { + player->message = s_PD_BLUEK; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + + case 27: // Yellow Lock + case 34: + if ( !player ) + return 0; + if (!player->cards[it_yellowcard] && !player->cards[it_yellowskull]) + { + player->message = s_PD_YELLOWK; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + + case 28: // Red Lock + case 33: + if ( !player ) + return 0; + if (!player->cards[it_redcard] && !player->cards[it_redskull]) + { + player->message = s_PD_REDK; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return 0; + } + break; + + default: + break; + } + + // if the wrong side of door is pushed, give oof sound + if (line->sidenum[1]==NO_INDEX) // killough + { + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return 0; + } + + // get the sector on the second side of activating linedef + sec = sides[line->sidenum[1]].sector; + secnum = sec-sectors; + + /* if door already has a thinker, use it + * cph 2001/04/05 - + * Ok, this is a disaster area. We're assuming that sec->ceilingdata + * is a vldoor_t! What if this door is controlled by both DR lines + * and by switches? I don't know how to fix that. + * Secondly, original Doom didn't distinguish floor/lighting/ceiling + * actions, so we need to do the same in demo compatibility mode. + */ + door = sec->ceilingdata; + if (demo_compatibility) { + if (!door) door = sec->floordata; + if (!door) door = sec->lightingdata; + } + /* If this is a repeatable line, and the door is already moving, then we can just reverse the current action. Note that in prboom 2.3.0 I erroneously removed the if-this-is-repeatable check, hence the prboom_4_compatibility clause below (foolishly assumed that already moving implies repeatable - but it could be moving due to another switch, e.g. lv19-509) */ + if (door && + ((compatibility_level == prboom_4_compatibility) || + (line->special == 1) || (line->special == 117) || (line->special == 26) || (line->special == 27) || (line->special == 28) + ) + ) { + /* For old demos we have to emulate the old buggy behavior and + * mess up non-T_VerticalDoor actions. + */ + if (compatibility_level < prboom_4_compatibility || + door->thinker.function == T_VerticalDoor) { + /* cph - we are writing outval to door->direction iff it is non-zero */ + signed int outval = 0; + + /* An already moving repeatable door which is being re-pressed, or a + * monster is trying to open a closing door - so change direction + * DEMOSYNC: we only read door->direction now if it really is a door. + */ + if (door->thinker.function == T_VerticalDoor && door->direction == -1) { + outval = 1; /* go back up */ + } else if (player) { + outval = -1; /* go back down */ + } + + /* Write this to the thinker. In demo compatibility mode, we might be + * overwriting a field of a non-vldoor_t thinker - we need to add any + * other thinker types here if any demos depend on specific fields + * being corrupted by this. + */ + if (outval) { + if (door->thinker.function == T_VerticalDoor) { + door->direction = outval; + } else if (door->thinker.function == T_PlatRaise) { + plat_t* p = (plat_t*)door; + p->wait = outval; + } else { + lprintf(LO_DEBUG, "EV_VerticalDoor: unknown thinker.function in thinker corruption emulation"); + } + + return 1; + } + } + /* Either we're in prboom >=v2.3 and it's not a door, or it's a door but + * we're a monster and don't want to shut it; exit with no action. + */ + return 0; + } + + // emit proper sound + switch(line->special) + { + case 117: // blazing door raise + case 118: // blazing door open + S_StartSound((mobj_t *)&sec->soundorg,sfx_bdopn); + break; + + default: // normal or locked door sound + S_StartSound((mobj_t *)&sec->soundorg,sfx_doropn); + break; + } + + // new door thinker + door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); + memset(door, 0, sizeof(*door)); + P_AddThinker (&door->thinker); + sec->ceilingdata = door; //jff 2/22/98 + door->thinker.function = T_VerticalDoor; + door->sector = sec; + door->direction = 1; + door->speed = VDOORSPEED; + door->topwait = VDOORWAIT; + door->line = line; // jff 1/31/98 remember line that triggered us + + /* killough 10/98: use gradual lighting changes if nonzero tag given */ + door->lighttag = comp[comp_doorlight] ? 0 : line->tag; + + // set the type of door from the activating linedef type + switch(line->special) + { + case 1: + case 26: + case 27: + case 28: + door->type = normal; + break; + + case 31: + case 32: + case 33: + case 34: + door->type = open; + line->special = 0; + break; + + case 117: // blazing door raise + door->type = blazeRaise; + door->speed = VDOORSPEED*4; + break; + case 118: // blazing door open + door->type = blazeOpen; + line->special = 0; + door->speed = VDOORSPEED*4; + break; + + default: + door->lighttag = 0; // killough 10/98 + break; + } + + // find the top and bottom of the movement range + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + return 1; +} + + +/////////////////////////////////////////////////////////////// +// +// Sector type door spawners +// +/////////////////////////////////////////////////////////////// + +// +// P_SpawnDoorCloseIn30() +// +// Spawn a door that closes after 30 seconds (called at level init) +// +// Passed the sector of the door, whose type specified the door action +// Returns nothing +// +void P_SpawnDoorCloseIn30 (sector_t* sec) +{ + vldoor_t* door; + + door = Z_Malloc ( sizeof(*door), PU_LEVSPEC, 0); + + memset(door, 0, sizeof(*door)); + P_AddThinker (&door->thinker); + + sec->ceilingdata = door; //jff 2/22/98 + sec->special = 0; + + door->thinker.function = T_VerticalDoor; + door->sector = sec; + door->direction = 0; + door->type = normal; + door->speed = VDOORSPEED; + door->topcountdown = 30 * 35; + door->line = NULL; // jff 1/31/98 remember line that triggered us + door->lighttag = 0; /* killough 10/98: no lighting changes */ +} + +// +// P_SpawnDoorRaiseIn5Mins() +// +// Spawn a door that opens after 5 minutes (called at level init) +// +// Passed the sector of the door, whose type specified the door action +// Returns nothing +// +void P_SpawnDoorRaiseIn5Mins +( sector_t* sec, + int secnum ) +{ + vldoor_t* door; + + door = Z_Malloc ( sizeof(*door), PU_LEVSPEC, 0); + + memset(door, 0, sizeof(*door)); + P_AddThinker (&door->thinker); + + sec->ceilingdata = door; //jff 2/22/98 + sec->special = 0; + + door->thinker.function = T_VerticalDoor; + door->sector = sec; + door->direction = 2; + door->type = raiseIn5Mins; + door->speed = VDOORSPEED; + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + door->topwait = VDOORWAIT; + door->topcountdown = 5 * 60 * 35; + door->line = NULL; // jff 1/31/98 remember line that triggered us + door->lighttag = 0; /* killough 10/98: no lighting changes */ +} diff --git a/src/p_enemy.c b/src/p_enemy.c new file mode 100644 index 0000000..937321e --- /dev/null +++ b/src/p_enemy.c @@ -0,0 +1,2601 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000,2002 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Enemy thinking, AI. + * Action Pointer Functions + * that are associated with states/frames. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "m_random.h" +#include "r_main.h" +#include "p_maputl.h" +#include "p_map.h" +#include "p_setup.h" +#include "p_spec.h" +#include "s_sound.h" +#include "sounds.h" +#include "p_inter.h" +#include "g_game.h" +#include "p_enemy.h" +#include "p_tick.h" +#include "m_bbox.h" +#include "lprintf.h" + +static mobj_t *current_actor; + +typedef enum { + DI_EAST, + DI_NORTHEAST, + DI_NORTH, + DI_NORTHWEST, + DI_WEST, + DI_SOUTHWEST, + DI_SOUTH, + DI_SOUTHEAST, + DI_NODIR, + NUMDIRS +} dirtype_t; + +static void P_NewChaseDir(mobj_t *actor); +void P_ZBumpCheck(mobj_t *); // phares + +// +// ENEMY THINKING +// Enemies are allways spawned +// with targetplayer = -1, threshold = 0 +// Most monsters are spawned unaware of all players, +// but some can be made preaware +// + +// +// Called by P_NoiseAlert. +// Recursively traverse adjacent sectors, +// sound blocking lines cut off traversal. +// +// killough 5/5/98: reformatted, cleaned up + +static void P_RecursiveSound(sector_t *sec, int soundblocks, + mobj_t *soundtarget) +{ + int i; + + // wake up all monsters in this sector + if (sec->validcount == validcount && sec->soundtraversed <= soundblocks+1) + return; // already flooded + + sec->validcount = validcount; + sec->soundtraversed = soundblocks+1; + P_SetTarget(&sec->soundtarget, soundtarget); + + for (i=0; ilinecount; i++) + { + sector_t *other; + line_t *check = sec->lines[i]; + + if (!(check->flags & ML_TWOSIDED)) + continue; + + P_LineOpening(check); + + if (openrange <= 0) + continue; // closed door + + other=sides[check->sidenum[sides[check->sidenum[0]].sector==sec]].sector; + + if (!(check->flags & ML_SOUNDBLOCK)) + P_RecursiveSound(other, soundblocks, soundtarget); + else + if (!soundblocks) + P_RecursiveSound(other, 1, soundtarget); + } +} + +// +// P_NoiseAlert +// If a monster yells at a player, +// it will alert other monsters to the player. +// +void P_NoiseAlert(mobj_t *target, mobj_t *emitter) +{ + validcount++; + P_RecursiveSound(emitter->subsector->sector, 0, target); +} + +// +// P_CheckMeleeRange +// + +static boolean P_CheckMeleeRange(mobj_t *actor) +{ + mobj_t *pl = actor->target; + + return // killough 7/18/98: friendly monsters don't attack other friends + pl && !(actor->flags & pl->flags & MF_FRIEND) && + (P_AproxDistance(pl->x-actor->x, pl->y-actor->y) < + MELEERANGE - 20*FRACUNIT + pl->info->radius) && + P_CheckSight(actor, actor->target); +} + +// +// P_HitFriend() +// +// killough 12/98 +// This function tries to prevent shooting at friends + +static boolean P_HitFriend(mobj_t *actor) +{ + return actor->flags & MF_FRIEND && actor->target && + (P_AimLineAttack(actor, + R_PointToAngle2(actor->x, actor->y, + actor->target->x, actor->target->y), + P_AproxDistance(actor->x-actor->target->x, + actor->y-actor->target->y), 0), + linetarget) && linetarget != actor->target && + !((linetarget->flags ^ actor->flags) & MF_FRIEND); +} + +// +// P_CheckMissileRange +// +static boolean P_CheckMissileRange(mobj_t *actor) +{ + fixed_t dist; + + if (!P_CheckSight(actor, actor->target)) + return false; + + if (actor->flags & MF_JUSTHIT) + { // the target just hit the enemy, so fight back! + actor->flags &= ~MF_JUSTHIT; + + /* killough 7/18/98: no friendly fire at corpses + * killough 11/98: prevent too much infighting among friends + * cph - yikes, talk about fitting everything on one line... */ + + return + !(actor->flags & MF_FRIEND) || + (actor->target->health > 0 && + (!(actor->target->flags & MF_FRIEND) || + (actor->target->player ? + monster_infighting || P_Random(pr_defect) >128 : + !(actor->target->flags & MF_JUSTHIT) && P_Random(pr_defect) >128))); + } + + /* killough 7/18/98: friendly monsters don't attack other friendly + * monsters or players (except when attacked, and then only once) + */ + if (actor->flags & actor->target->flags & MF_FRIEND) + return false; + + if (actor->reactiontime) + return false; // do not attack yet + + // OPTIMIZE: get this from a global checksight + dist = P_AproxDistance ( actor->x-actor->target->x, + actor->y-actor->target->y) - 64*FRACUNIT; + + if (!actor->info->meleestate) + dist -= 128*FRACUNIT; // no melee attack, so fire more + + dist >>= FRACBITS; + + if (actor->type == MT_VILE) + if (dist > 14*64) + return false; // too far away + + + if (actor->type == MT_UNDEAD) + { + if (dist < 196) + return false; // close for fist attack + dist >>= 1; + } + + if (actor->type == MT_CYBORG || + actor->type == MT_SPIDER || + actor->type == MT_SKULL) + dist >>= 1; + + if (dist > 200) + dist = 200; + + if (actor->type == MT_CYBORG && dist > 160) + dist = 160; + + if (P_Random(pr_missrange) < dist) + return false; + + if (P_HitFriend(actor)) + return false; + + return true; +} + +/* + * P_IsOnLift + * + * killough 9/9/98: + * + * Returns true if the object is on a lift. Used for AI, + * since it may indicate the need for crowded conditions, + * or that a monster should stay on the lift for a while + * while it goes up or down. + */ + +static boolean P_IsOnLift(const mobj_t *actor) +{ + const sector_t *sec = actor->subsector->sector; + line_t line; + int l; + + // Short-circuit: it's on a lift which is active. + if (sec->floordata && ((thinker_t *) sec->floordata)->function==T_PlatRaise) + return true; + + // Check to see if it's in a sector which can be activated as a lift. + if ((line.tag = sec->tag)) + for (l = -1; (l = P_FindLineFromLineTag(&line, l)) >= 0;) + switch (lines[l].special) + { + case 10: case 14: case 15: case 20: case 21: case 22: + case 47: case 53: case 62: case 66: case 67: case 68: + case 87: case 88: case 95: case 120: case 121: case 122: + case 123: case 143: case 162: case 163: case 181: case 182: + case 144: case 148: case 149: case 211: case 227: case 228: + case 231: case 232: case 235: case 236: + return true; + } + + return false; +} + +/* + * P_IsUnderDamage + * + * killough 9/9/98: + * + * Returns nonzero if the object is under damage based on + * their current position. Returns 1 if the damage is moderate, + * -1 if it is serious. Used for AI. + */ + +static int P_IsUnderDamage(mobj_t *actor) +{ + const struct msecnode_s *seclist; + const ceiling_t *cl; // Crushing ceiling + int dir = 0; + for (seclist=actor->touching_sectorlist; seclist; seclist=seclist->m_tnext) + if ((cl = seclist->m_sector->ceilingdata) && + cl->thinker.function == T_MoveCeiling) + dir |= cl->direction; + return dir; +} + +// +// P_Move +// Move in the current direction, +// returns false if the move is blocked. +// + +static fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000}; +static fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000}; + +// 1/11/98 killough: Limit removed on special lines crossed +extern line_t **spechit; // New code -- killough +extern int numspechit; + +static boolean P_Move(mobj_t *actor, boolean dropoff) /* killough 9/12/98 */ +{ + fixed_t tryx, tryy, deltax, deltay, origx, origy; + boolean try_ok; + int movefactor = ORIG_FRICTION_FACTOR; // killough 10/98 + int friction = ORIG_FRICTION; + int speed; + + if (actor->movedir == DI_NODIR) + return false; + +#ifdef RANGECHECK + if ((unsigned)actor->movedir >= 8) + I_Error ("P_Move: Weird actor->movedir!"); +#endif + + // killough 10/98: make monsters get affected by ice and sludge too: + + if (monster_friction) + movefactor = P_GetMoveFactor(actor, &friction); + + speed = actor->info->speed; + + if (friction < ORIG_FRICTION && // sludge + !(speed = ((ORIG_FRICTION_FACTOR - (ORIG_FRICTION_FACTOR-movefactor)/2) + * speed) / ORIG_FRICTION_FACTOR)) + speed = 1; // always give the monster a little bit of speed + + tryx = (origx = actor->x) + (deltax = speed * xspeed[actor->movedir]); + tryy = (origy = actor->y) + (deltay = speed * yspeed[actor->movedir]); + + try_ok = P_TryMove(actor, tryx, tryy, dropoff); + + // killough 10/98: + // Let normal momentum carry them, instead of steptoeing them across ice. + + if (try_ok && friction > ORIG_FRICTION) + { + actor->x = origx; + actor->y = origy; + movefactor *= FRACUNIT / ORIG_FRICTION_FACTOR / 4; + actor->momx += FixedMul(deltax, movefactor); + actor->momy += FixedMul(deltay, movefactor); + } + + if (!try_ok) + { // open any specials + int good; + + if (actor->flags & MF_FLOAT && floatok) + { + if (actor->z < tmfloorz) // must adjust height + actor->z += FLOATSPEED; + else + actor->z -= FLOATSPEED; + + actor->flags |= MF_INFLOAT; + + return true; + } + + if (!numspechit) + return false; + + actor->movedir = DI_NODIR; + + /* if the special is not a door that can be opened, return false + * + * killough 8/9/98: this is what caused monsters to get stuck in + * doortracks, because it thought that the monster freed itself + * by opening a door, even if it was moving towards the doortrack, + * and not the door itself. + * + * killough 9/9/98: If a line blocking the monster is activated, + * return true 90% of the time. If a line blocking the monster is + * not activated, but some other line is, return false 90% of the + * time. A bit of randomness is needed to ensure it's free from + * lockups, but for most cases, it returns the correct result. + * + * Do NOT simply return false 1/4th of the time (causes monsters to + * back out when they shouldn't, and creates secondary stickiness). + */ + + for (good = false; numspechit--; ) + if (P_UseSpecialLine(actor, spechit[numspechit], 0)) + good |= spechit[numspechit] == blockline ? 1 : 2; + + /* cph - compatibility maze here + * Boom v2.01 and orig. Doom return "good" + * Boom v2.02 and LxDoom return good && (P_Random(pr_trywalk)&3) + * MBF plays even more games + */ + if (!good || comp[comp_doorstuck]) return good; + if (!mbf_features) + return (P_Random(pr_trywalk)&3); /* jff 8/13/98 */ + else /* finally, MBF code */ + return ((P_Random(pr_opendoor) >= 230) ^ (good & 1)); + } + else + actor->flags &= ~MF_INFLOAT; + + /* killough 11/98: fall more slowly, under gravity, if felldown==true */ + if (!(actor->flags & MF_FLOAT) && + (!felldown || !mbf_features)) + actor->z = actor->floorz; + + return true; +} + +/* + * P_SmartMove + * + * killough 9/12/98: Same as P_Move, except smarter + */ + +static boolean P_SmartMove(mobj_t *actor) +{ + mobj_t *target = actor->target; + int on_lift, dropoff = false, under_damage; + + /* killough 9/12/98: Stay on a lift if target is on one */ + on_lift = !comp[comp_staylift] + && target && target->health > 0 + && target->subsector->sector->tag==actor->subsector->sector->tag && + P_IsOnLift(actor); + + under_damage = monster_avoid_hazards && P_IsUnderDamage(actor); + + // killough 10/98: allow dogs to drop off of taller ledges sometimes. + // dropoff==1 means always allow it, dropoff==2 means only up to 128 high, + // and only if the target is immediately on the other side of the line. + +#ifdef DOGS + // haleyjd: allow all friends of HelperType to also jump down + + if ((actor->type == MT_DOGS || (actor->type == (HelperThing-1) && actor->flags&MF_FRIEND)) + && target && dog_jumping && + !((target->flags ^ actor->flags) & MF_FRIEND) && + P_AproxDistance(actor->x - target->x, + actor->y - target->y) < FRACUNIT*144 && + P_Random(pr_dropoff) < 235) + dropoff = 2; +#endif + + if (!P_Move(actor, dropoff)) + return false; + + // killough 9/9/98: avoid crushing ceilings or other damaging areas + if ( + (on_lift && P_Random(pr_stayonlift) < 230 && // Stay on lift + !P_IsOnLift(actor)) + || + (monster_avoid_hazards && !under_damage && // Get away from damage + (under_damage = P_IsUnderDamage(actor)) && + (under_damage < 0 || P_Random(pr_avoidcrush) < 200)) + ) + actor->movedir = DI_NODIR; // avoid the area (most of the time anyway) + + return true; +} + +// +// TryWalk +// Attempts to move actor on +// in its current (ob->moveangle) direction. +// If blocked by either a wall or an actor +// returns FALSE +// If move is either clear or blocked only by a door, +// returns TRUE and sets... +// If a door is in the way, +// an OpenDoor call is made to start it opening. +// + +static boolean P_TryWalk(mobj_t *actor) +{ + if (!P_SmartMove(actor)) + return false; + actor->movecount = P_Random(pr_trywalk)&15; + return true; +} + +// +// P_DoNewChaseDir +// +// killough 9/8/98: +// +// Most of P_NewChaseDir(), except for what +// determines the new direction to take +// + +static void P_DoNewChaseDir(mobj_t *actor, fixed_t deltax, fixed_t deltay) +{ + dirtype_t xdir, ydir, tdir; + dirtype_t olddir = actor->movedir; + dirtype_t turnaround = olddir; + + if (turnaround != DI_NODIR) // find reverse direction + turnaround ^= 4; + + xdir = + deltax > 10*FRACUNIT ? DI_EAST : + deltax < -10*FRACUNIT ? DI_WEST : DI_NODIR; + + ydir = + deltay < -10*FRACUNIT ? DI_SOUTH : + deltay > 10*FRACUNIT ? DI_NORTH : DI_NODIR; + + // try direct route + if (xdir != DI_NODIR && ydir != DI_NODIR && turnaround != + (actor->movedir = deltay < 0 ? deltax > 0 ? DI_SOUTHEAST : DI_SOUTHWEST : + deltax > 0 ? DI_NORTHEAST : DI_NORTHWEST) && P_TryWalk(actor)) + return; + + // try other directions + if (P_Random(pr_newchase) > 200 || D_abs(deltay)>D_abs(deltax)) + tdir = xdir, xdir = ydir, ydir = tdir; + + if ((xdir == turnaround ? xdir = DI_NODIR : xdir) != DI_NODIR && + (actor->movedir = xdir, P_TryWalk(actor))) + return; // either moved forward or attacked + + if ((ydir == turnaround ? ydir = DI_NODIR : ydir) != DI_NODIR && + (actor->movedir = ydir, P_TryWalk(actor))) + return; + + // there is no direct path to the player, so pick another direction. + if (olddir != DI_NODIR && (actor->movedir = olddir, P_TryWalk(actor))) + return; + + // randomly determine direction of search + if (P_Random(pr_newchasedir) & 1) + { + for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++) + if (tdir != turnaround && (actor->movedir = tdir, P_TryWalk(actor))) + return; + } + else + for (tdir = DI_SOUTHEAST; tdir != DI_EAST-1; tdir--) + if (tdir != turnaround && (actor->movedir = tdir, P_TryWalk(actor))) + return; + + if ((actor->movedir = turnaround) != DI_NODIR && !P_TryWalk(actor)) + actor->movedir = DI_NODIR; +} + +// +// killough 11/98: +// +// Monsters try to move away from tall dropoffs. +// +// In Doom, they were never allowed to hang over dropoffs, +// and would remain stuck if involuntarily forced over one. +// This logic, combined with p_map.c (P_TryMove), allows +// monsters to free themselves without making them tend to +// hang over dropoffs. + +static fixed_t dropoff_deltax, dropoff_deltay, floorz; + +static boolean PIT_AvoidDropoff(line_t *line) +{ + if (line->backsector && // Ignore one-sided linedefs + tmbbox[BOXRIGHT] > line->bbox[BOXLEFT] && + tmbbox[BOXLEFT] < line->bbox[BOXRIGHT] && + tmbbox[BOXTOP] > line->bbox[BOXBOTTOM] && // Linedef must be contacted + tmbbox[BOXBOTTOM] < line->bbox[BOXTOP] && + P_BoxOnLineSide(tmbbox, line) == -1) + { + fixed_t front = line->frontsector->floorheight; + fixed_t back = line->backsector->floorheight; + angle_t angle; + + // The monster must contact one of the two floors, + // and the other must be a tall dropoff (more than 24). + + if (back == floorz && front < floorz - FRACUNIT*24) + angle = R_PointToAngle2(0,0,line->dx,line->dy); // front side dropoff + else + if (front == floorz && back < floorz - FRACUNIT*24) + angle = R_PointToAngle2(line->dx,line->dy,0,0); // back side dropoff + else + return true; + + // Move away from dropoff at a standard speed. + // Multiple contacted linedefs are cumulative (e.g. hanging over corner) + dropoff_deltax -= finesine[angle >> ANGLETOFINESHIFT]*32; + dropoff_deltay += finecosine[angle >> ANGLETOFINESHIFT]*32; + } + return true; +} + +// +// Driver for above +// + +static fixed_t P_AvoidDropoff(mobj_t *actor) +{ + int yh=((tmbbox[BOXTOP] = actor->y+actor->radius)-bmaporgy)>>MAPBLOCKSHIFT; + int yl=((tmbbox[BOXBOTTOM]= actor->y-actor->radius)-bmaporgy)>>MAPBLOCKSHIFT; + int xh=((tmbbox[BOXRIGHT] = actor->x+actor->radius)-bmaporgx)>>MAPBLOCKSHIFT; + int xl=((tmbbox[BOXLEFT] = actor->x-actor->radius)-bmaporgx)>>MAPBLOCKSHIFT; + int bx, by; + + floorz = actor->z; // remember floor height + + dropoff_deltax = dropoff_deltay = 0; + + // check lines + + validcount++; + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + P_BlockLinesIterator(bx, by, PIT_AvoidDropoff); // all contacted lines + + return dropoff_deltax | dropoff_deltay; // Non-zero if movement prescribed +} + +// +// P_NewChaseDir +// +// killough 9/8/98: Split into two functions +// + +static void P_NewChaseDir(mobj_t *actor) +{ + mobj_t *target = actor->target; + fixed_t deltax = target->x - actor->x; + fixed_t deltay = target->y - actor->y; + + // killough 8/8/98: sometimes move away from target, keeping distance + // + // 1) Stay a certain distance away from a friend, to avoid being in their way + // 2) Take advantage over an enemy without missiles, by keeping distance + + actor->strafecount = 0; + + if (mbf_features) { + if (actor->floorz - actor->dropoffz > FRACUNIT*24 && + actor->z <= actor->floorz && + !(actor->flags & (MF_DROPOFF|MF_FLOAT)) && + !comp[comp_dropoff] && + P_AvoidDropoff(actor)) /* Move away from dropoff */ + { + P_DoNewChaseDir(actor, dropoff_deltax, dropoff_deltay); + + // If moving away from dropoff, set movecount to 1 so that + // small steps are taken to get monster away from dropoff. + + actor->movecount = 1; + return; + } + else + { + fixed_t dist = P_AproxDistance(deltax, deltay); + + // Move away from friends when too close, except + // in certain situations (e.g. a crowded lift) + + if (actor->flags & target->flags & MF_FRIEND && + distfriend << FRACBITS > dist && + !P_IsOnLift(target) && !P_IsUnderDamage(actor)) + { + deltax = -deltax, deltay = -deltay; + } else + if (target->health > 0 && (actor->flags ^ target->flags) & MF_FRIEND) + { // Live enemy target + if (monster_backing && + actor->info->missilestate && actor->type != MT_SKULL && + ((!target->info->missilestate && dist < MELEERANGE*2) || + (target->player && dist < MELEERANGE*3 && + (target->player->readyweapon == wp_fist || + target->player->readyweapon == wp_chainsaw)))) + { // Back away from melee attacker + actor->strafecount = P_Random(pr_enemystrafe) & 15; + deltax = -deltax, deltay = -deltay; + } + } + } + } + + P_DoNewChaseDir(actor, deltax, deltay); + + // If strafing, set movecount to strafecount so that old Doom + // logic still works the same, except in the strafing part + + if (actor->strafecount) + actor->movecount = actor->strafecount; +} + +// +// P_IsVisible +// +// killough 9/9/98: whether a target is visible to a monster +// + +static boolean P_IsVisible(mobj_t *actor, mobj_t *mo, boolean allaround) +{ + if (!allaround) + { + angle_t an = R_PointToAngle2(actor->x, actor->y, + mo->x, mo->y) - actor->angle; + if (an > ANG90 && an < ANG270 && + P_AproxDistance(mo->x-actor->x, mo->y-actor->y) > MELEERANGE) + return false; + } + return P_CheckSight(actor, mo); +} + +// +// PIT_FindTarget +// +// killough 9/5/98 +// +// Finds monster targets for other monsters +// + +static int current_allaround; + +static boolean PIT_FindTarget(mobj_t *mo) +{ + mobj_t *actor = current_actor; + + if (!((mo->flags ^ actor->flags) & MF_FRIEND && // Invalid target + mo->health > 0 && (mo->flags & MF_COUNTKILL || mo->type == MT_SKULL))) + return true; + + // If the monster is already engaged in a one-on-one attack + // with a healthy friend, don't attack around 60% the time + { + const mobj_t *targ = mo->target; + if (targ && targ->target == mo && + P_Random(pr_skiptarget) > 100 && + (targ->flags ^ mo->flags) & MF_FRIEND && + targ->health*2 >= targ->info->spawnhealth) + return true; + } + + if (!P_IsVisible(actor, mo, current_allaround)) + return true; + + P_SetTarget(&actor->lastenemy, actor->target); // Remember previous target + P_SetTarget(&actor->target, mo); // Found target + + // Move the selected monster to the end of its associated + // list, so that it gets searched last next time. + + { + thinker_t *cap = &thinkerclasscap[mo->flags & MF_FRIEND ? + th_friends : th_enemies]; + (mo->thinker.cprev->cnext = mo->thinker.cnext)->cprev = mo->thinker.cprev; + (mo->thinker.cprev = cap->cprev)->cnext = &mo->thinker; + (mo->thinker.cnext = cap)->cprev = &mo->thinker; + } + + return false; +} + +// +// P_LookForPlayers +// If allaround is false, only look 180 degrees in front. +// Returns true if a player is targeted. +// + +static boolean P_LookForPlayers(mobj_t *actor, boolean allaround) +{ + player_t *player; + int stop, stopc, c; + + if (actor->flags & MF_FRIEND) + { // killough 9/9/98: friendly monsters go about players differently + int anyone; + +#if 0 + if (!allaround) // If you want friendly monsters not to awaken unprovoked + return false; +#endif + + // Go back to a player, no matter whether it's visible or not + for (anyone=0; anyone<=1; anyone++) + for (c=0; ctarget, players[c].mo); + + // killough 12/98: + // get out of refiring loop, to avoid hitting player accidentally + + if (actor->info->missilestate) + { + P_SetMobjState(actor, actor->info->seestate); + actor->flags &= ~MF_JUSTHIT; + } + + return true; + } + + return false; + } + + // Change mask of 3 to (MAXPLAYERS-1) -- killough 2/15/98: + stop = (actor->lastlook-1)&(MAXPLAYERS-1); + + c = 0; + + stopc = !mbf_features && + !demo_compatibility && monsters_remember ? + MAXPLAYERS : 2; // killough 9/9/98 + + for (;; actor->lastlook = (actor->lastlook+1)&(MAXPLAYERS-1)) + { + if (!playeringame[actor->lastlook]) + continue; + + // killough 2/15/98, 9/9/98: + if (c++ == stopc || actor->lastlook == stop) // done looking + { + // e6y + // Fixed Boom incompatibilities. The following code was missed. + // There are no more desyncs on Donce's demos on horror.wad + + // Use last known enemy if no players sighted -- killough 2/15/98: + if (!mbf_features && !demo_compatibility && monsters_remember) + { + if (actor->lastenemy && actor->lastenemy->health > 0) + { + actor->target = actor->lastenemy; + actor->lastenemy = NULL; + return true; + } + } + + return false; + } + + player = &players[actor->lastlook]; + + if (player->health <= 0) + continue; // dead + + if (!P_IsVisible(actor, player->mo, allaround)) + continue; + + P_SetTarget(&actor->target, player->mo); + + /* killough 9/9/98: give monsters a threshold towards getting players + * (we don't want it to be too easy for a player with dogs :) + */ + if (!comp[comp_pursuit]) + actor->threshold = 60; + + return true; + } +} + +// +// Friendly monsters, by Lee Killough 7/18/98 +// +// Friendly monsters go after other monsters first, but +// also return to owner if they cannot find any targets. +// A marine's best friend :) killough 7/18/98, 9/98 +// + +static boolean P_LookForMonsters(mobj_t *actor, boolean allaround) +{ + thinker_t *cap, *th; + + if (demo_compatibility) + return false; + + if (actor->lastenemy && actor->lastenemy->health > 0 && monsters_remember && + !(actor->lastenemy->flags & actor->flags & MF_FRIEND)) // not friends + { + P_SetTarget(&actor->target, actor->lastenemy); + P_SetTarget(&actor->lastenemy, NULL); + return true; + } + + /* Old demos do not support monster-seeking bots */ + if (!mbf_features) + return false; + + // Search the threaded list corresponding to this object's potential targets + cap = &thinkerclasscap[actor->flags & MF_FRIEND ? th_enemies : th_friends]; + + // Search for new enemy + + if (cap->cnext != cap) // Empty list? bail out early + { + int x = (actor->x - bmaporgx)>>MAPBLOCKSHIFT; + int y = (actor->y - bmaporgy)>>MAPBLOCKSHIFT; + int d; + + current_actor = actor; + current_allaround = allaround; + + // Search first in the immediate vicinity. + + if (!P_BlockThingsIterator(x, y, PIT_FindTarget)) + return true; + + for (d=1; d<5; d++) + { + int i = 1 - d; + do + if (!P_BlockThingsIterator(x+i, y-d, PIT_FindTarget) || + !P_BlockThingsIterator(x+i, y+d, PIT_FindTarget)) + return true; + while (++i < d); + do + if (!P_BlockThingsIterator(x-d, y+i, PIT_FindTarget) || + !P_BlockThingsIterator(x+d, y+i, PIT_FindTarget)) + return true; + while (--i + d >= 0); + } + + { // Random number of monsters, to prevent patterns from forming + int n = (P_Random(pr_friends) & 31) + 15; + + for (th = cap->cnext; th != cap; th = th->cnext) + if (--n < 0) + { + // Only a subset of the monsters were searched. Move all of + // the ones which were searched so far, to the end of the list. + + (cap->cnext->cprev = cap->cprev)->cnext = cap->cnext; + (cap->cprev = th->cprev)->cnext = cap; + (th->cprev = cap)->cnext = th; + break; + } + else + if (!PIT_FindTarget((mobj_t *) th)) // If target sighted + return true; + } + } + + return false; // No monster found +} + +// +// P_LookForTargets +// +// killough 9/5/98: look for targets to go after, depending on kind of monster +// + +static boolean P_LookForTargets(mobj_t *actor, int allaround) +{ + return actor->flags & MF_FRIEND ? + P_LookForMonsters(actor, allaround) || P_LookForPlayers (actor, allaround): + P_LookForPlayers (actor, allaround) || P_LookForMonsters(actor, allaround); +} + +// +// P_HelpFriend +// +// killough 9/8/98: Help friends in danger of dying +// + +static boolean P_HelpFriend(mobj_t *actor) +{ + thinker_t *cap, *th; + + // If less than 33% health, self-preservation rules + if (actor->health*3 < actor->info->spawnhealth) + return false; + + current_actor = actor; + current_allaround = true; + + // Possibly help a friend under 50% health + cap = &thinkerclasscap[actor->flags & MF_FRIEND ? th_friends : th_enemies]; + + for (th = cap->cnext; th != cap; th = th->cnext) + if (((mobj_t *) th)->health*2 >= ((mobj_t *) th)->info->spawnhealth) + { + if (P_Random(pr_helpfriend) < 180) + break; + } + else + if (((mobj_t *) th)->flags & MF_JUSTHIT && + ((mobj_t *) th)->target && + ((mobj_t *) th)->target != actor->target && + !PIT_FindTarget(((mobj_t *) th)->target)) + { + // Ignore any attacking monsters, while searching for friend + actor->threshold = BASETHRESHOLD; + return true; + } + + return false; +} + +// +// A_KeenDie +// DOOM II special, map 32. +// Uses special tag 666. +// +void A_KeenDie(mobj_t* mo) +{ + thinker_t *th; + line_t junk; + + A_Fall(mo); + + // scan the remaining thinkers to see if all Keens are dead + + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + if (th->function == P_MobjThinker) + { + mobj_t *mo2 = (mobj_t *) th; + if (mo2 != mo && mo2->type == mo->type && mo2->health > 0) + return; // other Keen not dead + } + + junk.tag = 666; + EV_DoDoor(&junk,open); +} + + +// +// ACTION ROUTINES +// + +// +// A_Look +// Stay in state until a player is sighted. +// + +void A_Look(mobj_t *actor) +{ + mobj_t *targ = actor->subsector->sector->soundtarget; + actor->threshold = 0; // any shot will wake up + + /* killough 7/18/98: + * Friendly monsters go after other monsters first, but + * also return to player, without attacking them, if they + * cannot find any targets. A marine's best friend :) + */ + actor->pursuecount = 0; + + if (!(actor->flags & MF_FRIEND && P_LookForTargets(actor, false)) && + !((targ = actor->subsector->sector->soundtarget) && + targ->flags & MF_SHOOTABLE && + (P_SetTarget(&actor->target, targ), + !(actor->flags & MF_AMBUSH) || P_CheckSight(actor, targ))) && + (actor->flags & MF_FRIEND || !P_LookForTargets(actor, false))) + return; + + // go into chase state + + if (actor->info->seesound) + { + int sound; + switch (actor->info->seesound) + { + case sfx_posit1: + case sfx_posit2: + case sfx_posit3: + sound = sfx_posit1+P_Random(pr_see)%3; + break; + + case sfx_bgsit1: + case sfx_bgsit2: + sound = sfx_bgsit1+P_Random(pr_see)%2; + break; + + default: + sound = actor->info->seesound; + break; + } + if (actor->type==MT_SPIDER || actor->type == MT_CYBORG) + S_StartSound(NULL, sound); // full volume + else + S_StartSound(actor, sound); + } + P_SetMobjState(actor, actor->info->seestate); +} + +// +// A_KeepChasing +// +// killough 10/98: +// Allows monsters to continue movement while attacking +// + +static void A_KeepChasing(mobj_t *actor) +{ + if (actor->movecount) + { + actor->movecount--; + if (actor->strafecount) + actor->strafecount--; + P_SmartMove(actor); + } +} + +// +// A_Chase +// Actor has a melee attack, +// so it tries to close as fast as possible +// + +void A_Chase(mobj_t *actor) +{ + if (actor->reactiontime) + actor->reactiontime--; + + if (actor->threshold) { /* modify target threshold */ + if (!actor->target || actor->target->health <= 0) + actor->threshold = 0; + else + actor->threshold--; + } + + /* turn towards movement direction if not there yet + * killough 9/7/98: keep facing towards target if strafing or backing out + */ + + if (actor->strafecount) + A_FaceTarget(actor); + else if (actor->movedir < 8) + { + int delta = (actor->angle &= (7<<29)) - (actor->movedir << 29); + if (delta > 0) + actor->angle -= ANG90/2; + else + if (delta < 0) + actor->angle += ANG90/2; + } + + if (!actor->target || !(actor->target->flags&MF_SHOOTABLE)) + { + if (!P_LookForTargets(actor,true)) // look for a new target + P_SetMobjState(actor, actor->info->spawnstate); // no new target + return; + } + + // do not attack twice in a row + if (actor->flags & MF_JUSTATTACKED) + { + actor->flags &= ~MF_JUSTATTACKED; + if (gameskill != sk_nightmare && !fastparm) + P_NewChaseDir(actor); + return; + } + + // check for melee attack + if (actor->info->meleestate && P_CheckMeleeRange(actor)) + { + if (actor->info->attacksound) + S_StartSound(actor, actor->info->attacksound); + P_SetMobjState(actor, actor->info->meleestate); + /* killough 8/98: remember an attack + * cph - DEMOSYNC? */ + if (!actor->info->missilestate) + actor->flags |= MF_JUSTHIT; + return; + } + + // check for missile attack + if (actor->info->missilestate) + if (!(gameskill < sk_nightmare && !fastparm && actor->movecount)) + if (P_CheckMissileRange(actor)) + { + P_SetMobjState(actor, actor->info->missilestate); + actor->flags |= MF_JUSTATTACKED; + return; + } + + if (!actor->threshold) { + if (!mbf_features) + { /* killough 9/9/98: for backward demo compatibility */ + if (netgame && !P_CheckSight(actor, actor->target) && + P_LookForPlayers(actor, true)) + return; + } + /* killough 7/18/98, 9/9/98: new monster AI */ + else if (help_friends && P_HelpFriend(actor)) + return; /* killough 9/8/98: Help friends in need */ + /* Look for new targets if current one is bad or is out of view */ + else if (actor->pursuecount) + actor->pursuecount--; + else { + /* Our pursuit time has expired. We're going to think about + * changing targets */ + actor->pursuecount = BASETHRESHOLD; + + /* Unless (we have a live target + * and it's not friendly + * and we can see it) + * try to find a new one; return if sucessful */ + + if (!(actor->target && actor->target->health > 0 && + ((comp[comp_pursuit] && !netgame) || + (((actor->target->flags ^ actor->flags) & MF_FRIEND || + (!(actor->flags & MF_FRIEND) && monster_infighting)) && + P_CheckSight(actor, actor->target)))) + && P_LookForTargets(actor, true)) + return; + + /* (Current target was good, or no new target was found.) + * + * If monster is a missile-less friend, give up pursuit and + * return to player, if no attacks have occurred recently. + */ + + if (!actor->info->missilestate && actor->flags & MF_FRIEND) { + if (actor->flags & MF_JUSTHIT) /* if recent action, */ + actor->flags &= ~MF_JUSTHIT; /* keep fighting */ + else if (P_LookForPlayers(actor, true)) /* else return to player */ + return; + } + } + } + + if (actor->strafecount) + actor->strafecount--; + + // chase towards player + if (--actor->movecount<0 || !P_SmartMove(actor)) + P_NewChaseDir(actor); + + // make active sound + if (actor->info->activesound && P_Random(pr_see)<3) + S_StartSound(actor, actor->info->activesound); +} + +// +// A_FaceTarget +// +void A_FaceTarget(mobj_t *actor) +{ + if (!actor->target) + return; + actor->flags &= ~MF_AMBUSH; + actor->angle = R_PointToAngle2(actor->x, actor->y, + actor->target->x, actor->target->y); + if (actor->target->flags & MF_SHADOW) + { // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_facetarget); + actor->angle += (t-P_Random(pr_facetarget))<<21; + } +} + +// +// A_PosAttack +// + +void A_PosAttack(mobj_t *actor) +{ + int angle, damage, slope, t; + + if (!actor->target) + return; + A_FaceTarget(actor); + angle = actor->angle; + slope = P_AimLineAttack(actor, angle, MISSILERANGE, 0); /* killough 8/2/98 */ + S_StartSound(actor, sfx_pistol); + + // killough 5/5/98: remove dependence on order of evaluation: + t = P_Random(pr_posattack); + angle += (t - P_Random(pr_posattack))<<20; + damage = (P_Random(pr_posattack)%5 + 1)*3; + P_LineAttack(actor, angle, MISSILERANGE, slope, damage); +} + +void A_SPosAttack(mobj_t* actor) +{ + int i, bangle, slope; + + if (!actor->target) + return; + S_StartSound(actor, sfx_shotgn); + A_FaceTarget(actor); + bangle = actor->angle; + slope = P_AimLineAttack(actor, bangle, MISSILERANGE, 0); /* killough 8/2/98 */ + for (i=0; i<3; i++) + { // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_sposattack); + int angle = bangle + ((t - P_Random(pr_sposattack))<<20); + int damage = ((P_Random(pr_sposattack)%5)+1)*3; + P_LineAttack(actor, angle, MISSILERANGE, slope, damage); + } +} + +void A_CPosAttack(mobj_t *actor) +{ + int angle, bangle, damage, slope, t; + + if (!actor->target) + return; + S_StartSound(actor, sfx_shotgn); + A_FaceTarget(actor); + bangle = actor->angle; + slope = P_AimLineAttack(actor, bangle, MISSILERANGE, 0); /* killough 8/2/98 */ + + // killough 5/5/98: remove dependence on order of evaluation: + t = P_Random(pr_cposattack); + angle = bangle + ((t - P_Random(pr_cposattack))<<20); + damage = ((P_Random(pr_cposattack)%5)+1)*3; + P_LineAttack(actor, angle, MISSILERANGE, slope, damage); +} + +void A_CPosRefire(mobj_t *actor) +{ + // keep firing unless target got out of sight + A_FaceTarget(actor); + + /* killough 12/98: Stop firing if a friend has gotten in the way */ + if (P_HitFriend(actor)) + goto stop; + + /* killough 11/98: prevent refiring on friends continuously */ + if (P_Random(pr_cposrefire) < 40) { + if (actor->target && actor->flags & actor->target->flags & MF_FRIEND) + goto stop; + else + return; + } + + if (!actor->target || actor->target->health <= 0 + || !P_CheckSight(actor, actor->target)) +stop: P_SetMobjState(actor, actor->info->seestate); +} + +void A_SpidRefire(mobj_t* actor) +{ + // keep firing unless target got out of sight + A_FaceTarget(actor); + + /* killough 12/98: Stop firing if a friend has gotten in the way */ + if (P_HitFriend(actor)) + goto stop; + + if (P_Random(pr_spidrefire) < 10) + return; + + // killough 11/98: prevent refiring on friends continuously + if (!actor->target || actor->target->health <= 0 + || actor->flags & actor->target->flags & MF_FRIEND + || !P_CheckSight(actor, actor->target)) + stop: P_SetMobjState(actor, actor->info->seestate); +} + +void A_BspiAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + P_SpawnMissile(actor, actor->target, MT_ARACHPLAZ); // launch a missile +} + +// +// A_TroopAttack +// + +void A_TroopAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + if (P_CheckMeleeRange(actor)) + { + int damage; + S_StartSound(actor, sfx_claw); + damage = (P_Random(pr_troopattack)%8+1)*3; + P_DamageMobj(actor->target, actor, actor, damage); + return; + } + P_SpawnMissile(actor, actor->target, MT_TROOPSHOT); // launch a missile +} + +void A_SargAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + if (P_CheckMeleeRange(actor)) + { + int damage = ((P_Random(pr_sargattack)%10)+1)*4; + P_DamageMobj(actor->target, actor, actor, damage); + } +} + +void A_HeadAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget (actor); + if (P_CheckMeleeRange(actor)) + { + int damage = (P_Random(pr_headattack)%6+1)*10; + P_DamageMobj(actor->target, actor, actor, damage); + return; + } + P_SpawnMissile(actor, actor->target, MT_HEADSHOT); // launch a missile +} + +void A_CyberAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + P_SpawnMissile(actor, actor->target, MT_ROCKET); +} + +void A_BruisAttack(mobj_t *actor) +{ + if (!actor->target) + return; + if (P_CheckMeleeRange(actor)) + { + int damage; + S_StartSound(actor, sfx_claw); + damage = (P_Random(pr_bruisattack)%8+1)*10; + P_DamageMobj(actor->target, actor, actor, damage); + return; + } + P_SpawnMissile(actor, actor->target, MT_BRUISERSHOT); // launch a missile +} + +// +// A_SkelMissile +// + +void A_SkelMissile(mobj_t *actor) +{ + mobj_t *mo; + + if (!actor->target) + return; + + A_FaceTarget (actor); + actor->z += 16*FRACUNIT; // so missile spawns higher + mo = P_SpawnMissile (actor, actor->target, MT_TRACER); + actor->z -= 16*FRACUNIT; // back to normal + + mo->x += mo->momx; + mo->y += mo->momy; + P_SetTarget(&mo->tracer, actor->target); +} + +int TRACEANGLE = 0xc000000; + +void A_Tracer(mobj_t *actor) +{ + angle_t exact; + fixed_t dist; + fixed_t slope; + mobj_t *dest; + mobj_t *th; + + /* killough 1/18/98: this is why some missiles do not have smoke + * and some do. Also, internal demos start at random gametics, thus + * the bug in which revenants cause internal demos to go out of sync. + * + * killough 3/6/98: fix revenant internal demo bug by subtracting + * levelstarttic from gametic. + * + * killough 9/29/98: use new "basetic" so that demos stay in sync + * during pauses and menu activations, while retaining old demo sync. + * + * leveltime would have been better to use to start with in Doom, but + * since old demos were recorded using gametic, we must stick with it, + * and improvise around it (using leveltime causes desync across levels). + */ + + if ((gametic-basetic) & 3) + return; + + // spawn a puff of smoke behind the rocket + P_SpawnPuff(actor->x, actor->y, actor->z); + + th = P_SpawnMobj (actor->x-actor->momx, + actor->y-actor->momy, + actor->z, MT_SMOKE); + + th->momz = FRACUNIT; + th->tics -= P_Random(pr_tracer) & 3; + if (th->tics < 1) + th->tics = 1; + + // adjust direction + dest = actor->tracer; + + if (!dest || dest->health <= 0) + return; + + // change angle + exact = R_PointToAngle2(actor->x, actor->y, dest->x, dest->y); + + if (exact != actor->angle) { + if (exact - actor->angle > 0x80000000) + { + actor->angle -= TRACEANGLE; + if (exact - actor->angle < 0x80000000) + actor->angle = exact; + } + else + { + actor->angle += TRACEANGLE; + if (exact - actor->angle > 0x80000000) + actor->angle = exact; + } + } + + exact = actor->angle>>ANGLETOFINESHIFT; + actor->momx = FixedMul(actor->info->speed, finecosine[exact]); + actor->momy = FixedMul(actor->info->speed, finesine[exact]); + + // change slope + dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y); + + dist = dist / actor->info->speed; + + if (dist < 1) + dist = 1; + + slope = (dest->z+40*FRACUNIT - actor->z) / dist; + + if (slope < actor->momz) + actor->momz -= FRACUNIT/8; + else + actor->momz += FRACUNIT/8; +} + +void A_SkelWhoosh(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + S_StartSound(actor,sfx_skeswg); +} + +void A_SkelFist(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + if (P_CheckMeleeRange(actor)) + { + int damage = ((P_Random(pr_skelfist)%10)+1)*6; + S_StartSound(actor, sfx_skepch); + P_DamageMobj(actor->target, actor, actor, damage); + } +} + +// +// PIT_VileCheck +// Detect a corpse that could be raised. +// + +mobj_t* corpsehit; +mobj_t* vileobj; +fixed_t viletryx; +fixed_t viletryy; + +static boolean PIT_VileCheck(mobj_t *thing) +{ + int maxdist; + boolean check; + + if (!(thing->flags & MF_CORPSE) ) + return true; // not a monster + + if (thing->tics != -1) + return true; // not lying still yet + + if (thing->info->raisestate == S_NULL) + return true; // monster doesn't have a raise state + + maxdist = thing->info->radius + mobjinfo[MT_VILE].radius; + + if (D_abs(thing->x-viletryx) > maxdist || D_abs(thing->y-viletryy) > maxdist) + return true; // not actually touching + +// Check to see if the radius and height are zero. If they are // phares +// then this is a crushed monster that has been turned into a // | +// gib. One of the options may be to ignore this guy. // V + +// Option 1: the original, buggy method, -> ghost (compatibility) +// Option 2: ressurect the monster, but not as a ghost +// Option 3: ignore the gib + +// if (Option3) // ^ +// if ((thing->height == 0) && (thing->radius == 0)) // | +// return true; // phares + + corpsehit = thing; + corpsehit->momx = corpsehit->momy = 0; + if (comp[comp_vile]) // phares + { // | + corpsehit->height <<= 2; // V + check = P_CheckPosition(corpsehit,corpsehit->x,corpsehit->y); + corpsehit->height >>= 2; + } + else + { + int height,radius; + + height = corpsehit->height; // save temporarily + radius = corpsehit->radius; // save temporarily + corpsehit->height = corpsehit->info->height; + corpsehit->radius = corpsehit->info->radius; + corpsehit->flags |= MF_SOLID; + check = P_CheckPosition(corpsehit,corpsehit->x,corpsehit->y); + corpsehit->height = height; // restore + corpsehit->radius = radius; // restore // ^ + corpsehit->flags &= ~MF_SOLID; + } // | + // phares + if (!check) + return true; // doesn't fit here + return false; // got one, so stop checking +} + +// +// A_VileChase +// Check for ressurecting a body +// + +void A_VileChase(mobj_t* actor) +{ + int xl, xh; + int yl, yh; + int bx, by; + + if (actor->movedir != DI_NODIR) + { + // check for corpses to raise + viletryx = + actor->x + actor->info->speed*xspeed[actor->movedir]; + viletryy = + actor->y + actor->info->speed*yspeed[actor->movedir]; + + xl = (viletryx - bmaporgx - MAXRADIUS*2)>>MAPBLOCKSHIFT; + xh = (viletryx - bmaporgx + MAXRADIUS*2)>>MAPBLOCKSHIFT; + yl = (viletryy - bmaporgy - MAXRADIUS*2)>>MAPBLOCKSHIFT; + yh = (viletryy - bmaporgy + MAXRADIUS*2)>>MAPBLOCKSHIFT; + + vileobj = actor; + for (bx=xl ; bx<=xh ; bx++) + { + for (by=yl ; by<=yh ; by++) + { + // Call PIT_VileCheck to check + // whether object is a corpse + // that canbe raised. + if (!P_BlockThingsIterator(bx,by,PIT_VileCheck)) + { + mobjinfo_t *info; + + // got one! + mobj_t* temp = actor->target; + actor->target = corpsehit; + A_FaceTarget(actor); + actor->target = temp; + + P_SetMobjState(actor, S_VILE_HEAL1); + S_StartSound(corpsehit, sfx_slop); + info = corpsehit->info; + + P_SetMobjState(corpsehit,info->raisestate); + + if (comp[comp_vile]) // phares + corpsehit->height <<= 2; // | + else // V + { + corpsehit->height = info->height; // fix Ghost bug + corpsehit->radius = info->radius; // fix Ghost bug + } // phares + + /* killough 7/18/98: + * friendliness is transferred from AV to raised corpse + */ + corpsehit->flags = + (info->flags & ~MF_FRIEND) | (actor->flags & MF_FRIEND); + + if (!((corpsehit->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL))) + totallive++; + + corpsehit->health = info->spawnhealth; + P_SetTarget(&corpsehit->target, NULL); // killough 11/98 + + if (mbf_features) + { /* kilough 9/9/98 */ + P_SetTarget(&corpsehit->lastenemy, NULL); + corpsehit->flags &= ~MF_JUSTHIT; + } + + /* killough 8/29/98: add to appropriate thread */ + P_UpdateThinker(&corpsehit->thinker); + + return; + } + } + } + } + A_Chase(actor); // Return to normal attack. +} + +// +// A_VileStart +// + +void A_VileStart(mobj_t *actor) +{ + S_StartSound(actor, sfx_vilatk); +} + +// +// A_Fire +// Keep fire in front of player unless out of sight +// + +void A_StartFire(mobj_t *actor) +{ + S_StartSound(actor,sfx_flamst); + A_Fire(actor); +} + +void A_FireCrackle(mobj_t* actor) +{ + S_StartSound(actor,sfx_flame); + A_Fire(actor); +} + +void A_Fire(mobj_t *actor) +{ + unsigned an; + mobj_t *dest = actor->tracer; + + if (!dest) + return; + + // don't move it if the vile lost sight + if (!P_CheckSight(actor->target, dest) ) + return; + + an = dest->angle >> ANGLETOFINESHIFT; + + P_UnsetThingPosition(actor); + actor->x = dest->x + FixedMul(24*FRACUNIT, finecosine[an]); + actor->y = dest->y + FixedMul(24*FRACUNIT, finesine[an]); + actor->z = dest->z; + P_SetThingPosition(actor); +} + +// +// A_VileTarget +// Spawn the hellfire +// + +void A_VileTarget(mobj_t *actor) +{ + mobj_t *fog; + + if (!actor->target) + return; + + A_FaceTarget(actor); + + // killough 12/98: fix Vile fog coordinates // CPhipps - compatibility optioned + fog = P_SpawnMobj(actor->target->x, + (compatibility_level < lxdoom_1_compatibility) ? actor->target->x : actor->target->y, + actor->target->z,MT_FIRE); + + P_SetTarget(&actor->tracer, fog); + P_SetTarget(&fog->target, actor); + P_SetTarget(&fog->tracer, actor->target); + A_Fire(fog); +} + +// +// A_VileAttack +// + +void A_VileAttack(mobj_t *actor) +{ + mobj_t *fire; + int an; + + if (!actor->target) + return; + + A_FaceTarget(actor); + + if (!P_CheckSight(actor, actor->target)) + return; + + S_StartSound(actor, sfx_barexp); + P_DamageMobj(actor->target, actor, actor, 20); + actor->target->momz = 1000*FRACUNIT/actor->target->info->mass; + + an = actor->angle >> ANGLETOFINESHIFT; + + fire = actor->tracer; + + if (!fire) + return; + + // move the fire between the vile and the player + fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]); + fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]); + P_RadiusAttack(fire, actor, 70); +} + +// +// Mancubus attack, +// firing three missiles (bruisers) +// in three different directions? +// Doesn't look like it. +// + +#define FATSPREAD (ANG90/8) + +void A_FatRaise(mobj_t *actor) +{ + A_FaceTarget(actor); + S_StartSound(actor, sfx_manatk); +} + +void A_FatAttack1(mobj_t *actor) +{ + mobj_t *mo; + int an; + + if (!actor->target) + return; + + A_FaceTarget(actor); + + // Change direction to ... + actor->angle += FATSPREAD; + + P_SpawnMissile(actor, actor->target, MT_FATSHOT); + + mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT); + mo->angle += FATSPREAD; + an = mo->angle >> ANGLETOFINESHIFT; + mo->momx = FixedMul(mo->info->speed, finecosine[an]); + mo->momy = FixedMul(mo->info->speed, finesine[an]); +} + +void A_FatAttack2(mobj_t *actor) +{ + mobj_t *mo; + int an; + + if (!actor->target) + return; + + A_FaceTarget(actor); + // Now here choose opposite deviation. + actor->angle -= FATSPREAD; + P_SpawnMissile(actor, actor->target, MT_FATSHOT); + + mo = P_SpawnMissile(actor, 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]); +} + +void A_FatAttack3(mobj_t *actor) +{ + mobj_t *mo; + int an; + + if (!actor->target) + return; + + A_FaceTarget(actor); + + mo = P_SpawnMissile(actor, 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->angle += FATSPREAD/2; + an = mo->angle >> ANGLETOFINESHIFT; + mo->momx = FixedMul(mo->info->speed, finecosine[an]); + mo->momy = FixedMul(mo->info->speed, finesine[an]); +} + + +// +// SkullAttack +// Fly at the player like a missile. +// +#define SKULLSPEED (20*FRACUNIT) + +void A_SkullAttack(mobj_t *actor) +{ + mobj_t *dest; + angle_t an; + int dist; + + if (!actor->target) + return; + + dest = actor->target; + actor->flags |= MF_SKULLFLY; + + S_StartSound(actor, actor->info->attacksound); + A_FaceTarget(actor); + an = actor->angle >> ANGLETOFINESHIFT; + actor->momx = FixedMul(SKULLSPEED, finecosine[an]); + actor->momy = FixedMul(SKULLSPEED, finesine[an]); + dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y); + dist = dist / SKULLSPEED; + + if (dist < 1) + dist = 1; + actor->momz = (dest->z+(dest->height>>1) - actor->z) / dist; +} + +// +// A_PainShootSkull +// Spawn a lost soul and launch it at the target +// + +static void A_PainShootSkull(mobj_t *actor, angle_t angle) +{ + fixed_t x,y,z; + mobj_t *newmobj; + angle_t an; + int prestep; + +// The original code checked for 20 skulls on the level, // phares +// and wouldn't spit another one if there were. If not in // phares +// compatibility mode, we remove the limit. // phares + // phares + if (comp[comp_pain]) /* killough 10/98: compatibility-optioned */ + { + // count total number of skulls currently on the level + int count = 0; + thinker_t *currentthinker = NULL; + while ((currentthinker = P_NextThinker(currentthinker,th_all)) != NULL) + if ((currentthinker->function == P_MobjThinker) + && ((mobj_t *)currentthinker)->type == MT_SKULL) + count++; + if (count > 20) // phares + return; // phares + } + + // okay, there's room for another one + + an = angle >> ANGLETOFINESHIFT; + + prestep = 4*FRACUNIT + 3*(actor->info->radius + mobjinfo[MT_SKULL].radius)/2; + + x = actor->x + FixedMul(prestep, finecosine[an]); + y = actor->y + FixedMul(prestep, finesine[an]); + z = actor->z + 8*FRACUNIT; + + if (comp[comp_skull]) /* killough 10/98: compatibility-optioned */ + newmobj = P_SpawnMobj(x, y, z, MT_SKULL); // phares + else // V + { + // Check whether the Lost Soul is being fired through a 1-sided + // wall or an impassible line, or a "monsters can't cross" line. + // If it is, then we don't allow the spawn. This is a bug fix, but + // it should be considered an enhancement, since it may disturb + // existing demos, so don't do it in compatibility mode. + + if (Check_Sides(actor,x,y)) + return; + + newmobj = P_SpawnMobj(x, y, z, MT_SKULL); + + // Check to see if the new Lost Soul's z value is above the + // ceiling of its new sector, or below the floor. If so, kill it. + + if ((newmobj->z > + (newmobj->subsector->sector->ceilingheight - newmobj->height)) || + (newmobj->z < newmobj->subsector->sector->floorheight)) + { + // kill it immediately + P_DamageMobj(newmobj,actor,actor,10000); + return; // ^ + } // | + } // phares + + /* killough 7/20/98: PEs shoot lost souls with the same friendliness */ + newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (actor->flags & MF_FRIEND); + + /* killough 8/29/98: add to appropriate thread */ + P_UpdateThinker(&newmobj->thinker); + + // Check for movements. + // killough 3/15/98: don't jump over dropoffs: + + if (!P_TryMove(newmobj, newmobj->x, newmobj->y, false)) + { + // kill it immediately + P_DamageMobj(newmobj, actor, actor, 10000); + return; + } + + P_SetTarget(&newmobj->target, actor->target); + A_SkullAttack(newmobj); +} + +// +// A_PainAttack +// Spawn a lost soul and launch it at the target +// + +void A_PainAttack(mobj_t *actor) +{ + if (!actor->target) + return; + A_FaceTarget(actor); + A_PainShootSkull(actor, actor->angle); +} + +void A_PainDie(mobj_t *actor) +{ + A_Fall(actor); + A_PainShootSkull(actor, actor->angle+ANG90); + A_PainShootSkull(actor, actor->angle+ANG180); + A_PainShootSkull(actor, actor->angle+ANG270); +} + +void A_Scream(mobj_t *actor) +{ + int sound; + + switch (actor->info->deathsound) + { + case 0: + return; + + case sfx_podth1: + case sfx_podth2: + case sfx_podth3: + sound = sfx_podth1 + P_Random(pr_scream)%3; + break; + + case sfx_bgdth1: + case sfx_bgdth2: + sound = sfx_bgdth1 + P_Random(pr_scream)%2; + break; + + default: + sound = actor->info->deathsound; + break; + } + + // Check for bosses. + if (actor->type==MT_SPIDER || actor->type == MT_CYBORG) + S_StartSound(NULL, sound); // full volume + else + S_StartSound(actor, sound); +} + +void A_XScream(mobj_t *actor) +{ + S_StartSound(actor, sfx_slop); +} + +void A_Pain(mobj_t *actor) +{ + if (actor->info->painsound) + S_StartSound(actor, actor->info->painsound); +} + +void A_Fall(mobj_t *actor) +{ + // actor is on ground, it can be walked over + actor->flags &= ~MF_SOLID; +} + +// +// A_Explode +// +void A_Explode(mobj_t *thingy) +{ + P_RadiusAttack( thingy, thingy->target, 128 ); +} + +// +// A_BossDeath +// Possibly trigger special effects +// if on first boss level +// + +void A_BossDeath(mobj_t *mo) +{ + thinker_t *th; + line_t junk; + int i; + + if (gamemode == commercial) + { + if (gamemap != 7) + return; + + if ((mo->type != MT_FATSO) + && (mo->type != MT_BABY)) + return; + } + else + { + // e6y + // Additional check of gameepisode is necessary, because + // there is no right or wrong solution for E4M6 in original EXEs, + // there's nothing to emulate. + if (comp[comp_666] && gameepisode < 4) + { + // e6y + // Only following checks are present in doom2.exe ver. 1.666 and 1.9 + // instead of separate checks for each episode in doomult.exe, plutonia.exe and tnt.exe + // There is no more desync on doom.wad\episode3.lmp + // http://www.doomworld.com/idgames/index.php?id=6909 + if (gamemap != 8) + return; + if (mo->type == MT_BRUISER && gameepisode != 1) + return; + } + 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; + } + } + + } + + // make sure there is a player alive for victory + for (i=0; i 0) + break; + + if (i==MAXPLAYERS) + return; // no one left alive, so do not end game + + // scan the remaining thinkers to see + // if all bosses are dead + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + if (th->function == P_MobjThinker) + { + mobj_t *mo2 = (mobj_t *) th; + if (mo2 != mo && mo2->type == mo->type && mo2->health > 0) + return; // other boss not dead + } + + // victory! + if ( gamemode == commercial) + { + if (gamemap == 7) + { + if (mo->type == MT_FATSO) + { + junk.tag = 666; + EV_DoFloor(&junk,lowerFloorToLowest); + return; + } + + if (mo->type == MT_BABY) + { + junk.tag = 667; + EV_DoFloor(&junk,raiseToTexture); + return; + } + } + } + else + { + switch(gameepisode) + { + case 1: + junk.tag = 666; + EV_DoFloor(&junk, lowerFloorToLowest); + return; + break; + + case 4: + switch(gamemap) + { + case 6: + junk.tag = 666; + EV_DoDoor(&junk, blazeOpen); + return; + break; + + case 8: + junk.tag = 666; + EV_DoFloor(&junk, lowerFloorToLowest); + return; + break; + } + } + } + G_ExitLevel(); +} + + +void A_Hoof (mobj_t* mo) +{ + S_StartSound(mo, sfx_hoof); + A_Chase(mo); +} + +void A_Metal(mobj_t *mo) +{ + S_StartSound(mo, sfx_metal); + A_Chase(mo); +} + +void A_BabyMetal(mobj_t *mo) +{ + S_StartSound(mo, sfx_bspwlk); + A_Chase(mo); +} + +void A_OpenShotgun2(player_t *player, pspdef_t *psp) +{ + S_StartSound(player->mo, sfx_dbopn); +} + +void A_LoadShotgun2(player_t *player, pspdef_t *psp) +{ + S_StartSound(player->mo, sfx_dbload); +} + +void A_CloseShotgun2(player_t *player, pspdef_t *psp) +{ + S_StartSound(player->mo, sfx_dbcls); + A_ReFire(player,psp); +} + +// killough 2/7/98: Remove limit on icon landings: +mobj_t **braintargets; +int numbraintargets_alloc; +int numbraintargets; + +struct brain_s brain; // killough 3/26/98: global state of boss brain + +// killough 3/26/98: initialize icon landings at level startup, +// rather than at boss wakeup, to prevent savegame-related crashes + +void P_SpawnBrainTargets(void) // killough 3/26/98: renamed old function +{ + thinker_t *thinker; + + // find all the target spots + numbraintargets = 0; + brain.targeton = 0; + brain.easy = 0; // killough 3/26/98: always init easy to 0 + + for (thinker = thinkercap.next ; + thinker != &thinkercap ; + thinker = thinker->next) + if (thinker->function == P_MobjThinker) + { + mobj_t *m = (mobj_t *) thinker; + + if (m->type == MT_BOSSTARGET ) + { // killough 2/7/98: remove limit on icon landings: + if (numbraintargets >= numbraintargets_alloc) + braintargets = realloc(braintargets, + (numbraintargets_alloc = numbraintargets_alloc ? + numbraintargets_alloc*2 : 32) *sizeof *braintargets); + braintargets[numbraintargets++] = m; + } + } +} + +void A_BrainAwake(mobj_t *mo) +{ + S_StartSound(NULL,sfx_bossit); // killough 3/26/98: only generates sound now +} + +void A_BrainPain(mobj_t *mo) +{ + S_StartSound(NULL,sfx_bospn); +} + +void A_BrainScream(mobj_t *mo) +{ + int x; + for (x=mo->x - 196*FRACUNIT ; x< mo->x + 320*FRACUNIT ; x+= FRACUNIT*8) + { + int y = mo->y - 320*FRACUNIT; + int z = 128 + P_Random(pr_brainscream)*2*FRACUNIT; + mobj_t *th = P_SpawnMobj (x,y,z, MT_ROCKET); + th->momz = P_Random(pr_brainscream)*512; + P_SetMobjState(th, S_BRAINEXPLODE1); + th->tics -= P_Random(pr_brainscream)&7; + if (th->tics < 1) + th->tics = 1; + } + S_StartSound(NULL,sfx_bosdth); +} + +void A_BrainExplode(mobj_t *mo) +{ // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_brainexp); + int x = mo->x + (t - P_Random(pr_brainexp))*2048; + int y = mo->y; + int z = 128 + P_Random(pr_brainexp)*2*FRACUNIT; + mobj_t *th = P_SpawnMobj(x,y,z, MT_ROCKET); + th->momz = P_Random(pr_brainexp)*512; + P_SetMobjState(th, S_BRAINEXPLODE1); + th->tics -= P_Random(pr_brainexp)&7; + if (th->tics < 1) + th->tics = 1; +} + +void A_BrainDie(mobj_t *mo) +{ + G_ExitLevel(); +} + +void A_BrainSpit(mobj_t *mo) +{ + mobj_t *targ, *newmobj; + + if (!numbraintargets) // killough 4/1/98: ignore if no targets + return; + + brain.easy ^= 1; // killough 3/26/98: use brain struct + if (gameskill <= sk_easy && !brain.easy) + return; + + // shoot a cube at current target + targ = braintargets[brain.targeton++]; // killough 3/26/98: + brain.targeton %= numbraintargets; // Use brain struct for targets + + // spawn brain missile + newmobj = P_SpawnMissile(mo, targ, MT_SPAWNSHOT); + P_SetTarget(&newmobj->target, targ); + newmobj->reactiontime = (short)(((targ->y-mo->y)/newmobj->momy)/newmobj->state->tics); + + // killough 7/18/98: brain friendliness is transferred + newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND); + + // killough 8/29/98: add to appropriate thread + P_UpdateThinker(&newmobj->thinker); + + S_StartSound(NULL, sfx_bospit); +} + +// travelling cube sound +void A_SpawnSound(mobj_t *mo) +{ + S_StartSound(mo,sfx_boscub); + A_SpawnFly(mo); +} + +void A_SpawnFly(mobj_t *mo) +{ + mobj_t *newmobj; + mobj_t *fog; + mobj_t *targ; + int r; + mobjtype_t type; + + if (--mo->reactiontime) + return; // still flying + + targ = mo->target; + + // First spawn teleport fog. + fog = P_SpawnMobj(targ->x, targ->y, targ->z, MT_SPAWNFIRE); + S_StartSound(fog, sfx_telept); + + // Randomly select monster to spawn. + r = P_Random(pr_spawnfly); + + // Probability distribution (kind of :), decreasing likelihood. + if ( r<50 ) + type = MT_TROOP; + else if (r<90) + type = MT_SERGEANT; + else if (r<120) + type = MT_SHADOWS; + else if (r<130) + type = MT_PAIN; + else if (r<160) + type = MT_HEAD; + else if (r<162) + type = MT_VILE; + else if (r<172) + type = MT_UNDEAD; + else if (r<192) + type = MT_BABY; + else if (r<222) + type = MT_FATSO; + else if (r<246) + type = MT_KNIGHT; + else + type = MT_BRUISER; + + newmobj = P_SpawnMobj(targ->x, targ->y, targ->z, type); + + /* killough 7/18/98: brain friendliness is transferred */ + newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND); + + /* killough 8/29/98: add to appropriate thread */ + P_UpdateThinker(&newmobj->thinker); + + if (P_LookForTargets(newmobj,true)) /* killough 9/4/98 */ + P_SetMobjState(newmobj, newmobj->info->seestate); + + // telefrag anything in this spot + P_TeleportMove(newmobj, newmobj->x, newmobj->y, true); /* killough 8/9/98 */ + + // remove self (i.e., cube). + P_RemoveMobj(mo); +} + +void A_PlayerScream(mobj_t *mo) +{ + int sound = sfx_pldeth; // Default death sound. + if (gamemode != shareware && mo->health < -50) + sound = sfx_pdiehi; // IF THE PLAYER DIES LESS THAN -50% WITHOUT GIBBING + S_StartSound(mo, sound); +} + +/* cph - MBF-added codepointer functions */ + +// killough 11/98: kill an object +void A_Die(mobj_t *actor) +{ + P_DamageMobj(actor, NULL, NULL, actor->health); +} + +// +// A_Detonate +// killough 8/9/98: same as A_Explode, except that the damage is variable +// + +void A_Detonate(mobj_t *mo) +{ + P_RadiusAttack(mo, mo->target, mo->info->damage); +} + +// +// killough 9/98: a mushroom explosion effect, sorta :) +// Original idea: Linguica +// + +void A_Mushroom(mobj_t *actor) +{ + int i, j, n = actor->info->damage; + + A_Explode(actor); // First make normal explosion + + // Now launch mushroom cloud + for (i = -n; i <= n; i += 8) + for (j = -n; j <= n; j += 8) + { + mobj_t target = *actor, *mo; + target.x += i << FRACBITS; // Aim in many directions from source + target.y += j << FRACBITS; + target.z += P_AproxDistance(i,j) << (FRACBITS+2); // Aim up fairly high + mo = P_SpawnMissile(actor, &target, MT_FATSHOT); // Launch fireball + mo->momx >>= 1; + mo->momy >>= 1; // Slow it down a bit + mo->momz >>= 1; + mo->flags &= ~MF_NOGRAVITY; // Make debris fall under gravity + } +} + +// +// killough 11/98 +// +// The following were inspired by Len Pitre +// +// A small set of highly-sought-after code pointers +// + +void A_Spawn(mobj_t *mo) +{ + if (mo->state->misc1) + { + /* mobj_t *newmobj = */ + P_SpawnMobj(mo->x, mo->y, (mo->state->misc2 << FRACBITS) + mo->z, + mo->state->misc1 - 1); + /* CPhipps - no friendlyness (yet) + newmobj->flags = (newmobj->flags & ~MF_FRIEND) | (mo->flags & MF_FRIEND); + */ + } +} + +void A_Turn(mobj_t *mo) +{ + mo->angle += (unsigned int)(((uint_64_t) mo->state->misc1 << 32) / 360); +} + +void A_Face(mobj_t *mo) +{ + mo->angle = (unsigned int)(((uint_64_t) mo->state->misc1 << 32) / 360); +} + +void A_Scratch(mobj_t *mo) +{ + mo->target && (A_FaceTarget(mo), P_CheckMeleeRange(mo)) ? + mo->state->misc2 ? S_StartSound(mo, mo->state->misc2) : (void) 0, + P_DamageMobj(mo->target, mo, mo, mo->state->misc1) : (void) 0; +} + +void A_PlaySound(mobj_t *mo) +{ + S_StartSound(mo->state->misc2 ? NULL : mo, mo->state->misc1); +} + +void A_RandomJump(mobj_t *mo) +{ + if (P_Random(pr_randomjump) < mo->state->misc2) + P_SetMobjState(mo, mo->state->misc1); +} + +// +// This allows linedef effects to be activated inside deh frames. +// + +void A_LineEffect(mobj_t *mo) +{ + static line_t junk; + player_t player; + player_t *oldplayer; + junk = *lines; + oldplayer = mo->player; + mo->player = &player; + player.health = 100; + junk.special = (short)mo->state->misc1; + if (!junk.special) + return; + junk.tag = (short)mo->state->misc2; + if (!P_UseSpecialLine(mo, &junk, 0)) + P_CrossSpecialLine(&junk, 0, mo); + mo->state->misc1 = junk.special; + mo->player = oldplayer; +} diff --git a/src/p_enemy.h b/src/p_enemy.h new file mode 100644 index 0000000..3c85861 --- /dev/null +++ b/src/p_enemy.h @@ -0,0 +1,118 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Enemy thinking, AI. + * Action Pointer Functions + * that are associated with states/frames. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_ENEMY__ +#define __P_ENEMY__ + +#include "p_mobj.h" + +void P_NoiseAlert (mobj_t *target, mobj_t *emmiter); +void P_SpawnBrainTargets(void); /* killough 3/26/98: spawn icon landings */ + +extern struct brain_s { /* killough 3/26/98: global state of boss brain */ + int easy, targeton; +} brain; + +// ******************************************************************** +// Function addresses or Code Pointers +// ******************************************************************** +// These function addresses are the Code Pointers that have been +// modified for years by Dehacked enthusiasts. The new BEX format +// allows more extensive changes (see d_deh.c) + +// Doesn't work with g++, needs actionf_p1 +void A_Explode(); +void A_Pain(); +void A_PlayerScream(); +void A_Fall(); +void A_XScream(); +void A_Look(); +void A_Chase(); +void A_FaceTarget(); +void A_PosAttack(); +void A_Scream(); +void A_SPosAttack(); +void A_VileChase(); +void A_VileStart(); +void A_VileTarget(); +void A_VileAttack(); +void A_StartFire(); +void A_Fire(); +void A_FireCrackle(); +void A_Tracer(); +void A_SkelWhoosh(); +void A_SkelFist(); +void A_SkelMissile(); +void A_FatRaise(); +void A_FatAttack1(); +void A_FatAttack2(); +void A_FatAttack3(); +void A_BossDeath(); +void A_CPosAttack(); +void A_CPosRefire(); +void A_TroopAttack(); +void A_SargAttack(); +void A_HeadAttack(); +void A_BruisAttack(); +void A_SkullAttack(); +void A_Metal(); +void A_SpidRefire(); +void A_BabyMetal(); +void A_BspiAttack(); +void A_Hoof(); +void A_CyberAttack(); +void A_PainAttack(); +void A_PainDie(); +void A_KeenDie(); +void A_BrainPain(); +void A_BrainScream(); +void A_BrainDie(); +void A_BrainAwake(); +void A_BrainSpit(); +void A_SpawnSound(); +void A_SpawnFly(); +void A_BrainExplode(); +void A_Die(); +void A_Detonate(); /* killough 8/9/98: detonate a bomb or other device */ +void A_Mushroom(); /* killough 10/98: mushroom effect */ +void A_Spawn(); // killough 11/98 +void A_Turn(); // killough 11/98 +void A_Face(); // killough 11/98 +void A_Scratch(); // killough 11/98 +void A_PlaySound(); // killough 11/98 +void A_RandomJump(); // killough 11/98 +void A_LineEffect(); // killough 11/98 + +#endif // __P_ENEMY__ diff --git a/src/p_floor.c b/src/p_floor.c new file mode 100644 index 0000000..ba55fdf --- /dev/null +++ b/src/p_floor.c @@ -0,0 +1,1042 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * General plane mover and floor mover action routines + * Floor motion, pure changer types, raising stairs. donuts, elevators + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "r_main.h" +#include "p_map.h" +#include "p_spec.h" +#include "p_tick.h" +#include "s_sound.h" +#include "sounds.h" + +/////////////////////////////////////////////////////////////////////// +// +// Plane (floor or ceiling), Floor motion and Elevator action routines +// +/////////////////////////////////////////////////////////////////////// + +// +// T_MovePlane() +// +// Move a plane (floor or ceiling) and check for crushing. Called +// every tick by all actions that move floors or ceilings. +// +// Passed the sector to move a plane in, the speed to move it at, +// the dest height it is to achieve, whether it crushes obstacles, +// whether it moves a floor or ceiling, and the direction up or down +// to move. +// +// Returns a result_e: +// ok - plane moved normally, has not achieved destination yet +// pastdest - plane moved normally and is now at destination height +// crushed - plane encountered an obstacle, is holding until removed +// +result_e T_MovePlane +( sector_t* sector, + fixed_t speed, + fixed_t dest, + boolean crush, + int floorOrCeiling, + int direction ) +{ + boolean flag; + fixed_t lastpos; + fixed_t destheight; //jff 02/04/98 used to keep floors/ceilings + // from moving thru each other + + switch(floorOrCeiling) + { + case 0: + // Moving a floor + switch(direction) + { + case -1: + // Moving a floor down + if (sector->floorheight - speed < dest) + { + lastpos = sector->floorheight; + sector->floorheight = dest; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + if (flag == true) + { + sector->floorheight =lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + } + return pastdest; + } + else + { + lastpos = sector->floorheight; + sector->floorheight -= speed; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + /* cph - make more compatible with original Doom, by + * reintroducing this code. This means floors can't lower + * if objects are stuck in the ceiling */ + if ((flag == true) && comp[comp_floors]) { + sector->floorheight = lastpos; + P_ChangeSector(sector,crush); + return crushed; + } + } + break; + + case 1: + // Moving a floor up + // jff 02/04/98 keep floor from moving thru ceilings + // jff 2/22/98 weaken check to demo_compatibility + destheight = (comp[comp_floors] || destceilingheight)? + dest : sector->ceilingheight; + if (sector->floorheight + speed > destheight) + { + lastpos = sector->floorheight; + sector->floorheight = destheight; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + if (flag == true) + { + sector->floorheight = lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + } + return pastdest; + } + else + { + // crushing is possible + lastpos = sector->floorheight; + sector->floorheight += speed; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + if (flag == true) + { + /* jff 1/25/98 fix floor crusher */ + if (comp[comp_floors]) { + if (crush == true) + return crushed; + } + sector->floorheight = lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + return crushed; + } + } + break; + } + break; + + case 1: + // moving a ceiling + switch(direction) + { + case -1: + // moving a ceiling down + // jff 02/04/98 keep ceiling from moving thru floors + // jff 2/22/98 weaken check to demo_compatibility + destheight = (comp[comp_floors] || dest>sector->floorheight)? + dest : sector->floorheight; + if (sector->ceilingheight - speed < destheight) + { + lastpos = sector->ceilingheight; + sector->ceilingheight = destheight; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + + if (flag == true) + { + sector->ceilingheight = lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + } + return pastdest; + } + else + { + // crushing is possible + lastpos = sector->ceilingheight; + sector->ceilingheight -= speed; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + + if (flag == true) + { + if (crush == true) + return crushed; + sector->ceilingheight = lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + return crushed; + } + } + break; + + case 1: + // moving a ceiling up + if (sector->ceilingheight + speed > dest) + { + lastpos = sector->ceilingheight; + sector->ceilingheight = dest; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + if (flag == true) + { + sector->ceilingheight = lastpos; + P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + } + return pastdest; + } + else + { + lastpos = sector->ceilingheight; + sector->ceilingheight += speed; + flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk + } + break; + } + break; + } + return ok; +} + +// +// T_MoveFloor() +// +// Move a floor to it's destination (up or down). +// Called once per tick for each moving floor. +// +// Passed a floormove_t structure that contains all pertinent info about the +// move. See P_SPEC.H for fields. +// No return. +// +// jff 02/08/98 all cases with labels beginning with gen added to support +// generalized line type behaviors. + +void T_MoveFloor(floormove_t* floor) +{ + result_e res; + + res = T_MovePlane // move the floor + ( + floor->sector, + floor->speed, + floor->floordestheight, + floor->crush, + 0, + floor->direction + ); + + if (!(leveltime&7)) // make the floormove sound + S_StartSound((mobj_t *)&floor->sector->soundorg, sfx_stnmov); + + if (res == pastdest) // if destination height is reached + { + if (floor->direction == 1) // going up + { + switch(floor->type) // handle texture/type changes + { + case donutRaise: + floor->sector->special = floor->newspecial; + floor->sector->floorpic = floor->texture; + break; + case genFloorChgT: + case genFloorChg0: + floor->sector->special = floor->newspecial; + //jff add to fix bug in special transfers from changes + floor->sector->oldspecial = floor->oldspecial; + //fall thru + case genFloorChg: + floor->sector->floorpic = floor->texture; + break; + default: + break; + } + } + else if (floor->direction == -1) // going down + { + switch(floor->type) // handle texture/type changes + { + case lowerAndChange: + floor->sector->special = floor->newspecial; + //jff add to fix bug in special transfers from changes + floor->sector->oldspecial = floor->oldspecial; + floor->sector->floorpic = floor->texture; + break; + case genFloorChgT: + case genFloorChg0: + floor->sector->special = floor->newspecial; + //jff add to fix bug in special transfers from changes + floor->sector->oldspecial = floor->oldspecial; + //fall thru + case genFloorChg: + floor->sector->floorpic = floor->texture; + break; + default: + break; + } + } + + floor->sector->floordata = NULL; //jff 2/22/98 + P_RemoveThinker(&floor->thinker);//remove this floor from list of movers + + //jff 2/26/98 implement stair retrigger lockout while still building + // note this only applies to the retriggerable generalized stairs + + if (floor->sector->stairlock==-2) // if this sector is stairlocked + { + sector_t *sec = floor->sector; + sec->stairlock=-1; // thinker done, promote lock to -1 + + while (sec->prevsec!=-1 && sectors[sec->prevsec].stairlock!=-2) + sec = §ors[sec->prevsec]; // search for a non-done thinker + if (sec->prevsec==-1) // if all thinkers previous are done + { + sec = floor->sector; // search forward + while (sec->nextsec!=-1 && sectors[sec->nextsec].stairlock!=-2) + sec = §ors[sec->nextsec]; + if (sec->nextsec==-1) // if all thinkers ahead are done too + { + while (sec->prevsec!=-1) // clear all locks + { + sec->stairlock = 0; + sec = §ors[sec->prevsec]; + } + sec->stairlock = 0; + } + } + } + + // make floor stop sound + S_StartSound((mobj_t *)&floor->sector->soundorg, sfx_pstop); + } +} + +// +// T_MoveElevator() +// +// Move an elevator to it's destination (up or down) +// Called once per tick for each moving floor. +// +// Passed an elevator_t structure that contains all pertinent info about the +// move. See P_SPEC.H for fields. +// No return. +// +// jff 02/22/98 added to support parallel floor/ceiling motion +// +void T_MoveElevator(elevator_t* elevator) +{ + result_e res; + + if (elevator->direction<0) // moving down + { + res = T_MovePlane //jff 4/7/98 reverse order of ceiling/floor + ( + elevator->sector, + elevator->speed, + elevator->ceilingdestheight, + 0, + 1, // move floor + elevator->direction + ); + if (res==ok || res==pastdest) // jff 4/7/98 don't move ceil if blocked + T_MovePlane + ( + elevator->sector, + elevator->speed, + elevator->floordestheight, + 0, + 0, // move ceiling + elevator->direction + ); + } + else // up + { + res = T_MovePlane //jff 4/7/98 reverse order of ceiling/floor + ( + elevator->sector, + elevator->speed, + elevator->floordestheight, + 0, + 0, // move ceiling + elevator->direction + ); + if (res==ok || res==pastdest) // jff 4/7/98 don't move floor if blocked + T_MovePlane + ( + elevator->sector, + elevator->speed, + elevator->ceilingdestheight, + 0, + 1, // move floor + elevator->direction + ); + } + + // make floor move sound + if (!(leveltime&7)) + S_StartSound((mobj_t *)&elevator->sector->soundorg, sfx_stnmov); + + if (res == pastdest) // if destination height acheived + { + elevator->sector->floordata = NULL; //jff 2/22/98 + elevator->sector->ceilingdata = NULL; //jff 2/22/98 + P_RemoveThinker(&elevator->thinker); // remove elevator from actives + + // make floor stop sound + S_StartSound((mobj_t *)&elevator->sector->soundorg, sfx_pstop); + } +} + +/////////////////////////////////////////////////////////////////////// +// +// Floor motion linedef handlers +// +/////////////////////////////////////////////////////////////////////// + +// +// EV_DoFloor() +// +// Handle regular and extended floor types +// +// Passed the line that activated the floor and the type of floor motion +// Returns true if a thinker was created. +// +int EV_DoFloor +( line_t* line, + floor_e floortype ) +{ + int secnum; + int rtn; + int i; + sector_t* sec; + floormove_t* floor; + + secnum = -1; + rtn = 0; + // move all floors with the same tag as the linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + + // Don't start a second thinker on the same floor + if (P_SectorActive(floor_special,sec)) //jff 2/23/98 + continue; + + // new floor thinker + rtn = 1; + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + memset(floor, 0, sizeof(*floor)); + P_AddThinker (&floor->thinker); + sec->floordata = floor; //jff 2/22/98 + floor->thinker.function = T_MoveFloor; + floor->type = floortype; + floor->crush = false; + + // setup the thinker according to the linedef type + switch(floortype) + { + case lowerFloor: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = P_FindHighestFloorSurrounding(sec); + break; + + //jff 02/03/30 support lowering floor by 24 absolute + case lowerFloor24: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; + break; + + //jff 02/03/30 support lowering floor by 32 absolute (fast) + case lowerFloor32Turbo: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED*4; + floor->floordestheight = floor->sector->floorheight + 32 * FRACUNIT; + break; + + case lowerFloorToLowest: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = P_FindLowestFloorSurrounding(sec); + break; + + //jff 02/03/30 support lowering floor to next lowest floor + case lowerFloorToNearest: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = + P_FindNextLowestFloor(sec,floor->sector->floorheight); + break; + + case turboLower: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED * 4; + floor->floordestheight = P_FindHighestFloorSurrounding(sec); + if (floor->floordestheight != sec->floorheight) + floor->floordestheight += 8*FRACUNIT; + break; + + case raiseFloorCrush: + floor->crush = true; + case raiseFloor: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = P_FindLowestCeilingSurrounding(sec); + if (floor->floordestheight > sec->ceilingheight) + floor->floordestheight = sec->ceilingheight; + floor->floordestheight -= (8*FRACUNIT)*(floortype == raiseFloorCrush); + break; + + case raiseFloorTurbo: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED*4; + floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight); + break; + + case raiseFloorToNearest: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight); + break; + + case raiseFloor24: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; + break; + + // jff 2/03/30 support straight raise by 32 (fast) + case raiseFloor32Turbo: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED*4; + floor->floordestheight = floor->sector->floorheight + 32 * FRACUNIT; + break; + + case raiseFloor512: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = floor->sector->floorheight + 512 * FRACUNIT; + break; + + case raiseFloor24AndChange: + floor->direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT; + sec->floorpic = line->frontsector->floorpic; + sec->special = line->frontsector->special; + //jff 3/14/98 transfer both old and new special + sec->oldspecial = line->frontsector->oldspecial; + break; + + case raiseToTexture: + { + int minsize = INT_MAX; + side_t* side; + + /* jff 3/13/98 no ovf */ + if (!comp[comp_model]) minsize = 32000<direction = 1; + floor->sector = sec; + floor->speed = FLOORSPEED; + for (i = 0; i < sec->linecount; i++) + { + if (twoSided (secnum, i) ) + { + side = getSide(secnum,i,0); + // jff 8/14/98 don't scan texture 0, its not real + if (side->bottomtexture > 0 || + (comp[comp_model] && !side->bottomtexture)) + if (textureheight[side->bottomtexture] < minsize) + minsize = textureheight[side->bottomtexture]; + side = getSide(secnum,i,1); + // jff 8/14/98 don't scan texture 0, its not real + if (side->bottomtexture > 0 || + (comp[comp_model] && !side->bottomtexture)) + if (textureheight[side->bottomtexture] < minsize) + minsize = textureheight[side->bottomtexture]; + } + } + if (comp[comp_model]) + floor->floordestheight = floor->sector->floorheight + minsize; + else + { + floor->floordestheight = + (floor->sector->floorheight>>FRACBITS) + (minsize>>FRACBITS); + if (floor->floordestheight>32000) + floor->floordestheight = 32000; //jff 3/13/98 do not + floor->floordestheight<<=FRACBITS; // allow height overflow + } + } + break; + + case lowerAndChange: + floor->direction = -1; + floor->sector = sec; + floor->speed = FLOORSPEED; + floor->floordestheight = P_FindLowestFloorSurrounding(sec); + floor->texture = sec->floorpic; + + // jff 1/24/98 make sure floor->newspecial gets initialized + // in case no surrounding sector is at floordestheight + // --> should not affect compatibility <-- + floor->newspecial = sec->special; + //jff 3/14/98 transfer both old and new special + floor->oldspecial = sec->oldspecial; + + //jff 5/23/98 use model subroutine to unify fixes and handling + sec = P_FindModelFloorSector(floor->floordestheight,sec-sectors); + if (sec) + { + floor->texture = sec->floorpic; + floor->newspecial = sec->special; + //jff 3/14/98 transfer both old and new special + floor->oldspecial = sec->oldspecial; + } + break; + default: + break; + } + } + return rtn; +} + +// +// EV_DoChange() +// +// Handle pure change types. These change floor texture and sector type +// by trigger or numeric model without moving the floor. +// +// The linedef causing the change and the type of change is passed +// Returns true if any sector changes +// +// jff 3/15/98 added to better support generalized sector types +// +int EV_DoChange +( line_t* line, + change_e changetype ) +{ + int secnum; + int rtn; + sector_t* sec; + sector_t* secm; + + secnum = -1; + rtn = 0; + // change all sectors with the same tag as the linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + + rtn = 1; + + // handle trigger or numeric change type + switch(changetype) + { + case trigChangeOnly: + sec->floorpic = line->frontsector->floorpic; + sec->special = line->frontsector->special; + sec->oldspecial = line->frontsector->oldspecial; + break; + case numChangeOnly: + secm = P_FindModelFloorSector(sec->floorheight,secnum); + if (secm) // if no model, no change + { + sec->floorpic = secm->floorpic; + sec->special = secm->special; + sec->oldspecial = secm->oldspecial; + } + break; + default: + break; + } + } + return rtn; +} + +/* + * EV_BuildStairs() + * + * Handles staircase building. A sequence of sectors chosen by algorithm + * rise at a speed indicated to a height that increases by the stepsize + * each step. + * + * Passed the linedef triggering the stairs and the type of stair rise + * Returns true if any thinkers are created + * + * cph 2001/09/21 - compatibility nightmares again + * There are three different ways this function has, during its history, stepped + * through all the stairs to be triggered by the single switch + * - original Doom used a linear P_FindSectorFromLineTag, but failed to preserve + * the index of the previous sector found, so instead it would restart its + * linear search from the last sector of the previous staircase + * - MBF/PrBoom with comp_stairs fail to emulate this, because their + * P_FindSectorFromLineTag is a chained hash table implementation. Instead they + * start following the hash chain from the last sector of the previous + * staircase, which will (probably) have the wrong tag, so they miss any further + * stairs + * - Boom fixed the bug, and MBF/PrBoom without comp_stairs work right + */ +static inline int P_FindSectorFromLineTagWithLowerBound +(line_t* l, int start, int min) +{ + /* Emulate original Doom's linear lower-bounded P_FindSectorFromLineTag + * as needed */ + do { + start = P_FindSectorFromLineTag(l,start); + } while (start >= 0 && start <= min); + return start; +} + +int EV_BuildStairs +( line_t* line, + stair_e type ) +{ + /* cph 2001/09/22 - cleaned up this function to save my sanity. A separate + * outer loop index makes the logic much cleared, and local variables moved + * into the inner blocks helps too */ + int ssec = -1; + int minssec = -1; + int rtn = 0; + + // start a stair at each sector tagged the same as the linedef + while ((ssec = P_FindSectorFromLineTagWithLowerBound(line,ssec,minssec)) >= 0) + { + int secnum = ssec; + sector_t* sec = §ors[secnum]; + + // don't start a stair if the first step's floor is already moving + if (!P_SectorActive(floor_special,sec)) { //jff 2/22/98 + floormove_t* floor; + int texture, height; + fixed_t stairsize; + fixed_t speed; + int ok; + + // create new floor thinker for first step + rtn = 1; + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + memset(floor, 0, sizeof(*floor)); + P_AddThinker (&floor->thinker); + sec->floordata = floor; + floor->thinker.function = T_MoveFloor; + floor->direction = 1; + floor->sector = sec; + floor->type = buildStair; //jff 3/31/98 do not leave uninited + + // set up the speed and stepsize according to the stairs type + switch(type) + { + default: // killough -- prevent compiler warning + case build8: + speed = FLOORSPEED/4; + stairsize = 8*FRACUNIT; + if (!demo_compatibility) + floor->crush = false; //jff 2/27/98 fix uninitialized crush field + break; + case turbo16: + speed = FLOORSPEED*4; + stairsize = 16*FRACUNIT; + if (!demo_compatibility) + floor->crush = true; //jff 2/27/98 fix uninitialized crush field + break; + } + floor->speed = speed; + height = sec->floorheight + stairsize; + floor->floordestheight = height; + + texture = sec->floorpic; + + // Find next sector to raise + // 1. Find 2-sided line with same sector side[0] (lowest numbered) + // 2. Other side is the next sector to raise + // 3. Unless already moving, or different texture, then stop building + do + { + int i; + ok = 0; + + for (i = 0;i < sec->linecount;i++) + { + sector_t* tsec = (sec->lines[i])->frontsector; + int newsecnum; + if ( !((sec->lines[i])->flags & ML_TWOSIDED) ) + continue; + + newsecnum = tsec-sectors; + + if (secnum != newsecnum) + continue; + + tsec = (sec->lines[i])->backsector; + if (!tsec) continue; //jff 5/7/98 if no backside, continue + newsecnum = tsec - sectors; + + // if sector's floor is different texture, look for another + if (tsec->floorpic != texture) + continue; + + /* jff 6/19/98 prevent double stepsize + * killough 10/98: intentionally left this way [MBF comment] + * cph 2001/02/06: stair bug fix should be controlled by comp_stairs, + * except if we're emulating MBF which perversly reverted the fix + */ + if (comp[comp_stairs] || (compatibility_level == mbf_compatibility)) + height += stairsize; // jff 6/28/98 change demo compatibility + + // if sector's floor already moving, look for another + if (P_SectorActive(floor_special,tsec)) //jff 2/22/98 + continue; + + /* cph - see comment above - do this iff we didn't do so above */ + if (!comp[comp_stairs] && (compatibility_level != mbf_compatibility)) + height += stairsize; + + sec = tsec; + secnum = newsecnum; + + // create and initialize a thinker for the next step + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + memset(floor, 0, sizeof(*floor)); + P_AddThinker (&floor->thinker); + + sec->floordata = floor; //jff 2/22/98 + floor->thinker.function = T_MoveFloor; + floor->direction = 1; + floor->sector = sec; + floor->speed = speed; + floor->floordestheight = height; + floor->type = buildStair; //jff 3/31/98 do not leave uninited + //jff 2/27/98 fix uninitialized crush field + if (!demo_compatibility) + floor->crush = type==build8? false : true; + ok = 1; + break; + } + } while(ok); // continue until no next step is found + + } + /* killough 10/98: compatibility option */ + if (comp[comp_stairs]) { + /* cph 2001/09/22 - emulate buggy MBF comp_stairs for demos, with logic + * reversed since we now have a separate outer loop index. + * DEMOSYNC - what about boom_compatibility_compatibility? + */ + if ((compatibility_level >= mbf_compatibility) && (compatibility_level < + prboom_3_compatibility)) ssec = secnum; /* Trash outer loop index */ + else { + /* cph 2001/09/22 - now the correct comp_stairs - Doom used a linear + * search from the last secnum, so we set that as a minimum value and do + * a fresh tag search + */ + ssec = -1; minssec = secnum; + } + } + } + return rtn; +} + +// +// EV_DoDonut() +// +// Handle donut function: lower pillar, raise surrounding pool, both to height, +// texture and type of the sector surrounding the pool. +// +// Passed the linedef that triggered the donut +// Returns whether a thinker was created +// +int EV_DoDonut(line_t* line) +{ + sector_t* s1; + sector_t* s2; + sector_t* s3; + int secnum; + int rtn; + int i; + floormove_t* floor; + + secnum = -1; + rtn = 0; + // do function on all sectors with same tag as linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + s1 = §ors[secnum]; // s1 is pillar's sector + + // do not start the donut if the pillar is already moving + if (P_SectorActive(floor_special,s1)) //jff 2/22/98 + continue; + + s2 = getNextSector(s1->lines[0],s1); // s2 is pool's sector + if (!s2) continue; // note lowest numbered line around + // pillar must be two-sided + + /* do not start the donut if the pool is already moving + * cph - DEMOSYNC - was !compatibility */ + if (!comp[comp_floors] && P_SectorActive(floor_special,s2)) + continue; //jff 5/7/98 + + // find a two sided line around the pool whose other side isn't the pillar + for (i = 0;i < s2->linecount;i++) + { + //jff 3/29/98 use true two-sidedness, not the flag + // killough 4/5/98: changed demo_compatibility to compatibility + if (comp[comp_model]) + { + if ((!s2->lines[i]->flags & ML_TWOSIDED) || + (s2->lines[i]->backsector == s1)) + continue; + } + else if (!s2->lines[i]->backsector || s2->lines[i]->backsector == s1) + continue; + + rtn = 1; //jff 1/26/98 no donut action - no switch change on return + + s3 = s2->lines[i]->backsector; // s3 is model sector for changes + + // Spawn rising slime + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + memset(floor, 0, sizeof(*floor)); + P_AddThinker (&floor->thinker); + s2->floordata = floor; //jff 2/22/98 + floor->thinker.function = T_MoveFloor; + floor->type = donutRaise; + floor->crush = false; + floor->direction = 1; + floor->sector = s2; + floor->speed = FLOORSPEED / 2; + floor->texture = s3->floorpic; + floor->newspecial = 0; + floor->floordestheight = s3->floorheight; + + // Spawn lowering donut-hole pillar + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + memset(floor, 0, sizeof(*floor)); + P_AddThinker (&floor->thinker); + s1->floordata = floor; //jff 2/22/98 + floor->thinker.function = T_MoveFloor; + floor->type = lowerFloor; + floor->crush = false; + floor->direction = -1; + floor->sector = s1; + floor->speed = FLOORSPEED / 2; + floor->floordestheight = s3->floorheight; + break; + } + } + return rtn; +} + +// +// EV_DoElevator +// +// Handle elevator linedef types +// +// Passed the linedef that triggered the elevator and the elevator action +// +// jff 2/22/98 new type to move floor and ceiling in parallel +// +int EV_DoElevator +( line_t* line, + elevator_e elevtype ) +{ + int secnum; + int rtn; + sector_t* sec; + elevator_t* elevator; + + secnum = -1; + rtn = 0; + // act on all sectors with the same tag as the triggering linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + + // If either floor or ceiling is already activated, skip it + if (sec->floordata || sec->ceilingdata) //jff 2/22/98 + continue; + + // create and initialize new elevator thinker + rtn = 1; + elevator = Z_Malloc (sizeof(*elevator), PU_LEVSPEC, 0); + memset(elevator, 0, sizeof(*elevator)); + P_AddThinker (&elevator->thinker); + sec->floordata = elevator; //jff 2/22/98 + sec->ceilingdata = elevator; //jff 2/22/98 + elevator->thinker.function = T_MoveElevator; + elevator->type = elevtype; + + // set up the fields according to the type of elevator action + switch(elevtype) + { + // elevator down to next floor + case elevateDown: + elevator->direction = -1; + elevator->sector = sec; + elevator->speed = ELEVATORSPEED; + elevator->floordestheight = + P_FindNextLowestFloor(sec,sec->floorheight); + elevator->ceilingdestheight = + elevator->floordestheight + sec->ceilingheight - sec->floorheight; + break; + + // elevator up to next floor + case elevateUp: + elevator->direction = 1; + elevator->sector = sec; + elevator->speed = ELEVATORSPEED; + elevator->floordestheight = + P_FindNextHighestFloor(sec,sec->floorheight); + elevator->ceilingdestheight = + elevator->floordestheight + sec->ceilingheight - sec->floorheight; + break; + + // elevator to floor height of activating switch's front sector + case elevateCurrent: + elevator->sector = sec; + elevator->speed = ELEVATORSPEED; + elevator->floordestheight = line->frontsector->floorheight; + elevator->ceilingdestheight = + elevator->floordestheight + sec->ceilingheight - sec->floorheight; + elevator->direction = + elevator->floordestheight>sec->floorheight? 1 : -1; + break; + + default: + break; + } + } + return rtn; +} diff --git a/src/p_genlin.c b/src/p_genlin.c new file mode 100644 index 0000000..873b25b --- /dev/null +++ b/src/p_genlin.c @@ -0,0 +1,1164 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Generalized linedef type handlers + * Floors, Ceilings, Doors, Locked Doors, Lifts, Stairs, Crushers + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" //jff 6/19/98 for demo_compatibility +#include "r_main.h" +#include "p_spec.h" +#include "p_tick.h" +#include "m_random.h" +#include "s_sound.h" +#include "sounds.h" + +////////////////////////////////////////////////////////// +// +// Generalized Linedef Type handlers +// +////////////////////////////////////////////////////////// + +// +// EV_DoGenFloor() +// +// Handle generalized floor types +// +// Passed the line activating the generalized floor function +// Returns true if a thinker is created +// +// jff 02/04/98 Added this routine (and file) to handle generalized +// floor movers using bit fields in the line special type. +// +int EV_DoGenFloor +( line_t* line ) +{ + int secnum; + int rtn; + boolean manual; + sector_t* sec; + floormove_t* floor; + unsigned value = (unsigned)line->special - GenFloorBase; + + // parse the bit fields in the line's special type + + int Crsh = (value & FloorCrush) >> FloorCrushShift; + int ChgT = (value & FloorChange) >> FloorChangeShift; + int Targ = (value & FloorTarget) >> FloorTargetShift; + int Dirn = (value & FloorDirection) >> FloorDirectionShift; + int ChgM = (value & FloorModel) >> FloorModelShift; + int Sped = (value & FloorSpeed) >> FloorSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + rtn = 0; + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_floor; + } + + secnum = -1; + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + +manual_floor: + // Do not start another function if floor already moving + if (P_SectorActive(floor_special,sec)) + { + if (!manual) + continue; + else + return rtn; + } + + // new floor thinker + rtn = 1; + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + memset(floor, 0, sizeof(*floor)); + P_AddThinker (&floor->thinker); + sec->floordata = floor; + floor->thinker.function = T_MoveFloor; + floor->crush = Crsh; + floor->direction = Dirn? 1 : -1; + floor->sector = sec; + floor->texture = sec->floorpic; + floor->newspecial = sec->special; + //jff 3/14/98 transfer old special field too + floor->oldspecial = sec->oldspecial; + floor->type = genFloor; + + // set the speed of motion + switch (Sped) + { + case SpeedSlow: + floor->speed = FLOORSPEED; + break; + case SpeedNormal: + floor->speed = FLOORSPEED*2; + break; + case SpeedFast: + floor->speed = FLOORSPEED*4; + break; + case SpeedTurbo: + floor->speed = FLOORSPEED*8; + break; + default: + break; + } + + // set the destination height + switch(Targ) + { + case FtoHnF: + floor->floordestheight = P_FindHighestFloorSurrounding(sec); + break; + case FtoLnF: + floor->floordestheight = P_FindLowestFloorSurrounding(sec); + break; + case FtoNnF: + floor->floordestheight = Dirn? + P_FindNextHighestFloor(sec,sec->floorheight) : + P_FindNextLowestFloor(sec,sec->floorheight); + break; + case FtoLnC: + floor->floordestheight = P_FindLowestCeilingSurrounding(sec); + break; + case FtoC: + floor->floordestheight = sec->ceilingheight; + break; + case FbyST: + floor->floordestheight = (floor->sector->floorheight>>FRACBITS) + + floor->direction * (P_FindShortestTextureAround(secnum)>>FRACBITS); + if (floor->floordestheight>32000) //jff 3/13/98 prevent overflow + floor->floordestheight=32000; // wraparound in floor height + if (floor->floordestheight<-32000) + floor->floordestheight=-32000; + floor->floordestheight<<=FRACBITS; + break; + case Fby24: + floor->floordestheight = floor->sector->floorheight + + floor->direction * 24*FRACUNIT; + break; + case Fby32: + floor->floordestheight = floor->sector->floorheight + + floor->direction * 32*FRACUNIT; + break; + default: + break; + } + + // set texture/type change properties + if (ChgT) // if a texture change is indicated + { + if (ChgM) // if a numeric model change + { + sector_t *sec; + + //jff 5/23/98 find model with ceiling at target height if target + //is a ceiling type + sec = (Targ==FtoLnC || Targ==FtoC)? + P_FindModelCeilingSector(floor->floordestheight,secnum) : + P_FindModelFloorSector(floor->floordestheight,secnum); + if (sec) + { + floor->texture = sec->floorpic; + switch(ChgT) + { + case FChgZero: // zero type + floor->newspecial = 0; + //jff 3/14/98 change old field too + floor->oldspecial = 0; + floor->type = genFloorChg0; + break; + case FChgTyp: // copy type + floor->newspecial = sec->special; + //jff 3/14/98 change old field too + floor->oldspecial = sec->oldspecial; + floor->type = genFloorChgT; + break; + case FChgTxt: // leave type be + floor->type = genFloorChg; + break; + default: + break; + } + } + } + else // else if a trigger model change + { + floor->texture = line->frontsector->floorpic; + switch (ChgT) + { + case FChgZero: // zero type + floor->newspecial = 0; + //jff 3/14/98 change old field too + floor->oldspecial = 0; + floor->type = genFloorChg0; + break; + case FChgTyp: // copy type + floor->newspecial = line->frontsector->special; + //jff 3/14/98 change old field too + floor->oldspecial = line->frontsector->oldspecial; + floor->type = genFloorChgT; + break; + case FChgTxt: // leave type be + floor->type = genFloorChg; + default: + break; + } + } + } + if (manual) return rtn; + } + return rtn; +} + + +// +// EV_DoGenCeiling() +// +// Handle generalized ceiling types +// +// Passed the linedef activating the ceiling function +// Returns true if a thinker created +// +// jff 02/04/98 Added this routine (and file) to handle generalized +// floor movers using bit fields in the line special type. +// +int EV_DoGenCeiling +( line_t* line ) +{ + int secnum; + int rtn; + boolean manual; + fixed_t targheight; + sector_t* sec; + ceiling_t* ceiling; + unsigned value = (unsigned)line->special - GenCeilingBase; + + // parse the bit fields in the line's special type + + int Crsh = (value & CeilingCrush) >> CeilingCrushShift; + int ChgT = (value & CeilingChange) >> CeilingChangeShift; + int Targ = (value & CeilingTarget) >> CeilingTargetShift; + int Dirn = (value & CeilingDirection) >> CeilingDirectionShift; + int ChgM = (value & CeilingModel) >> CeilingModelShift; + int Sped = (value & CeilingSpeed) >> CeilingSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + rtn = 0; + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_ceiling; + } + + secnum = -1; + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + +manual_ceiling: + // Do not start another function if ceiling already moving + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + { + if (!manual) + continue; + else + return rtn; + } + + // new ceiling thinker + rtn = 1; + ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0); + memset(ceiling, 0, sizeof(*ceiling)); + P_AddThinker (&ceiling->thinker); + sec->ceilingdata = ceiling; //jff 2/22/98 + ceiling->thinker.function = T_MoveCeiling; + ceiling->crush = Crsh; + ceiling->direction = Dirn? 1 : -1; + ceiling->sector = sec; + ceiling->texture = sec->ceilingpic; + ceiling->newspecial = sec->special; + //jff 3/14/98 change old field too + ceiling->oldspecial = sec->oldspecial; + ceiling->tag = sec->tag; + ceiling->type = genCeiling; + + // set speed of motion + switch (Sped) + { + case SpeedSlow: + ceiling->speed = CEILSPEED; + break; + case SpeedNormal: + ceiling->speed = CEILSPEED*2; + break; + case SpeedFast: + ceiling->speed = CEILSPEED*4; + break; + case SpeedTurbo: + ceiling->speed = CEILSPEED*8; + break; + default: + break; + } + + // set destination target height + targheight = sec->ceilingheight; + switch(Targ) + { + case CtoHnC: + targheight = P_FindHighestCeilingSurrounding(sec); + break; + case CtoLnC: + targheight = P_FindLowestCeilingSurrounding(sec); + break; + case CtoNnC: + targheight = Dirn? + P_FindNextHighestCeiling(sec,sec->ceilingheight) : + P_FindNextLowestCeiling(sec,sec->ceilingheight); + break; + case CtoHnF: + targheight = P_FindHighestFloorSurrounding(sec); + break; + case CtoF: + targheight = sec->floorheight; + break; + case CbyST: + targheight = (ceiling->sector->ceilingheight>>FRACBITS) + + ceiling->direction * (P_FindShortestUpperAround(secnum)>>FRACBITS); + if (targheight>32000) //jff 3/13/98 prevent overflow + targheight=32000; // wraparound in ceiling height + if (targheight<-32000) + targheight=-32000; + targheight<<=FRACBITS; + break; + case Cby24: + targheight = ceiling->sector->ceilingheight + + ceiling->direction * 24*FRACUNIT; + break; + case Cby32: + targheight = ceiling->sector->ceilingheight + + ceiling->direction * 32*FRACUNIT; + break; + default: + break; + } + if (Dirn) ceiling->topheight = targheight; + else ceiling->bottomheight = targheight; + + // set texture/type change properties + if (ChgT) // if a texture change is indicated + { + if (ChgM) // if a numeric model change + { + sector_t *sec; + + //jff 5/23/98 find model with floor at target height if target + //is a floor type + sec = (Targ==CtoHnF || Targ==CtoF)? + P_FindModelFloorSector(targheight,secnum) : + P_FindModelCeilingSector(targheight,secnum); + if (sec) + { + ceiling->texture = sec->ceilingpic; + switch (ChgT) + { + case CChgZero: // type is zeroed + ceiling->newspecial = 0; + //jff 3/14/98 change old field too + ceiling->oldspecial = 0; + ceiling->type = genCeilingChg0; + break; + case CChgTyp: // type is copied + ceiling->newspecial = sec->special; + //jff 3/14/98 change old field too + ceiling->oldspecial = sec->oldspecial; + ceiling->type = genCeilingChgT; + break; + case CChgTxt: // type is left alone + ceiling->type = genCeilingChg; + break; + default: + break; + } + } + } + else // else if a trigger model change + { + ceiling->texture = line->frontsector->ceilingpic; + switch (ChgT) + { + case CChgZero: // type is zeroed + ceiling->newspecial = 0; + //jff 3/14/98 change old field too + ceiling->oldspecial = 0; + ceiling->type = genCeilingChg0; + break; + case CChgTyp: // type is copied + ceiling->newspecial = line->frontsector->special; + //jff 3/14/98 change old field too + ceiling->oldspecial = line->frontsector->oldspecial; + ceiling->type = genCeilingChgT; + break; + case CChgTxt: // type is left alone + ceiling->type = genCeilingChg; + break; + default: + break; + } + } + } + P_AddActiveCeiling(ceiling); // add this ceiling to the active list + if (manual) return rtn; + } + return rtn; +} + +// +// EV_DoGenLift() +// +// Handle generalized lift types +// +// Passed the linedef activating the lift +// Returns true if a thinker is created +// +int EV_DoGenLift +( line_t* line ) +{ + plat_t* plat; + int secnum; + int rtn; + boolean manual; + sector_t* sec; + unsigned value = (unsigned)line->special - GenLiftBase; + + // parse the bit fields in the line's special type + + int Targ = (value & LiftTarget) >> LiftTargetShift; + int Dely = (value & LiftDelay) >> LiftDelayShift; + int Sped = (value & LiftSpeed) >> LiftSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + secnum = -1; + rtn = 0; + + // Activate all plats that are in_stasis + + if (Targ==LnF2HnF) + P_ActivateInStasis(line->tag); + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_lift; + } + + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + +manual_lift: + // Do not start another function if floor already moving + if (P_SectorActive(floor_special,sec)) + { + if (!manual) + continue; + else + return rtn; + } + + // Setup the plat thinker + rtn = 1; + plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0); + memset(plat, 0, sizeof(*plat)); + P_AddThinker(&plat->thinker); + + plat->sector = sec; + plat->sector->floordata = plat; + plat->thinker.function = T_PlatRaise; + plat->crush = false; + plat->tag = line->tag; + + plat->type = genLift; + plat->high = sec->floorheight; + plat->status = down; + + // setup the target destination height + switch(Targ) + { + case F2LnF: + plat->low = P_FindLowestFloorSurrounding(sec); + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + break; + case F2NnF: + plat->low = P_FindNextLowestFloor(sec,sec->floorheight); + break; + case F2LnC: + plat->low = P_FindLowestCeilingSurrounding(sec); + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + break; + case LnF2HnF: + plat->type = genPerpetual; + plat->low = P_FindLowestFloorSurrounding(sec); + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + plat->high = P_FindHighestFloorSurrounding(sec); + if (plat->high < sec->floorheight) + plat->high = sec->floorheight; + plat->status = P_Random(pr_genlift)&1; + break; + default: + break; + } + + // setup the speed of motion + switch(Sped) + { + case SpeedSlow: + plat->speed = PLATSPEED * 2; + break; + case SpeedNormal: + plat->speed = PLATSPEED * 4; + break; + case SpeedFast: + plat->speed = PLATSPEED * 8; + break; + case SpeedTurbo: + plat->speed = PLATSPEED * 16; + break; + default: + break; + } + + // setup the delay time before the floor returns + switch(Dely) + { + case 0: + plat->wait = 1*35; + break; + case 1: + plat->wait = PLATWAIT*35; + break; + case 2: + plat->wait = 5*35; + break; + case 3: + plat->wait = 10*35; + break; + } + + S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart); + P_AddActivePlat(plat); // add this plat to the list of active plats + + if (manual) + return rtn; + } + return rtn; +} + +// +// EV_DoGenStairs() +// +// Handle generalized stair building +// +// Passed the linedef activating the stairs +// Returns true if a thinker is created +// +int EV_DoGenStairs +( line_t* line ) +{ + int secnum; + int osecnum; //jff 3/4/98 preserve loop index + int height; + int i; + int newsecnum; + int texture; + int ok; + int rtn; + boolean manual; + + sector_t* sec; + sector_t* tsec; + + floormove_t* floor; + + fixed_t stairsize; + fixed_t speed; + + unsigned value = (unsigned)line->special - GenStairsBase; + + // parse the bit fields in the line's special type + + int Igno = (value & StairIgnore) >> StairIgnoreShift; + int Dirn = (value & StairDirection) >> StairDirectionShift; + int Step = (value & StairStep) >> StairStepShift; + int Sped = (value & StairSpeed) >> StairSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + rtn = 0; + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_stair; + } + + secnum = -1; + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + +manual_stair: + //Do not start another function if floor already moving + //jff 2/26/98 add special lockout condition to wait for entire + //staircase to build before retriggering + if (P_SectorActive(floor_special,sec) || sec->stairlock) + { + if (!manual) + continue; + else + return rtn; + } + + // new floor thinker + rtn = 1; + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + memset(floor, 0, sizeof(*floor)); + P_AddThinker (&floor->thinker); + sec->floordata = floor; + floor->thinker.function = T_MoveFloor; + floor->direction = Dirn? 1 : -1; + floor->sector = sec; + + // setup speed of stair building + switch(Sped) + { + default: + case SpeedSlow: + floor->speed = FLOORSPEED/4; + break; + case SpeedNormal: + floor->speed = FLOORSPEED/2; + break; + case SpeedFast: + floor->speed = FLOORSPEED*2; + break; + case SpeedTurbo: + floor->speed = FLOORSPEED*4; + break; + } + + // setup stepsize for stairs + switch(Step) + { + default: + case 0: + stairsize = 4*FRACUNIT; + break; + case 1: + stairsize = 8*FRACUNIT; + break; + case 2: + stairsize = 16*FRACUNIT; + break; + case 3: + stairsize = 24*FRACUNIT; + break; + } + + speed = floor->speed; + height = sec->floorheight + floor->direction * stairsize; + floor->floordestheight = height; + texture = sec->floorpic; + floor->crush = false; + floor->type = genBuildStair; // jff 3/31/98 do not leave uninited + + sec->stairlock = -2; // jff 2/26/98 set up lock on current sector + sec->nextsec = -1; + sec->prevsec = -1; + + osecnum = secnum; //jff 3/4/98 preserve loop index + // Find next sector to raise + // 1. Find 2-sided line with same sector side[0] + // 2. Other side is the next sector to raise + do + { + ok = 0; + for (i = 0;i < sec->linecount;i++) + { + if ( !((sec->lines[i])->backsector) ) + continue; + + tsec = (sec->lines[i])->frontsector; + newsecnum = tsec-sectors; + + if (secnum != newsecnum) + continue; + + tsec = (sec->lines[i])->backsector; + newsecnum = tsec - sectors; + + if (!Igno && tsec->floorpic != texture) + continue; + + /* jff 6/19/98 prevent double stepsize */ + if (compatibility_level < boom_202_compatibility) + height += floor->direction * stairsize; + + //jff 2/26/98 special lockout condition for retriggering + if (P_SectorActive(floor_special,tsec) || tsec->stairlock) + continue; + + /* jff 6/19/98 increase height AFTER continue */ + if (compatibility_level >= boom_202_compatibility) + height += floor->direction * stairsize; + + // jff 2/26/98 + // link the stair chain in both directions + // lock the stair sector until building complete + sec->nextsec = newsecnum; // link step to next + tsec->prevsec = secnum; // link next back + tsec->nextsec = -1; // set next forward link as end + tsec->stairlock = -2; // lock the step + + sec = tsec; + secnum = newsecnum; + floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); + + memset(floor, 0, sizeof(*floor)); + P_AddThinker (&floor->thinker); + + sec->floordata = floor; + floor->thinker.function = T_MoveFloor; + floor->direction = Dirn? 1 : -1; + floor->sector = sec; + floor->speed = speed; + floor->floordestheight = height; + floor->crush = false; + floor->type = genBuildStair; // jff 3/31/98 do not leave uninited + + ok = 1; + break; + } + } while(ok); + if (manual) + return rtn; + secnum = osecnum; //jff 3/4/98 restore old loop index + } + // retriggerable generalized stairs build up or down alternately + if (rtn) + line->special ^= StairDirection; // alternate dir on succ activations + return rtn; +} + +// +// EV_DoGenCrusher() +// +// Handle generalized crusher types +// +// Passed the linedef activating the crusher +// Returns true if a thinker created +// +int EV_DoGenCrusher +( line_t* line ) +{ + int secnum; + int rtn; + boolean manual; + sector_t* sec; + ceiling_t* ceiling; + unsigned value = (unsigned)line->special - GenCrusherBase; + + // parse the bit fields in the line's special type + + int Slnt = (value & CrusherSilent) >> CrusherSilentShift; + int Sped = (value & CrusherSpeed) >> CrusherSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + //jff 2/22/98 Reactivate in-stasis ceilings...for certain types. + //jff 4/5/98 return if activated + rtn = P_ActivateInStasisCeiling(line); + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_crusher; + } + + secnum = -1; + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + +manual_crusher: + // Do not start another function if ceiling already moving + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + { + if (!manual) + continue; + else + return rtn; + } + + // new ceiling thinker + rtn = 1; + ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0); + memset(ceiling, 0, sizeof(*ceiling)); + P_AddThinker (&ceiling->thinker); + sec->ceilingdata = ceiling; //jff 2/22/98 + ceiling->thinker.function = T_MoveCeiling; + ceiling->crush = true; + ceiling->direction = -1; + ceiling->sector = sec; + ceiling->texture = sec->ceilingpic; + ceiling->newspecial = sec->special; + ceiling->tag = sec->tag; + ceiling->type = Slnt? genSilentCrusher : genCrusher; + ceiling->topheight = sec->ceilingheight; + ceiling->bottomheight = sec->floorheight + (8*FRACUNIT); + + // setup ceiling motion speed + switch (Sped) + { + case SpeedSlow: + ceiling->speed = CEILSPEED; + break; + case SpeedNormal: + ceiling->speed = CEILSPEED*2; + break; + case SpeedFast: + ceiling->speed = CEILSPEED*4; + break; + case SpeedTurbo: + ceiling->speed = CEILSPEED*8; + break; + default: + break; + } + ceiling->oldspeed=ceiling->speed; + + P_AddActiveCeiling(ceiling); // add to list of active ceilings + if (manual) return rtn; + } + return rtn; +} + +// +// EV_DoGenLockedDoor() +// +// Handle generalized locked door types +// +// Passed the linedef activating the generalized locked door +// Returns true if a thinker created +// +int EV_DoGenLockedDoor +( line_t* line ) +{ + int secnum,rtn; + sector_t* sec; + vldoor_t* door; + boolean manual; + unsigned value = (unsigned)line->special - GenLockedBase; + + // parse the bit fields in the line's special type + + int Kind = (value & LockedKind) >> LockedKindShift; + int Sped = (value & LockedSpeed) >> LockedSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + rtn = 0; + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_locked; + } + + secnum = -1; + rtn = 0; + + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; +manual_locked: + // Do not start another function if ceiling already moving + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + { + if (!manual) + continue; + else + return rtn; + } + + // new door thinker + rtn = 1; + door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); + memset(door, 0, sizeof(*door)); + P_AddThinker (&door->thinker); + sec->ceilingdata = door; //jff 2/22/98 + + door->thinker.function = T_VerticalDoor; + door->sector = sec; + door->topwait = VDOORWAIT; + door->line = line; + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + door->direction = 1; + + /* killough 10/98: implement gradual lighting */ + door->lighttag = !comp[comp_doorlight] && + (line->special&6) == 6 && + line->special > GenLockedBase ? line->tag : 0; + + // setup speed of door motion + switch(Sped) + { + default: + case SpeedSlow: + door->type = Kind? genOpen : genRaise; + door->speed = VDOORSPEED; + break; + case SpeedNormal: + door->type = Kind? genOpen : genRaise; + door->speed = VDOORSPEED*2; + break; + case SpeedFast: + door->type = Kind? genBlazeOpen : genBlazeRaise; + door->speed = VDOORSPEED*4; + break; + case SpeedTurbo: + door->type = Kind? genBlazeOpen : genBlazeRaise; + door->speed = VDOORSPEED*8; + + break; + } + + // killough 4/15/98: fix generalized door opening sounds + // (previously they always had the blazing door close sound) + + S_StartSound((mobj_t *)&door->sector->soundorg, // killough 4/15/98 + door->speed >= VDOORSPEED*4 ? sfx_bdopn : sfx_doropn); + + if (manual) + return rtn; + } + return rtn; +} + +// +// EV_DoGenDoor() +// +// Handle generalized door types +// +// Passed the linedef activating the generalized door +// Returns true if a thinker created +// +int EV_DoGenDoor +( line_t* line ) +{ + int secnum,rtn; + sector_t* sec; + boolean manual; + vldoor_t* door; + unsigned value = (unsigned)line->special - GenDoorBase; + + // parse the bit fields in the line's special type + + int Dely = (value & DoorDelay) >> DoorDelayShift; + int Kind = (value & DoorKind) >> DoorKindShift; + int Sped = (value & DoorSpeed) >> DoorSpeedShift; + int Trig = (value & TriggerType) >> TriggerTypeShift; + + rtn = 0; + + // check if a manual trigger, if so do just the sector on the backside + manual = false; + if (Trig==PushOnce || Trig==PushMany) + { + if (!(sec = line->backsector)) + return rtn; + secnum = sec-sectors; + manual = true; + goto manual_door; + } + + + secnum = -1; + rtn = 0; + + // if not manual do all sectors tagged the same as the line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; +manual_door: + // Do not start another function if ceiling already moving + if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 + { + if (!manual) + continue; + else + return rtn; + } + + // new door thinker + rtn = 1; + door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); + memset(door, 0, sizeof(*door)); + P_AddThinker (&door->thinker); + sec->ceilingdata = door; //jff 2/22/98 + + door->thinker.function = T_VerticalDoor; + door->sector = sec; + // setup delay for door remaining open/closed + switch(Dely) + { + default: + case 0: + door->topwait = 35; + break; + case 1: + door->topwait = VDOORWAIT; + break; + case 2: + door->topwait = 2*VDOORWAIT; + break; + case 3: + door->topwait = 7*VDOORWAIT; + break; + } + + // setup speed of door motion + switch(Sped) + { + default: + case SpeedSlow: + door->speed = VDOORSPEED; + break; + case SpeedNormal: + door->speed = VDOORSPEED*2; + break; + case SpeedFast: + door->speed = VDOORSPEED*4; + break; + case SpeedTurbo: + door->speed = VDOORSPEED*8; + break; + } + door->line = line; // jff 1/31/98 remember line that triggered us + + /* killough 10/98: implement gradual lighting */ + door->lighttag = !comp[comp_doorlight] && + (line->special&6) == 6 && + line->special > GenLockedBase ? line->tag : 0; + + // set kind of door, whether it opens then close, opens, closes etc. + // assign target heights accordingly + switch(Kind) + { + case OdCDoor: + door->direction = 1; + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + if (door->topheight != sec->ceilingheight) + S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast || comp[comp_sound] ? sfx_bdopn : sfx_doropn); + door->type = Sped>=SpeedFast? genBlazeRaise : genRaise; + break; + case ODoor: + door->direction = 1; + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + if (door->topheight != sec->ceilingheight) + S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast || comp[comp_sound] ? sfx_bdopn : sfx_doropn); + door->type = Sped>=SpeedFast? genBlazeOpen : genOpen; + break; + case CdODoor: + door->topheight = sec->ceilingheight; + door->direction = -1; + S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast && !comp[comp_sound] ? sfx_bdcls : sfx_dorcls); + door->type = Sped>=SpeedFast? genBlazeCdO : genCdO; + break; + case CDoor: + door->topheight = P_FindLowestCeilingSurrounding(sec); + door->topheight -= 4*FRACUNIT; + door->direction = -1; + S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast && !comp[comp_sound] ? sfx_bdcls : sfx_dorcls); + door->type = Sped>=SpeedFast? genBlazeClose : genClose; + break; + default: + break; + } + if (manual) + return rtn; + } + return rtn; +} diff --git a/src/p_inter.c b/src/p_inter.c new file mode 100644 index 0000000..2688e95 --- /dev/null +++ b/src/p_inter.c @@ -0,0 +1,913 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Handling interactions (i.e., collisions). + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "dstrings.h" +#include "m_random.h" +#include "am_map.h" +#include "r_main.h" +#include "s_sound.h" +#include "sounds.h" +#include "d_deh.h" // Ty 03/22/98 - externalized strings +#include "p_tick.h" +#include "lprintf.h" + +#include "p_inter.h" +#include "p_enemy.h" + +#ifdef __GNUG__ +#pragma implementation "p_inter.h" +#endif +#include "p_inter.h" + +#define BONUSADD 6 + +// Ty 03/07/98 - add deh externals +// Maximums and such were hardcoded values. Need to externalize those for +// dehacked support (and future flexibility). Most var names came from the key +// strings used in dehacked. + +int initial_health = 100; +int initial_bullets = 50; +int maxhealth = 100; // was MAXHEALTH as a #define, used only in this module +int max_armor = 200; +int green_armor_class = 1; // these are involved with armortype below +int blue_armor_class = 2; +int max_soul = 200; +int soul_health = 100; +int mega_health = 200; +int god_health = 100; // these are used in cheats (see st_stuff.c) +int idfa_armor = 200; +int idfa_armor_class = 2; +// not actually used due to pairing of cheat_k and cheat_fa +int idkfa_armor = 200; +int idkfa_armor_class = 2; + +int bfgcells = 40; // used in p_pspr.c +int monsters_infight = 0; // e6y: Dehacked support - monsters infight +// Ty 03/07/98 - end deh externals + +// a weapon is found with two clip loads, +// a big item has five clip loads +int maxammo[NUMAMMO] = {200, 50, 300, 50}; +int clipammo[NUMAMMO] = { 10, 4, 20, 1}; + +// +// GET STUFF +// + +// +// P_GiveAmmo +// Num is the number of clip loads, +// not the individual count (0= 1/2 clip). +// Returns false if the ammo can't be picked up at all +// + +static boolean P_GiveAmmo(player_t *player, ammotype_t ammo, int num) +{ + int oldammo; + + if (ammo == am_noammo) + return false; + +#ifdef RANGECHECK + if (ammo < 0 || ammo > NUMAMMO) + I_Error ("P_GiveAmmo: bad type %i", ammo); +#endif + + if ( player->ammo[ammo] == player->maxammo[ammo] ) + return false; + + if (num) + num *= clipammo[ammo]; + else + num = clipammo[ammo]/2; + + // give double ammo in trainer mode, you'll need in nightmare + if (gameskill == sk_baby || gameskill == sk_nightmare) + num <<= 1; + + oldammo = player->ammo[ammo]; + player->ammo[ammo] += num; + + if (player->ammo[ammo] > player->maxammo[ammo]) + player->ammo[ammo] = player->maxammo[ammo]; + + // If non zero ammo, don't change up weapons, player was lower on purpose. + if (oldammo) + return true; + + // We were down to zero, so select a new weapon. + // Preferences are not user selectable. + + switch (ammo) + { + case am_clip: + if (player->readyweapon == wp_fist) { + if (player->weaponowned[wp_chaingun]) + player->pendingweapon = wp_chaingun; + else + player->pendingweapon = wp_pistol; + } + break; + + case am_shell: + if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol) + if (player->weaponowned[wp_shotgun]) + player->pendingweapon = wp_shotgun; + break; + + case am_cell: + if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol) + if (player->weaponowned[wp_plasma]) + player->pendingweapon = wp_plasma; + break; + + case am_misl: + if (player->readyweapon == wp_fist) + if (player->weaponowned[wp_missile]) + player->pendingweapon = wp_missile; + default: + break; + } + return true; +} + +// +// P_GiveWeapon +// The weapon name may have a MF_DROPPED flag ored in. +// + +static boolean P_GiveWeapon(player_t *player, weapontype_t weapon, boolean dropped) +{ + 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; + + P_GiveAmmo(player, weaponinfo[weapon].ammo, deathmatch ? 5 : 2); + + player->pendingweapon = weapon; + /* cph 20028/10 - for old-school DM addicts, allow old behavior + * where only consoleplayer's pickup sounds are heard */ + // displayplayer, not consoleplayer, for viewing multiplayer demos + if (!comp[comp_sound] || player == &players[displayplayer]) + S_StartSound (player->mo, sfx_wpnup|PICKUP_SOUND); // killough 4/25/98 + return false; + } + + if (weaponinfo[weapon].ammo != am_noammo) + { + // give one clip with a dropped weapon, + // two clips with a found weapon + gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, dropped ? 1 : 2); + } + else + gaveammo = false; + + if (player->weaponowned[weapon]) + gaveweapon = false; + else + { + gaveweapon = true; + player->weaponowned[weapon] = true; + player->pendingweapon = weapon; + } + return gaveweapon || gaveammo; +} + +// +// P_GiveBody +// Returns false if the body isn't needed at all +// + +static boolean P_GiveBody(player_t *player, int num) +{ + if (player->health >= maxhealth) + return false; // Ty 03/09/98 externalized MAXHEALTH to maxhealth + player->health += num; + if (player->health > maxhealth) + player->health = maxhealth; + player->mo->health = player->health; + return true; +} + +// +// P_GiveArmor +// Returns false if the armor is worse +// than the current armor. +// + +static boolean P_GiveArmor(player_t *player, int armortype) +{ + int hits = armortype*100; + if (player->armorpoints >= hits) + return false; // don't pick up + player->armortype = armortype; + player->armorpoints = hits; + return true; +} + +// +// P_GiveCard +// + +static void P_GiveCard(player_t *player, card_t card) +{ + if (player->cards[card]) + return; + player->bonuscount = BONUSADD; + player->cards[card] = 1; +} + +// +// P_GivePower +// +// Rewritten by Lee Killough +// + +boolean P_GivePower(player_t *player, int power) +{ + static const int tics[NUMPOWERS] = { + INVULNTICS, 1 /* strength */, INVISTICS, + IRONTICS, 1 /* allmap */, INFRATICS, + }; + + switch (power) + { + case pw_invisibility: + player->mo->flags |= MF_SHADOW; + break; + case pw_allmap: + if (player->powers[pw_allmap]) + return false; + break; + case pw_strength: + P_GiveBody(player,100); + break; + } + + // Unless player has infinite duration cheat, set duration (killough) + + if (player->powers[power] >= 0) + player->powers[power] = tics[power]; + return true; +} + +// +// P_TouchSpecialThing +// + +void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) +{ + player_t *player; + int i; + int sound; + fixed_t delta = special->z - toucher->z; + + if (delta > toucher->height || delta < -8*FRACUNIT) + return; // out of reach + + sound = sfx_itemup; + player = toucher->player; + + // Dead thing touching. + // Can happen with a sliding player corpse. + if (toucher->health <= 0) + return; + + // Identify by sprite. + switch (special->sprite) + { + // armor + case SPR_ARM1: + if (!P_GiveArmor (player, green_armor_class)) + return; + player->message = s_GOTARMOR; // Ty 03/22/98 - externalized + break; + + case SPR_ARM2: + if (!P_GiveArmor (player, blue_armor_class)) + return; + player->message = s_GOTMEGA; // Ty 03/22/98 - externalized + break; + + // bonus items + case SPR_BON1: + player->health++; // can go over 100% + if (player->health > (maxhealth * 2)) + player->health = (maxhealth * 2); + player->mo->health = player->health; + player->message = s_GOTHTHBONUS; // Ty 03/22/98 - externalized + break; + + case SPR_BON2: + player->armorpoints++; // can go over 100% + if (player->armorpoints > max_armor) + player->armorpoints = max_armor; + if (!player->armortype) + player->armortype = green_armor_class; + player->message = s_GOTARMBONUS; // Ty 03/22/98 - externalized + break; + + case SPR_SOUL: + player->health += soul_health; + if (player->health > max_soul) + player->health = max_soul; + player->mo->health = player->health; + player->message = s_GOTSUPER; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + case SPR_MEGA: + if (gamemode != commercial) + return; + player->health = mega_health; + player->mo->health = player->health; + P_GiveArmor (player,blue_armor_class); + player->message = s_GOTMSPHERE; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + // cards + // leave cards for everyone + case SPR_BKEY: + if (!player->cards[it_bluecard]) + player->message = s_GOTBLUECARD; // Ty 03/22/98 - externalized + P_GiveCard (player, it_bluecard); + if (!netgame) + break; + return; + + case SPR_YKEY: + if (!player->cards[it_yellowcard]) + player->message = s_GOTYELWCARD; // Ty 03/22/98 - externalized + P_GiveCard (player, it_yellowcard); + if (!netgame) + break; + return; + + case SPR_RKEY: + if (!player->cards[it_redcard]) + player->message = s_GOTREDCARD; // Ty 03/22/98 - externalized + P_GiveCard (player, it_redcard); + if (!netgame) + break; + return; + + case SPR_BSKU: + if (!player->cards[it_blueskull]) + player->message = s_GOTBLUESKUL; // Ty 03/22/98 - externalized + P_GiveCard (player, it_blueskull); + if (!netgame) + break; + return; + + case SPR_YSKU: + if (!player->cards[it_yellowskull]) + player->message = s_GOTYELWSKUL; // Ty 03/22/98 - externalized + P_GiveCard (player, it_yellowskull); + if (!netgame) + break; + return; + + case SPR_RSKU: + if (!player->cards[it_redskull]) + player->message = s_GOTREDSKULL; // Ty 03/22/98 - externalized + P_GiveCard (player, it_redskull); + if (!netgame) + break; + return; + + // medikits, heals + case SPR_STIM: + if (!P_GiveBody (player, 10)) + return; + player->message = s_GOTSTIM; // Ty 03/22/98 - externalized + break; + + case SPR_MEDI: + if (!P_GiveBody (player, 25)) + return; + + if (player->health < 50) // cph - 25 + the 25 just added, thanks to Quasar for reporting this bug + player->message = s_GOTMEDINEED; // Ty 03/22/98 - externalized + else + player->message = s_GOTMEDIKIT; // Ty 03/22/98 - externalized + break; + + + // power ups + case SPR_PINV: + if (!P_GivePower (player, pw_invulnerability)) + return; + player->message = s_GOTINVUL; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + case SPR_PSTR: + if (!P_GivePower (player, pw_strength)) + return; + player->message = s_GOTBERSERK; // Ty 03/22/98 - externalized + if (player->readyweapon != wp_fist) + player->pendingweapon = wp_fist; + sound = sfx_getpow; + break; + + case SPR_PINS: + if (!P_GivePower (player, pw_invisibility)) + return; + player->message = s_GOTINVIS; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + case SPR_SUIT: + if (!P_GivePower (player, pw_ironfeet)) + return; + player->message = s_GOTSUIT; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + case SPR_PMAP: + if (!P_GivePower (player, pw_allmap)) + return; + player->message = s_GOTMAP; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + case SPR_PVIS: + if (!P_GivePower (player, pw_infrared)) + return; + player->message = s_GOTVISOR; // Ty 03/22/98 - externalized + sound = sfx_getpow; + break; + + // ammo + case SPR_CLIP: + if (special->flags & MF_DROPPED) + { + if (!P_GiveAmmo (player,am_clip,0)) + return; + } + else + { + if (!P_GiveAmmo (player,am_clip,1)) + return; + } + player->message = s_GOTCLIP; // Ty 03/22/98 - externalized + break; + + case SPR_AMMO: + if (!P_GiveAmmo (player, am_clip,5)) + return; + player->message = s_GOTCLIPBOX; // Ty 03/22/98 - externalized + break; + + case SPR_ROCK: + if (!P_GiveAmmo (player, am_misl,1)) + return; + player->message = s_GOTROCKET; // Ty 03/22/98 - externalized + break; + + case SPR_BROK: + if (!P_GiveAmmo (player, am_misl,5)) + return; + player->message = s_GOTROCKBOX; // Ty 03/22/98 - externalized + break; + + case SPR_CELL: + if (!P_GiveAmmo (player, am_cell,1)) + return; + player->message = s_GOTCELL; // Ty 03/22/98 - externalized + break; + + case SPR_CELP: + if (!P_GiveAmmo (player, am_cell,5)) + return; + player->message = s_GOTCELLBOX; // Ty 03/22/98 - externalized + break; + + case SPR_SHEL: + if (!P_GiveAmmo (player, am_shell,1)) + return; + player->message = s_GOTSHELLS; // Ty 03/22/98 - externalized + break; + + case SPR_SBOX: + if (!P_GiveAmmo (player, am_shell,5)) + return; + player->message = s_GOTSHELLBOX; // Ty 03/22/98 - externalized + break; + + case SPR_BPAK: + if (!player->backpack) + { + for (i=0 ; imaxammo[i] *= 2; + player->backpack = true; + } + for (i=0 ; imessage = s_GOTBACKPACK; // Ty 03/22/98 - externalized + break; + + // weapons + case SPR_BFUG: + if (!P_GiveWeapon (player, wp_bfg, false) ) + return; + player->message = s_GOTBFG9000; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_MGUN: + if (!P_GiveWeapon (player, wp_chaingun, (special->flags&MF_DROPPED)!=0) ) + return; + player->message = s_GOTCHAINGUN; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_CSAW: + if (!P_GiveWeapon (player, wp_chainsaw, false) ) + return; + player->message = s_GOTCHAINSAW; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_LAUN: + if (!P_GiveWeapon (player, wp_missile, false) ) + return; + player->message = s_GOTLAUNCHER; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_PLAS: + if (!P_GiveWeapon (player, wp_plasma, false) ) + return; + player->message = s_GOTPLASMA; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_SHOT: + if (!P_GiveWeapon (player, wp_shotgun, (special->flags&MF_DROPPED)!=0 ) ) + return; + player->message = s_GOTSHOTGUN; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + case SPR_SGN2: + if (!P_GiveWeapon(player, wp_supershotgun, (special->flags&MF_DROPPED)!=0)) + return; + player->message = s_GOTSHOTGUN2; // Ty 03/22/98 - externalized + sound = sfx_wpnup; + break; + + default: + I_Error ("P_SpecialThing: Unknown gettable thing"); + } + + if (special->flags & MF_COUNTITEM) + player->itemcount++; + P_RemoveMobj (special); + player->bonuscount += BONUSADD; + + /* cph 20028/10 - for old-school DM addicts, allow old behavior + * where only consoleplayer's pickup sounds are heard */ + // displayplayer, not consoleplayer, for viewing multiplayer demos + if (!comp[comp_sound] || player == &players[displayplayer]) + S_StartSound (player->mo, sound | PICKUP_SOUND); // killough 4/25/98 +} + +// +// KillMobj +// +// killough 11/98: make static +static void P_KillMobj(mobj_t *source, mobj_t *target) +{ + mobjtype_t item; + mobj_t *mo; + + target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY); + + if (target->type != MT_SKULL) + target->flags &= ~MF_NOGRAVITY; + + target->flags |= MF_CORPSE|MF_DROPOFF; + target->height >>= 2; + + if (!((target->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL))) + totallive--; + + if (source && source->player) + { + // count for intermission + if (target->flags & MF_COUNTKILL) + source->player->killcount++; + if (target->player) + source->player->frags[target->player-players]++; + } + else + if (target->flags & MF_COUNTKILL) { /* Add to kills tally */ + if ((compatibility_level < lxdoom_1_compatibility) || !netgame) { + if (!netgame) + // count all monster deaths, + // even those caused by other monsters + players[0].killcount++; + } else + if (!deathmatch) { + // try and find a player to give the kill to, otherwise give the + // kill to a random player. this fixes the missing monsters bug + // in coop - rain + // CPhipps - not a bug as such, but certainly an inconsistency. + if (target->lastenemy && target->lastenemy->health > 0 + && target->lastenemy->player) // Fighting a player + target->lastenemy->player->killcount++; + else { + // cph - randomely choose a player in the game to be credited + // and do it uniformly between the active players + unsigned int activeplayers = 0, player, i; + + for (player = 0; playerplayer) + { + // count environment kills against you + if (!source) + target->player->frags[target->player-players]++; + + target->flags &= ~MF_SOLID; + target->player->playerstate = PST_DEAD; + P_DropWeapon (target->player); + + if (target->player == &players[consoleplayer] && (automapmode & am_active)) + AM_Stop(); // don't die in auto map; switch view prior to dying + } + + if (target->health < -target->info->spawnhealth && target->info->xdeathstate) + P_SetMobjState (target, target->info->xdeathstate); + else + P_SetMobjState (target, target->info->deathstate); + + target->tics -= P_Random(pr_killtics)&3; + + if (target->tics < 1) + target->tics = 1; + + // Drop stuff. + // This determines the kind of object spawned + // during the death frame of a thing. + + switch (target->type) + { + case MT_WOLFSS: + case MT_POSSESSED: + item = MT_CLIP; + break; + + case MT_SHOTGUY: + item = MT_SHOTGUN; + break; + + case MT_CHAINGUY: + item = MT_CHAINGUN; + break; + + default: + return; + } + + mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item); + mo->flags |= MF_DROPPED; // special versions of items +} + +// +// P_DamageMobj +// Damages both enemies and players +// "inflictor" is the thing that caused the damage +// creature or missile, can be NULL (slime, etc) +// "source" is the thing to target after taking damage +// creature or NULL +// Source and inflictor are the same for melee attacks. +// Source can be NULL for slime, barrel explosions +// and other environmental stuff. +// + +void P_DamageMobj(mobj_t *target,mobj_t *inflictor, mobj_t *source, int damage) +{ + player_t *player; + boolean justhit = false; /* killough 11/98 */ + + /* killough 8/31/98: allow bouncers to take damage */ + if (!(target->flags & (MF_SHOOTABLE | MF_BOUNCES))) + return; // shouldn't happen... + + if (target->health <= 0) + return; + + if (target->flags & MF_SKULLFLY) + target->momx = target->momy = target->momz = 0; + + player = target->player; + if (player && gameskill == sk_baby) + damage >>= 1; // take half damage in trainer mode + + // Some close combat weapons should not + // inflict thrust and push the victim out of reach, + // thus kick away unless using the chainsaw. + + if (inflictor && !(target->flags & MF_NOCLIP) && + (!source || !source->player || + source->player->readyweapon != wp_chainsaw)) + { + unsigned ang = R_PointToAngle2 (inflictor->x, inflictor->y, + target->x, target->y); + + fixed_t thrust = damage*(FRACUNIT>>3)*100/target->info->mass; + + // make fall forwards sometimes + if ( damage < 40 && damage > target->health + && target->z - inflictor->z > 64*FRACUNIT + && P_Random(pr_damagemobj) & 1) + { + ang += ANG180; + thrust *= 4; + } + + ang >>= ANGLETOFINESHIFT; + target->momx += FixedMul (thrust, finecosine[ang]); + target->momy += FixedMul (thrust, finesine[ang]); + + /* killough 11/98: thrust objects hanging off ledges */ + if (target->intflags & MIF_FALLING && target->gear >= MAXGEAR) + target->gear = 0; + } + + // player specific + if (player) + { + // end of game hell hack + if (target->subsector->sector->special == 11 && damage >= target->health) + damage = target->health - 1; + + // Below certain threshold, + // ignore damage in GOD mode, or with INVUL power. + // killough 3/26/98: make god mode 100% god mode in non-compat mode + + if ((damage < 1000 || (!comp[comp_god] && (player->cheats&CF_GODMODE))) && + (player->cheats&CF_GODMODE || player->powers[pw_invulnerability])) + return; + + if (player->armortype) + { + int saved = player->armortype == 1 ? damage/3 : damage/2; + if (player->armorpoints <= saved) + { + // armor is used up + saved = player->armorpoints; + player->armortype = 0; + } + player->armorpoints -= saved; + damage -= saved; + } + + player->health -= damage; // mirror mobj health here for Dave + if (player->health < 0) + player->health = 0; + + player->attacker = source; + player->damagecount += damage; // add damage after armor / invuln + + if (player->damagecount > 100) + player->damagecount = 100; // teleport stomp does 10k points... + } + + // do the damage + target->health -= damage; + if (target->health <= 0) + { + P_KillMobj (source, target); + return; + } + + // killough 9/7/98: keep track of targets so that friends can help friends + if (mbf_features) + { + /* If target is a player, set player's target to source, + * so that a friend can tell who's hurting a player + */ + if (player) + P_SetTarget(&target->target, source); + + /* killough 9/8/98: + * If target's health is less than 50%, move it to the front of its list. + * This will slightly increase the chances that enemies will choose to + * "finish it off", but its main purpose is to alert friends of danger. + */ + if (target->health*2 < target->info->spawnhealth) + { + thinker_t *cap = &thinkerclasscap[target->flags & MF_FRIEND ? + th_friends : th_enemies]; + (target->thinker.cprev->cnext = target->thinker.cnext)->cprev = + target->thinker.cprev; + (target->thinker.cnext = cap->cnext)->cprev = &target->thinker; + (target->thinker.cprev = cap)->cnext = &target->thinker; + } + } + + if (P_Random (pr_painchance) < target->info->painchance && + !(target->flags & MF_SKULLFLY)) { //killough 11/98: see below + if (mbf_features) + justhit = true; + else + target->flags |= MF_JUSTHIT; // fight back! + + P_SetMobjState(target, target->info->painstate); + } + + target->reactiontime = 0; // we're awake now... + + /* killough 9/9/98: cleaned up, made more consistent: */ + + if (source && source != target && source->type != MT_VILE && + (!target->threshold || target->type == MT_VILE) && + ((source->flags ^ target->flags) & MF_FRIEND || + monster_infighting || + !mbf_features)) + { + /* if not intent on another player, chase after this one + * + * killough 2/15/98: remember last enemy, to prevent + * sleeping early; 2/21/98: Place priority on players + * killough 9/9/98: cleaned up, made more consistent: + */ + + if (!target->lastenemy || target->lastenemy->health <= 0 || + (!mbf_features ? + !target->lastenemy->player : + !((target->flags ^ target->lastenemy->flags) & MF_FRIEND) && + target->target != source)) // remember last enemy - killough + P_SetTarget(&target->lastenemy, target->target); + + P_SetTarget(&target->target, source); // killough 11/98 + target->threshold = BASETHRESHOLD; + if (target->state == &states[target->info->spawnstate] + && target->info->seestate != S_NULL) + P_SetMobjState (target, target->info->seestate); + } + + /* killough 11/98: Don't attack a friend, unless hit by that friend. + * cph 2006/04/01 - implicitly this is only if mbf_features */ + if (justhit && (target->target == source || !target->target || + !(target->flags & target->target->flags & MF_FRIEND))) + target->flags |= MF_JUSTHIT; // fight back! +} diff --git a/src/p_inter.h b/src/p_inter.h new file mode 100644 index 0000000..53b64a7 --- /dev/null +++ b/src/p_inter.h @@ -0,0 +1,75 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Thing events, and dehacked specified numbers controlling them. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_INTER__ +#define __P_INTER__ + +#include "d_player.h" +#include "p_mobj.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +/* Ty 03/09/98 Moved to an int in p_inter.c for deh and externalization */ +#define MAXHEALTH maxhealth + +/* follow a player exlusively for 3 seconds */ +#define BASETHRESHOLD (100) + +boolean P_GivePower(player_t *, int); +void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher); +void P_DamageMobj(mobj_t *target,mobj_t *inflictor,mobj_t *source,int damage); + +/* killough 5/2/98: moved from d_deh.c, g_game.c, m_misc.c, others: */ + +extern int god_health; /* Ty 03/09/98 - deh support, see also p_inter.c */ +extern int idfa_armor; +extern int idfa_armor_class; +extern int idkfa_armor; +extern int idkfa_armor_class; /* Ty - end */ +/* Ty 03/13/98 - externalized initial settings for respawned player */ +extern int initial_health; +extern int initial_bullets; +extern int maxhealth; +extern int max_armor; +extern int green_armor_class; +extern int blue_armor_class; +extern int max_soul; +extern int soul_health; +extern int mega_health; +extern int bfgcells; +extern int monsters_infight; // e6y: Dehacked support - monsters infight +extern int maxammo[], clipammo[]; + +#endif diff --git a/src/p_lights.c b/src/p_lights.c new file mode 100644 index 0000000..84936e0 --- /dev/null +++ b/src/p_lights.c @@ -0,0 +1,443 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Action routines for lighting thinkers + * Spawn sector based lighting effects. + * Handle lighting linedef types + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" //jff 5/18/98 +#include "doomdef.h" +#include "m_random.h" +#include "r_main.h" +#include "p_spec.h" +#include "p_tick.h" + +////////////////////////////////////////////////////////// +// +// Lighting action routines, called once per tick +// +////////////////////////////////////////////////////////// + +// +// T_FireFlicker() +// +// Firelight flicker action routine, called once per tick +// +// Passed a fireflicker_t structure containing light levels and timing +// Returns nothing +// +void T_FireFlicker (fireflicker_t* flick) +{ + int amount; + + if (--flick->count) + return; + + amount = (P_Random(pr_lights)&3)*16; + + if (flick->sector->lightlevel - amount < flick->minlight) + flick->sector->lightlevel = flick->minlight; + else + flick->sector->lightlevel = flick->maxlight - amount; + + flick->count = 4; +} + +// +// T_LightFlash() +// +// Broken light flashing action routine, called once per tick +// +// Passed a lightflash_t structure containing light levels and timing +// Returns nothing +// +void T_LightFlash (lightflash_t* flash) +{ + if (--flash->count) + return; + + if (flash->sector->lightlevel == flash->maxlight) + { + flash-> sector->lightlevel = flash->minlight; + flash->count = (P_Random(pr_lights)&flash->mintime)+1; + } + else + { + flash-> sector->lightlevel = flash->maxlight; + flash->count = (P_Random(pr_lights)&flash->maxtime)+1; + } + +} + +// +// T_StrobeFlash() +// +// Strobe light flashing action routine, called once per tick +// +// Passed a strobe_t structure containing light levels and timing +// Returns nothing +// +void T_StrobeFlash (strobe_t* flash) +{ + if (--flash->count) + return; + + if (flash->sector->lightlevel == flash->minlight) + { + flash-> sector->lightlevel = flash->maxlight; + flash->count = flash->brighttime; + } + else + { + flash-> sector->lightlevel = flash->minlight; + flash->count =flash->darktime; + } +} + +// +// T_Glow() +// +// Glowing light action routine, called once per tick +// +// Passed a glow_t structure containing light levels and timing +// Returns nothing +// + +void T_Glow(glow_t* g) +{ + switch(g->direction) + { + case -1: + // light dims + g->sector->lightlevel -= GLOWSPEED; + if (g->sector->lightlevel <= g->minlight) + { + g->sector->lightlevel += GLOWSPEED; + g->direction = 1; + } + break; + + case 1: + // light brightens + g->sector->lightlevel += GLOWSPEED; + if (g->sector->lightlevel >= g->maxlight) + { + g->sector->lightlevel -= GLOWSPEED; + g->direction = -1; + } + break; + } +} + +////////////////////////////////////////////////////////// +// +// Sector lighting type spawners +// +// After the map has been loaded, each sector is scanned +// for specials that spawn thinkers +// +////////////////////////////////////////////////////////// + +// +// P_SpawnFireFlicker() +// +// Spawns a fire flicker lighting thinker +// +// Passed the sector that spawned the thinker +// Returns nothing +// +void P_SpawnFireFlicker (sector_t* sector) +{ + fireflicker_t* flick; + + // Note that we are resetting sector attributes. + // Nothing special about it during gameplay. + sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type + + flick = Z_Malloc ( sizeof(*flick), PU_LEVSPEC, 0); + + memset(flick, 0, sizeof(*flick)); + P_AddThinker (&flick->thinker); + + flick->thinker.function = T_FireFlicker; + flick->sector = sector; + flick->maxlight = sector->lightlevel; + flick->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel)+16; + flick->count = 4; +} + +// +// P_SpawnLightFlash() +// +// Spawns a broken light flash lighting thinker +// +// Passed the sector that spawned the thinker +// Returns nothing +// +void P_SpawnLightFlash (sector_t* sector) +{ + lightflash_t* flash; + + // nothing special about it during gameplay + sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type + + flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0); + + memset(flash, 0, sizeof(*flash)); + P_AddThinker (&flash->thinker); + + flash->thinker.function = T_LightFlash; + flash->sector = sector; + flash->maxlight = sector->lightlevel; + + flash->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel); + flash->maxtime = 64; + flash->mintime = 7; + flash->count = (P_Random(pr_lights)&flash->maxtime)+1; +} + +// +// P_SpawnStrobeFlash +// +// Spawns a blinking light thinker +// +// Passed the sector that spawned the thinker, speed of blinking +// and whether blinking is to by syncrhonous with other sectors +// +// Returns nothing +// +void P_SpawnStrobeFlash +( sector_t* sector, + int fastOrSlow, + int inSync ) +{ + strobe_t* flash; + + flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0); + + memset(flash, 0, sizeof(*flash)); + P_AddThinker (&flash->thinker); + + flash->sector = sector; + flash->darktime = fastOrSlow; + flash->brighttime = STROBEBRIGHT; + flash->thinker.function = T_StrobeFlash; + flash->maxlight = sector->lightlevel; + flash->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel); + + if (flash->minlight == flash->maxlight) + flash->minlight = 0; + + // nothing special about it during gameplay + sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type + + if (!inSync) + flash->count = (P_Random(pr_lights)&7)+1; + else + flash->count = 1; +} + +// +// P_SpawnGlowingLight() +// +// Spawns a glowing light (smooth oscillation from min to max) thinker +// +// Passed the sector that spawned the thinker +// Returns nothing +// +void P_SpawnGlowingLight(sector_t* sector) +{ + glow_t* g; + + g = Z_Malloc( sizeof(*g), PU_LEVSPEC, 0); + + memset(g, 0, sizeof(*g)); + P_AddThinker(&g->thinker); + + g->sector = sector; + g->minlight = P_FindMinSurroundingLight(sector,sector->lightlevel); + g->maxlight = sector->lightlevel; + g->thinker.function = T_Glow; + g->direction = -1; + + sector->special &= ~31; //jff 3/14/98 clear non-generalized sector type +} + +////////////////////////////////////////////////////////// +// +// Linedef lighting function handlers +// +////////////////////////////////////////////////////////// + +// +// EV_StartLightStrobing() +// +// Start strobing lights (usually from a trigger) +// +// Passed the line that activated the strobing +// Returns true +// +// jff 2/12/98 added int return value, fixed return +// +int EV_StartLightStrobing(line_t* line) +{ + int secnum; + sector_t* sec; + + secnum = -1; + // start lights strobing in all sectors tagged same as line + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + // if already doing a lighting function, don't start a second + if (P_SectorActive(lighting_special,sec)) //jff 2/22/98 + continue; + + P_SpawnStrobeFlash (sec,SLOWDARK, 0); + } + return 1; +} + +// +// EV_TurnTagLightsOff() +// +// Turn line's tagged sector's lights to min adjacent neighbor level +// +// Passed the line that activated the lights being turned off +// Returns true +// +// jff 2/12/98 added int return value, fixed return +// +int EV_TurnTagLightsOff(line_t* line) +{ + int j; + + // search sectors for those with same tag as activating line + + // killough 10/98: replaced inefficient search with fast search + for (j = -1; (j = P_FindSectorFromLineTag(line,j)) >= 0;) + { + sector_t *sector = sectors + j, *tsec; + int i, min = sector->lightlevel; + // find min neighbor light level + for (i = 0;i < sector->linecount; i++) + if ((tsec = getNextSector(sector->lines[i], sector)) && + tsec->lightlevel < min) + min = tsec->lightlevel; + sector->lightlevel = min; + } + return 1; +} + +// +// EV_LightTurnOn() +// +// Turn sectors tagged to line lights on to specified or max neighbor level +// +// Passed the activating line, and a level to set the light to +// If level passed is 0, the maximum neighbor lighting is used +// Returns true +// +// jff 2/12/98 added int return value, fixed return +// +int EV_LightTurnOn(line_t *line, int bright) +{ + int i; + + // search all sectors for ones with same tag as activating line + + // killough 10/98: replace inefficient search with fast search + for (i = -1; (i = P_FindSectorFromLineTag(line,i)) >= 0;) + { + sector_t *temp, *sector = sectors+i; + int j, tbright = bright; //jff 5/17/98 search for maximum PER sector + + // bright = 0 means to search for highest light level surrounding sector + + if (!bright) + for (j = 0;j < sector->linecount; j++) + if ((temp = getNextSector(sector->lines[j],sector)) && + temp->lightlevel > tbright) + tbright = temp->lightlevel; + + sector->lightlevel = tbright; + + //jff 5/17/98 unless compatibility optioned + //then maximum near ANY tagged sector + if (comp[comp_model]) + bright = tbright; + } + return 1; +} + +/* killough 10/98: + * + * EV_LightTurnOnPartway() + * + * Turn sectors tagged to line lights on to specified or max neighbor level + * + * Passed the activating line, and a light level fraction between 0 and 1. + * Sets the light to min on 0, max on 1, and interpolates in-between. + * Used for doors with gradual lighting effects. + * + * Returns true + */ + +int EV_LightTurnOnPartway(line_t *line, fixed_t level) +{ + int i; + + if (level < 0) // clip at extremes + level = 0; + if (level > FRACUNIT) + level = FRACUNIT; + + // search all sectors for ones with same tag as activating line + for (i = -1; (i = P_FindSectorFromLineTag(line,i)) >= 0;) + { + sector_t *temp, *sector = sectors+i; + int j, bright = 0, min = sector->lightlevel; + + for (j = 0; j < sector->linecount; j++) + if ((temp = getNextSector(sector->lines[j],sector))) + { + if (temp->lightlevel > bright) + bright = temp->lightlevel; + if (temp->lightlevel < min) + min = temp->lightlevel; + } + + sector->lightlevel = // Set level in-between extremes + (level * bright + (FRACUNIT-level) * min) >> FRACBITS; + } + return 1; +} + diff --git a/src/p_map.c b/src/p_map.c new file mode 100644 index 0000000..a8c3a6d --- /dev/null +++ b/src/p_map.c @@ -0,0 +1,2335 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2004 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Movement, collision handling. + * Shooting and aiming. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "r_main.h" +#include "p_mobj.h" +#include "p_maputl.h" +#include "p_map.h" +#include "p_setup.h" +#include "p_spec.h" +#include "s_sound.h" +#include "sounds.h" +#include "p_inter.h" +#include "m_random.h" +#include "m_bbox.h" +#include "lprintf.h" + +static mobj_t *tmthing; +static fixed_t tmx; +static fixed_t tmy; +static int pe_x; // Pain Elemental position for Lost Soul checks // phares +static int pe_y; // Pain Elemental position for Lost Soul checks // phares +static int ls_x; // Lost Soul position for Lost Soul checks // phares +static int ls_y; // Lost Soul position for Lost Soul checks // phares + +// If "floatok" true, move would be ok +// if within "tmfloorz - tmceilingz". + +boolean floatok; + +/* killough 11/98: if "felldown" true, object was pushed down ledge */ +boolean felldown; + +// The tm* items are used to hold information globally, usually for +// line or object intersection checking + +fixed_t tmbbox[4]; // bounding box for line intersection checks +fixed_t tmfloorz; // floor you'd hit if free to fall +fixed_t tmceilingz; // ceiling of sector you're in +fixed_t tmdropoffz; // dropoff on other side of line you're crossing + +// keep track of the line that lowers the ceiling, +// so missiles don't explode against sky hack walls + +line_t *ceilingline; +line_t *blockline; /* killough 8/11/98: blocking linedef */ +line_t *floorline; /* killough 8/1/98: Highest touched floor */ +static int tmunstuck; /* killough 8/1/98: whether to allow unsticking */ + +// keep track of special lines as they are hit, +// but don't process them until the move is proven valid + +// 1/11/98 killough: removed limit on special lines crossed +line_t **spechit; // new code -- killough +static int spechit_max; // killough + +int numspechit; + +// Temporary holder for thing_sectorlist threads +msecnode_t* sector_list = NULL; // phares 3/16/98 + +// +// TELEPORT MOVE +// + +// +// PIT_StompThing +// + +static boolean telefrag; /* killough 8/9/98: whether to telefrag at exit */ + +boolean PIT_StompThing (mobj_t* thing) + { + fixed_t blockdist; + + // phares 9/10/98: moved this self-check to start of routine + + // don't clip against self + + if (thing == tmthing) + return true; + + if (!(thing->flags & MF_SHOOTABLE)) // Can't shoot it? Can't stomp it! + return true; + + blockdist = thing->radius + tmthing->radius; + + if (D_abs(thing->x - tmx) >= blockdist || D_abs(thing->y - tmy) >= blockdist) + return true; // didn't hit it + + // monsters don't stomp things except on boss level + if (!telefrag) // killough 8/9/98: make consistent across all levels + return false; + + P_DamageMobj (thing, tmthing, tmthing, 10000); // Stomp! + + return true; + } + + +/* + * killough 8/28/98: + * + * P_GetFriction() + * + * Returns the friction associated with a particular mobj. + */ + +int P_GetFriction(const mobj_t *mo, int *frictionfactor) +{ + int friction = ORIG_FRICTION; + int movefactor = ORIG_FRICTION_FACTOR; + const msecnode_t *m; + const sector_t *sec; + + /* Assign the friction value to objects on the floor, non-floating, + * and clipped. Normally the object's friction value is kept at + * ORIG_FRICTION and this thinker changes it for icy or muddy floors. + * + * When the object is straddling sectors with the same + * floorheight that have different frictions, use the lowest + * friction value (muddy has precedence over icy). + */ + + if (!(mo->flags & (MF_NOCLIP|MF_NOGRAVITY)) + && (mbf_features || (mo->player && !compatibility)) && + variable_friction) + for (m = mo->touching_sectorlist; m; m = m->m_tnext) + if ((sec = m->m_sector)->special & FRICTION_MASK && + (sec->friction < friction || friction == ORIG_FRICTION) && + (mo->z <= sec->floorheight || + (sec->heightsec != -1 && + mo->z <= sectors[sec->heightsec].floorheight && + mbf_features))) + friction = sec->friction, movefactor = sec->movefactor; + + if (frictionfactor) + *frictionfactor = movefactor; + + return friction; +} + +/* phares 3/19/98 + * P_GetMoveFactor() returns the value by which the x,y + * movements are multiplied to add to player movement. + * + * killough 8/28/98: rewritten + */ + +int P_GetMoveFactor(const mobj_t *mo, int *frictionp) +{ + int movefactor, friction; + + //e6y + if (!mbf_features) + { + int momentum; + + movefactor = ORIG_FRICTION_FACTOR; + + if (!compatibility && variable_friction && + !(mo->flags & (MF_NOGRAVITY | MF_NOCLIP))) + { + friction = mo->friction; + if (friction == ORIG_FRICTION) // normal floor + ; + else if (friction > ORIG_FRICTION) // ice + { + movefactor = mo->movefactor; + ((mobj_t*)mo)->movefactor = ORIG_FRICTION_FACTOR; // reset + } + else // sludge + { + + // phares 3/11/98: you start off slowly, then increase as + // you get better footing + + momentum = (P_AproxDistance(mo->momx,mo->momy)); + movefactor = mo->movefactor; + if (momentum > MORE_FRICTION_MOMENTUM<<2) + movefactor <<= 3; + + else if (momentum > MORE_FRICTION_MOMENTUM<<1) + movefactor <<= 2; + + else if (momentum > MORE_FRICTION_MOMENTUM) + movefactor <<= 1; + + ((mobj_t*)mo)->movefactor = ORIG_FRICTION_FACTOR; // reset + } + } // ^ + + return(movefactor); // | + } + + // If the floor is icy or muddy, it's harder to get moving. This is where + // the different friction factors are applied to 'trying to move'. In + // p_mobj.c, the friction factors are applied as you coast and slow down. + + if ((friction = P_GetFriction(mo, &movefactor)) < ORIG_FRICTION) + { + // phares 3/11/98: you start off slowly, then increase as + // you get better footing + + int momentum = P_AproxDistance(mo->momx,mo->momy); + + if (momentum > MORE_FRICTION_MOMENTUM<<2) + movefactor <<= 3; + else if (momentum > MORE_FRICTION_MOMENTUM<<1) + movefactor <<= 2; + else if (momentum > MORE_FRICTION_MOMENTUM) + movefactor <<= 1; + } + + if (frictionp) + *frictionp = friction; + + return movefactor; +} + +// +// P_TeleportMove +// + +boolean P_TeleportMove (mobj_t* thing,fixed_t x,fixed_t y, boolean boss) + { + int xl; + int xh; + int yl; + int yh; + int bx; + int by; + + subsector_t* newsubsec; + + /* killough 8/9/98: make telefragging more consistent, preserve compatibility */ + telefrag = thing->player || + (!comp[comp_telefrag] ? boss : (gamemap==30)); + + // kill anything occupying the position + + tmthing = thing; + + tmx = x; + tmy = y; + + tmbbox[BOXTOP] = y + tmthing->radius; + tmbbox[BOXBOTTOM] = y - tmthing->radius; + tmbbox[BOXRIGHT] = x + tmthing->radius; + tmbbox[BOXLEFT] = x - tmthing->radius; + + newsubsec = R_PointInSubsector (x,y); + ceilingline = NULL; + + // The base floor/ceiling is from the subsector + // that contains the point. + // Any contacted lines the step closer together + // will adjust them. + + tmfloorz = tmdropoffz = newsubsec->sector->floorheight; + tmceilingz = newsubsec->sector->ceilingheight; + + validcount++; + numspechit = 0; + + // stomp on any things contacted + + xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; + + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + if (!P_BlockThingsIterator(bx,by,PIT_StompThing)) + return false; + + // the move is ok, + // so unlink from the old position & link into the new position + + P_UnsetThingPosition (thing); + + thing->floorz = tmfloorz; + thing->ceilingz = tmceilingz; + thing->dropoffz = tmdropoffz; // killough 11/98 + + thing->x = x; + thing->y = y; + + P_SetThingPosition (thing); + + thing->PrevX = x; + thing->PrevY = y; + thing->PrevZ = thing->floorz; + + return true; + } + + +// +// MOVEMENT ITERATOR FUNCTIONS +// + +// e6y: Spechits overrun emulation code +static void SpechitOverrun(line_t *ld); + +// // phares +// PIT_CrossLine // | +// Checks to see if a PE->LS trajectory line crosses a blocking // V +// line. Returns false if it does. +// +// tmbbox holds the bounding box of the trajectory. If that box +// does not touch the bounding box of the line in question, +// then the trajectory is not blocked. If the PE is on one side +// of the line and the LS is on the other side, then the +// trajectory is blocked. +// +// Currently this assumes an infinite line, which is not quite +// correct. A more correct solution would be to check for an +// intersection of the trajectory and the line, but that takes +// longer and probably really isn't worth the effort. +// + +static // killough 3/26/98: make static +boolean PIT_CrossLine (line_t* ld) + { + if (!(ld->flags & ML_TWOSIDED) || + (ld->flags & (ML_BLOCKING|ML_BLOCKMONSTERS))) + if (!(tmbbox[BOXLEFT] > ld->bbox[BOXRIGHT] || + tmbbox[BOXRIGHT] < ld->bbox[BOXLEFT] || + tmbbox[BOXTOP] < ld->bbox[BOXBOTTOM] || + tmbbox[BOXBOTTOM] > ld->bbox[BOXTOP])) + if (P_PointOnLineSide(pe_x,pe_y,ld) != P_PointOnLineSide(ls_x,ls_y,ld)) + return(false); // line blocks trajectory // ^ + return(true); // line doesn't block trajectory // | + } // phares + + +/* killough 8/1/98: used to test intersection between thing and line + * assuming NO movement occurs -- used to avoid sticky situations. + */ + +static int untouched(line_t *ld) +{ + fixed_t x, y, tmbbox[4]; + return + (tmbbox[BOXRIGHT] = (x=tmthing->x)+tmthing->radius) <= ld->bbox[BOXLEFT] || + (tmbbox[BOXLEFT] = x-tmthing->radius) >= ld->bbox[BOXRIGHT] || + (tmbbox[BOXTOP] = (y=tmthing->y)+tmthing->radius) <= ld->bbox[BOXBOTTOM] || + (tmbbox[BOXBOTTOM] = y-tmthing->radius) >= ld->bbox[BOXTOP] || + P_BoxOnLineSide(tmbbox, ld) != -1; +} + +// +// PIT_CheckLine +// Adjusts tmfloorz and tmceilingz as lines are contacted +// + +static // killough 3/26/98: make static +boolean PIT_CheckLine (line_t* ld) +{ + if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] + || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] + || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] + || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP] ) + return true; // didn't hit it + + if (P_BoxOnLineSide(tmbbox, ld) != -1) + return true; // didn't hit it + + // A line has been hit + + // The moving thing's destination position will cross the given line. + // If this should not be allowed, return false. + // If the line is special, keep track of it + // to process later if the move is proven ok. + // NOTE: specials are NOT sorted by order, + // so two special lines that are only 8 pixels apart + // could be crossed in either order. + + // killough 7/24/98: allow player to move out of 1s wall, to prevent sticking + if (!ld->backsector) // one sided line + { + blockline = ld; + return tmunstuck && !untouched(ld) && + FixedMul(tmx-tmthing->x,ld->dy) > FixedMul(tmy-tmthing->y,ld->dx); + } + + // killough 8/10/98: allow bouncing objects to pass through as missiles + if (!(tmthing->flags & (MF_MISSILE | MF_BOUNCES))) + { + if (ld->flags & ML_BLOCKING) // explicitly blocking everything + return tmunstuck && !untouched(ld); // killough 8/1/98: allow escape + + // killough 8/9/98: monster-blockers don't affect friends + if (!(tmthing->flags & MF_FRIEND || tmthing->player) + && ld->flags & ML_BLOCKMONSTERS) + return false; // block monsters only + } + + // set openrange, opentop, openbottom + // these define a 'window' from one sector to another across this line + + P_LineOpening (ld); + + // adjust floor & ceiling heights + + if (opentop < tmceilingz) + { + tmceilingz = opentop; + ceilingline = ld; + blockline = ld; + } + + if (openbottom > tmfloorz) + { + tmfloorz = openbottom; + floorline = ld; // killough 8/1/98: remember floor linedef + blockline = ld; + } + + if (lowfloor < tmdropoffz) + tmdropoffz = lowfloor; + + // if contacted a special line, add it to the list + + if (ld->special) + { + // 1/11/98 killough: remove limit on lines hit, by array doubling + if (numspechit >= spechit_max) { + spechit_max = spechit_max ? spechit_max*2 : 8; + spechit = realloc(spechit,sizeof *spechit*spechit_max); // killough + } + spechit[numspechit++] = ld; + // e6y: Spechits overrun emulation code + if (numspechit >= 8 && demo_compatibility) + SpechitOverrun(ld); + } + + return true; +} + +// +// PIT_CheckThing +// + +static boolean PIT_CheckThing(mobj_t *thing) // killough 3/26/98: make static +{ + fixed_t blockdist; + int damage; + + // killough 11/98: add touchy things + if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE|MF_TOUCHY))) + return true; + + blockdist = thing->radius + tmthing->radius; + + if (D_abs(thing->x - tmx) >= blockdist || D_abs(thing->y - tmy) >= blockdist) + return true; // didn't hit it + + // killough 11/98: + // + // This test has less information content (it's almost always false), so it + // should not be moved up to first, as it adds more overhead than it removes. + + // don't clip against self + + if (thing == tmthing) + return true; + + /* killough 11/98: + * + * TOUCHY flag, for mines or other objects which die on contact with solids. + * If a solid object of a different type comes in contact with a touchy + * thing, and the touchy thing is not the sole one moving relative to fixed + * surroundings such as walls, then the touchy thing dies immediately. + */ + + if (thing->flags & MF_TOUCHY && // touchy object + tmthing->flags & MF_SOLID && // solid object touches it + thing->health > 0 && // touchy object is alive + (thing->intflags & MIF_ARMED || // Thing is an armed mine + sentient(thing)) && // ... or a sentient thing + (thing->type != tmthing->type || // only different species + thing->type == MT_PLAYER) && // ... or different players + thing->z + thing->height >= tmthing->z && // touches vertically + tmthing->z + tmthing->height >= thing->z && + (thing->type ^ MT_PAIN) | // PEs and lost souls + (tmthing->type ^ MT_SKULL) && // are considered same + (thing->type ^ MT_SKULL) | // (but Barons & Knights + (tmthing->type ^ MT_PAIN)) // are intentionally not) + { + P_DamageMobj(thing, NULL, NULL, thing->health); // kill object + return true; + } + + // check for skulls slamming into things + + if (tmthing->flags & MF_SKULLFLY) + { + // A flying skull is smacking something. + // Determine damage amount, and the skull comes to a dead stop. + + int damage = ((P_Random(pr_skullfly)%8)+1)*tmthing->info->damage; + + P_DamageMobj (thing, tmthing, tmthing, damage); + + tmthing->flags &= ~MF_SKULLFLY; + tmthing->momx = tmthing->momy = tmthing->momz = 0; + + P_SetMobjState (tmthing, tmthing->info->spawnstate); + + return false; // stop moving + } + + // missiles can hit other things + // killough 8/10/98: bouncing non-solid things can hit other things too + + if (tmthing->flags & MF_MISSILE || (tmthing->flags & MF_BOUNCES && + !(tmthing->flags & MF_SOLID))) + { + // see if it went over / under + + if (tmthing->z > thing->z + thing->height) + return true; // overhead + + if (tmthing->z+tmthing->height < thing->z) + return true; // underneath + + if (tmthing->target && (tmthing->target->type == thing->type || + (tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER)|| + (tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT))) + { + if (thing == tmthing->target) + return true; // Don't hit same species as originator. + else + // e6y: Dehacked support - monsters infight + if (thing->type != MT_PLAYER && !monsters_infight) // Explode, but do no damage. + return false; // Let players missile other players. + } + + // killough 8/10/98: if moving thing is not a missile, no damage + // is inflicted, and momentum is reduced if object hit is solid. + + if (!(tmthing->flags & MF_MISSILE)) { + if (!(thing->flags & MF_SOLID)) { + return true; + } else { + tmthing->momx = -tmthing->momx; + tmthing->momy = -tmthing->momy; + if (!(tmthing->flags & MF_NOGRAVITY)) + { + tmthing->momx >>= 2; + tmthing->momy >>= 2; + } + return false; + } + } + + if (!(thing->flags & MF_SHOOTABLE)) + return !(thing->flags & MF_SOLID); // didn't do any damage + + // damage / explode + + damage = ((P_Random(pr_damage)%8)+1)*tmthing->info->damage; + P_DamageMobj (thing, tmthing, tmthing->target, damage); + + // don't traverse any more + return false; + } + + // check for special pickup + + if (thing->flags & MF_SPECIAL) + { + uint_64_t solid = thing->flags & MF_SOLID; + if (tmthing->flags & MF_PICKUP) + P_TouchSpecialThing(thing, tmthing); // can remove thing + return !solid; + } + + // killough 3/16/98: Allow non-solid moving objects to move through solid + // ones, by allowing the moving thing (tmthing) to move if it's non-solid, + // despite another solid thing being in the way. + // killough 4/11/98: Treat no-clipping things as not blocking + // ...but not in demo_compatibility mode + + return !(thing->flags & MF_SOLID) + || (!demo_compatibility + && (thing->flags & MF_NOCLIP || !(tmthing->flags & MF_SOLID))); + + // return !(thing->flags & MF_SOLID); // old code -- killough +} + +// This routine checks for Lost Souls trying to be spawned // phares +// across 1-sided lines, impassible lines, or "monsters can't // | +// cross" lines. Draw an imaginary line between the PE // V +// and the new Lost Soul spawn spot. If that line crosses +// a 'blocking' line, then disallow the spawn. Only search +// lines in the blocks of the blockmap where the bounding box +// of the trajectory line resides. Then check bounding box +// of the trajectory vs. the bounding box of each blocking +// line to see if the trajectory and the blocking line cross. +// Then check the PE and LS to see if they're on different +// sides of the blocking line. If so, return true, otherwise +// false. + +boolean Check_Sides(mobj_t* actor, int x, int y) + { + int bx,by,xl,xh,yl,yh; + + pe_x = actor->x; + pe_y = actor->y; + ls_x = x; + ls_y = y; + + // Here is the bounding box of the trajectory + + tmbbox[BOXLEFT] = pe_x < x ? pe_x : x; + tmbbox[BOXRIGHT] = pe_x > x ? pe_x : x; + tmbbox[BOXTOP] = pe_y > y ? pe_y : y; + tmbbox[BOXBOTTOM] = pe_y < y ? pe_y : y; + + // Determine which blocks to look in for blocking lines + + xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + + // xl->xh, yl->yh determine the mapblock set to search + + validcount++; // prevents checking same line twice + for (bx = xl ; bx <= xh ; bx++) + for (by = yl ; by <= yh ; by++) + if (!P_BlockLinesIterator(bx,by,PIT_CrossLine)) + return true; // ^ + return(false); // | + } // phares + +// +// MOVEMENT CLIPPING +// + +// +// P_CheckPosition +// This is purely informative, nothing is modified +// (except things picked up). +// +// in: +// a mobj_t (can be valid or invalid) +// a position to be checked +// (doesn't need to be related to the mobj_t->x,y) +// +// during: +// special things are touched if MF_PICKUP +// early out on solid lines? +// +// out: +// newsubsec +// floorz +// ceilingz +// tmdropoffz +// the lowest point contacted +// (monsters won't move to a dropoff) +// speciallines[] +// numspeciallines +// + +boolean P_CheckPosition (mobj_t* thing,fixed_t x,fixed_t y) + { + int xl; + int xh; + int yl; + int yh; + int bx; + int by; + subsector_t* newsubsec; + + tmthing = thing; + + tmx = x; + tmy = y; + + tmbbox[BOXTOP] = y + tmthing->radius; + tmbbox[BOXBOTTOM] = y - tmthing->radius; + tmbbox[BOXRIGHT] = x + tmthing->radius; + tmbbox[BOXLEFT] = x - tmthing->radius; + + newsubsec = R_PointInSubsector (x,y); + floorline = blockline = ceilingline = NULL; // killough 8/1/98 + + // Whether object can get out of a sticky situation: + tmunstuck = thing->player && /* only players */ + thing->player->mo == thing && /* not voodoo dolls */ + mbf_features; /* not under old demos */ + + // The base floor / ceiling is from the subsector + // that contains the point. + // Any contacted lines the step closer together + // will adjust them. + + tmfloorz = tmdropoffz = newsubsec->sector->floorheight; + tmceilingz = newsubsec->sector->ceilingheight; + validcount++; + numspechit = 0; + + if ( tmthing->flags & MF_NOCLIP ) + return true; + + // Check things first, possibly picking things up. + // The bounding box is extended by MAXRADIUS + // because mobj_ts are grouped into mapblocks + // based on their origin point, and can overlap + // into adjacent blocks by up to MAXRADIUS units. + + xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; + + + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + if (!P_BlockThingsIterator(bx,by,PIT_CheckThing)) + return false; + + // check lines + + xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + if (!P_BlockLinesIterator (bx,by,PIT_CheckLine)) + return false; // doesn't fit + + return true; + } + + +// +// P_TryMove +// Attempt to move to a new position, +// crossing special lines unless MF_TELEPORT is set. +// +boolean P_TryMove(mobj_t* thing,fixed_t x,fixed_t y, + boolean dropoff) // killough 3/15/98: allow dropoff as option + { + fixed_t oldx; + fixed_t oldy; + + felldown = floatok = false; // killough 11/98 + + if (!P_CheckPosition (thing, x, y)) + return false; // solid wall or thing + + if ( !(thing->flags & MF_NOCLIP) ) + { + // killough 7/26/98: reformatted slightly + // killough 8/1/98: Possibly allow escape if otherwise stuck + + if (tmceilingz - tmfloorz < thing->height || // doesn't fit + // mobj must lower to fit + (floatok = true, !(thing->flags & MF_TELEPORT) && + tmceilingz - thing->z < thing->height) || + // too big a step up + (!(thing->flags & MF_TELEPORT) && + tmfloorz - thing->z > 24*FRACUNIT)) + return tmunstuck + && !(ceilingline && untouched(ceilingline)) + && !( floorline && untouched( floorline)); + + /* killough 3/15/98: Allow certain objects to drop off + * killough 7/24/98, 8/1/98: + * Prevent monsters from getting stuck hanging off ledges + * killough 10/98: Allow dropoffs in controlled circumstances + * killough 11/98: Improve symmetry of clipping on stairs + */ + + if (!(thing->flags & (MF_DROPOFF|MF_FLOAT))) { + if (comp[comp_dropoff]) + { + if ((compatibility || !dropoff + // fix demosync bug in mbf compatibility mode + || (mbf_features && compatibility_level <= prboom_2_compatibility)) + && (tmfloorz - tmdropoffz > 24*FRACUNIT)) + return false; // don't stand over a dropoff + } + else + if (!dropoff || (dropoff==2 && // large jump down (e.g. dogs) + (tmfloorz-tmdropoffz > 128*FRACUNIT || + !thing->target || thing->target->z >tmdropoffz))) + { + if (!monkeys || !mbf_features ? + tmfloorz - tmdropoffz > 24*FRACUNIT : + thing->floorz - tmfloorz > 24*FRACUNIT || + thing->dropoffz - tmdropoffz > 24*FRACUNIT) + return false; + } + else { /* dropoff allowed -- check for whether it fell more than 24 */ + felldown = !(thing->flags & MF_NOGRAVITY) && + thing->z - tmfloorz > 24*FRACUNIT; + } + } + + if (thing->flags & MF_BOUNCES && // killough 8/13/98 + !(thing->flags & (MF_MISSILE|MF_NOGRAVITY)) && + !sentient(thing) && tmfloorz - thing->z > 16*FRACUNIT) + return false; // too big a step up for bouncers under gravity + + // killough 11/98: prevent falling objects from going up too many steps + if (thing->intflags & MIF_FALLING && tmfloorz - thing->z > + FixedMul(thing->momx,thing->momx)+FixedMul(thing->momy,thing->momy)) + return false; + } + + // the move is ok, + // so unlink from the old position and link into the new position + + P_UnsetThingPosition (thing); + + oldx = thing->x; + oldy = thing->y; + thing->floorz = tmfloorz; + thing->ceilingz = tmceilingz; + thing->dropoffz = tmdropoffz; // killough 11/98: keep track of dropoffs + thing->x = x; + thing->y = y; + + P_SetThingPosition (thing); + + // if any special lines were hit, do the effect + + if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) ) + while (numspechit--) + if (spechit[numspechit]->special) // see if the line was crossed + { + int oldside; + if ((oldside = P_PointOnLineSide(oldx, oldy, spechit[numspechit])) != + P_PointOnLineSide(thing->x, thing->y, spechit[numspechit])) + P_CrossSpecialLine(spechit[numspechit], oldside, thing); + } + + return true; + } + +/* + * killough 9/12/98: + * + * Apply "torque" to objects hanging off of ledges, so that they + * fall off. It's not really torque, since Doom has no concept of + * rotation, but it's a convincing effect which avoids anomalies + * such as lifeless objects hanging more than halfway off of ledges, + * and allows objects to roll off of the edges of moving lifts, or + * to slide up and then back down stairs, or to fall into a ditch. + * If more than one linedef is contacted, the effects are cumulative, + * so balancing is possible. + */ + +static boolean PIT_ApplyTorque(line_t *ld) +{ + if (ld->backsector && // If thing touches two-sided pivot linedef + tmbbox[BOXRIGHT] > ld->bbox[BOXLEFT] && + tmbbox[BOXLEFT] < ld->bbox[BOXRIGHT] && + tmbbox[BOXTOP] > ld->bbox[BOXBOTTOM] && + tmbbox[BOXBOTTOM] < ld->bbox[BOXTOP] && + P_BoxOnLineSide(tmbbox, ld) == -1) + { + mobj_t *mo = tmthing; + + fixed_t dist = // lever arm + + (ld->dx >> FRACBITS) * (mo->y >> FRACBITS) + - (ld->dy >> FRACBITS) * (mo->x >> FRACBITS) + - (ld->dx >> FRACBITS) * (ld->v1->y >> FRACBITS) + + (ld->dy >> FRACBITS) * (ld->v1->x >> FRACBITS); + + if (dist < 0 ? // dropoff direction + ld->frontsector->floorheight < mo->z && + ld->backsector->floorheight >= mo->z : + ld->backsector->floorheight < mo->z && + ld->frontsector->floorheight >= mo->z) + { + /* At this point, we know that the object straddles a two-sided + * linedef, and that the object's center of mass is above-ground. + */ + + fixed_t x = D_abs(ld->dx), y = D_abs(ld->dy); + + if (y > x) + { + fixed_t t = x; + x = y; + y = t; + } + + y = finesine[(tantoangle[FixedDiv(y,x)>>DBITS] + + ANG90) >> ANGLETOFINESHIFT]; + + /* Momentum is proportional to distance between the + * object's center of mass and the pivot linedef. + * + * It is scaled by 2^(OVERDRIVE - gear). When gear is + * increased, the momentum gradually decreases to 0 for + * the same amount of pseudotorque, so that oscillations + * are prevented, yet it has a chance to reach equilibrium. + */ + dist = FixedDiv(FixedMul(dist, (mo->gear < OVERDRIVE) ? + y << -(mo->gear - OVERDRIVE) : + y >> +(mo->gear - OVERDRIVE)), x); + + /* Apply momentum away from the pivot linedef. */ + + x = FixedMul(ld->dy, dist); + y = FixedMul(ld->dx, dist); + + /* Avoid moving too fast all of a sudden (step into "overdrive") */ + + dist = FixedMul(x,x) + FixedMul(y,y); + + while (dist > FRACUNIT*4 && mo->gear < MAXGEAR) + ++mo->gear, x >>= 1, y >>= 1, dist >>= 1; + + mo->momx -= x; + mo->momy += y; + } + } + return true; +} + +/* + * killough 9/12/98 + * + * Applies "torque" to objects, based on all contacted linedefs + */ + +void P_ApplyTorque(mobj_t *mo) +{ + int xl = ((tmbbox[BOXLEFT] = + mo->x - mo->radius) - bmaporgx) >> MAPBLOCKSHIFT; + int xh = ((tmbbox[BOXRIGHT] = + mo->x + mo->radius) - bmaporgx) >> MAPBLOCKSHIFT; + int yl = ((tmbbox[BOXBOTTOM] = + mo->y - mo->radius) - bmaporgy) >> MAPBLOCKSHIFT; + int yh = ((tmbbox[BOXTOP] = + mo->y + mo->radius) - bmaporgy) >> MAPBLOCKSHIFT; + int bx,by,flags = mo->intflags; //Remember the current state, for gear-change + + tmthing = mo; + validcount++; /* prevents checking same line twice */ + + for (bx = xl ; bx <= xh ; bx++) + for (by = yl ; by <= yh ; by++) + P_BlockLinesIterator(bx, by, PIT_ApplyTorque); + + /* If any momentum, mark object as 'falling' using engine-internal flags */ + if (mo->momx | mo->momy) + mo->intflags |= MIF_FALLING; + else // Clear the engine-internal flag indicating falling object. + mo->intflags &= ~MIF_FALLING; + + /* If the object has been moving, step up the gear. + * This helps reach equilibrium and avoid oscillations. + * + * Doom has no concept of potential energy, much less + * of rotation, so we have to creatively simulate these + * systems somehow :) + */ + + if (!((mo->intflags | flags) & MIF_FALLING)) // If not falling for a while, + mo->gear = 0; // Reset it to full strength + else + if (mo->gear < MAXGEAR) // Else if not at max gear, + mo->gear++; // move up a gear +} + +// +// P_ThingHeightClip +// Takes a valid thing and adjusts the thing->floorz, +// thing->ceilingz, and possibly thing->z. +// This is called for all nearby monsters +// whenever a sector changes height. +// If the thing doesn't fit, +// the z will be set to the lowest value +// and false will be returned. +// + +boolean P_ThingHeightClip (mobj_t* thing) +{ + boolean onfloor; + + onfloor = (thing->z == thing->floorz); + + P_CheckPosition (thing, thing->x, thing->y); + + /* what about stranding a monster partially off an edge? + * killough 11/98: Answer: see below (upset balance if hanging off ledge) + */ + + thing->floorz = tmfloorz; + thing->ceilingz = tmceilingz; + thing->dropoffz = tmdropoffz; /* killough 11/98: remember dropoffs */ + + if (onfloor) + { + + // walking monsters rise and fall with the floor + + thing->z = thing->floorz; + + /* killough 11/98: Possibly upset balance of objects hanging off ledges */ + if (thing->intflags & MIF_FALLING && thing->gear >= MAXGEAR) + thing->gear = 0; + } + else + { + + // don't adjust a floating monster unless forced to + + if (thing->z+thing->height > thing->ceilingz) + thing->z = thing->ceilingz - thing->height; + } + + return thing->ceilingz - thing->floorz >= thing->height; +} + + +// +// SLIDE MOVE +// Allows the player to slide along any angled walls. +// + +/* killough 8/2/98: make variables static */ +static fixed_t bestslidefrac; +static line_t* bestslideline; +static mobj_t* slidemo; +static fixed_t tmxmove; +static fixed_t tmymove; + + +// +// P_HitSlideLine +// Adjusts the xmove / ymove +// so that the next move will slide along the wall. +// If the floor is icy, then you can bounce off a wall. // phares +// + +void P_HitSlideLine (line_t* ld) + { + int side; + angle_t lineangle; + angle_t moveangle; + angle_t deltaangle; + fixed_t movelen; + fixed_t newlen; + boolean icyfloor; // is floor icy? // phares + // | + // Under icy conditions, if the angle of approach to the wall // V + // is more than 45 degrees, then you'll bounce and lose half + // your momentum. If less than 45 degrees, you'll slide along + // the wall. 45 is arbitrary and is believable. + + // Check for the special cases of horz or vert walls. + + /* killough 10/98: only bounce if hit hard (prevents wobbling) + * cph - DEMOSYNC - should only affect players in Boom demos? */ + + //e6y + if (mbf_features) + { + icyfloor = + P_AproxDistance(tmxmove, tmymove) > 4*FRACUNIT && + variable_friction && // killough 8/28/98: calc friction on demand + slidemo->z <= slidemo->floorz && + P_GetFriction(slidemo, NULL) > ORIG_FRICTION; + } + else + { + extern boolean onground; + icyfloor = !compatibility && + variable_friction && + slidemo->player && + onground && + slidemo->friction > ORIG_FRICTION; + } + + if (ld->slopetype == ST_HORIZONTAL) + { + if (icyfloor && (D_abs(tmymove) > D_abs(tmxmove))) + { + tmxmove /= 2; // absorb half the momentum + tmymove = -tmymove/2; + S_StartSound(slidemo,sfx_oof); // oooff! + } + else + tmymove = 0; // no more movement in the Y direction + return; + } + + if (ld->slopetype == ST_VERTICAL) + { + if (icyfloor && (D_abs(tmxmove) > D_abs(tmymove))) + { + tmxmove = -tmxmove/2; // absorb half the momentum + tmymove /= 2; + S_StartSound(slidemo,sfx_oof); // oooff! // ^ + } // | + else // phares + tmxmove = 0; // no more movement in the X direction + return; + } + + // The wall is angled. Bounce if the angle of approach is // phares + // less than 45 degrees. // phares + + side = P_PointOnLineSide (slidemo->x, slidemo->y, ld); + + lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy); + if (side == 1) + lineangle += ANG180; + moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove); + + // killough 3/2/98: + // The moveangle+=10 breaks v1.9 demo compatibility in + // some demos, so it needs demo_compatibility switch. + + if (!demo_compatibility) + moveangle += 10; // prevents sudden path reversal due to // phares + // rounding error // | + deltaangle = moveangle-lineangle; // V + movelen = P_AproxDistance (tmxmove, tmymove); + if (icyfloor && (deltaangle > ANG45) && (deltaangle < ANG90+ANG45)) + { + moveangle = lineangle - deltaangle; + movelen /= 2; // absorb + S_StartSound(slidemo,sfx_oof); // oooff! + moveangle >>= ANGLETOFINESHIFT; + tmxmove = FixedMul (movelen, finecosine[moveangle]); + tmymove = FixedMul (movelen, finesine[moveangle]); + } // ^ + else // | + { // phares + if (deltaangle > ANG180) + deltaangle += ANG180; + + // I_Error ("SlideLine: ang>ANG180"); + + lineangle >>= ANGLETOFINESHIFT; + deltaangle >>= ANGLETOFINESHIFT; + newlen = FixedMul (movelen, finecosine[deltaangle]); + tmxmove = FixedMul (newlen, finecosine[lineangle]); + tmymove = FixedMul (newlen, finesine[lineangle]); + } // phares + } + + +// +// PTR_SlideTraverse +// + +boolean PTR_SlideTraverse (intercept_t* in) + { + line_t* li; + + if (!in->isaline) + I_Error ("PTR_SlideTraverse: not a line?"); + + li = in->d.line; + + if ( ! (li->flags & ML_TWOSIDED) ) + { + if (P_PointOnLineSide (slidemo->x, slidemo->y, li)) + return true; // don't hit the back side + goto isblocking; + } + + // set openrange, opentop, openbottom. + // These define a 'window' from one sector to another across a line + + P_LineOpening (li); + + if (openrange < slidemo->height) + goto isblocking; // doesn't fit + + if (opentop - slidemo->z < slidemo->height) + goto isblocking; // mobj is too high + + if (openbottom - slidemo->z > 24*FRACUNIT ) + goto isblocking; // too big a step up + + // this line doesn't block movement + + return true; + + // the line does block movement, + // see if it is closer than best so far + +isblocking: + + if (in->frac < bestslidefrac) + { + bestslidefrac = in->frac; + bestslideline = li; + } + + return false; // stop + } + + +// +// P_SlideMove +// The momx / momy move is bad, so try to slide +// along a wall. +// Find the first line hit, move flush to it, +// and slide along it +// +// This is a kludgy mess. +// +// killough 11/98: reformatted + +void P_SlideMove(mobj_t *mo) +{ + int hitcount = 3; + + slidemo = mo; // the object that's sliding + + do + { + fixed_t leadx, leady, trailx, traily; + + if (!--hitcount) + goto stairstep; // don't loop forever + + // trace along the three leading corners + + if (mo->momx > 0) + leadx = mo->x + mo->radius, trailx = mo->x - mo->radius; + else + leadx = mo->x - mo->radius, trailx = mo->x + mo->radius; + + if (mo->momy > 0) + leady = mo->y + mo->radius, traily = mo->y - mo->radius; + else + leady = mo->y - mo->radius, traily = mo->y + mo->radius; + + bestslidefrac = FRACUNIT+1; + + P_PathTraverse(leadx, leady, leadx+mo->momx, leady+mo->momy, + PT_ADDLINES, PTR_SlideTraverse); + P_PathTraverse(trailx, leady, trailx+mo->momx, leady+mo->momy, + PT_ADDLINES, PTR_SlideTraverse); + P_PathTraverse(leadx, traily, leadx+mo->momx, traily+mo->momy, + PT_ADDLINES, PTR_SlideTraverse); + + // move up to the wall + + if (bestslidefrac == FRACUNIT+1) + { + // the move must have hit the middle, so stairstep + + stairstep: + + /* killough 3/15/98: Allow objects to drop off ledges + * + * phares 5/4/98: kill momentum if you can't move at all + * This eliminates player bobbing if pressed against a wall + * while on ice. + * + * killough 10/98: keep buggy code around for old Boom demos + * + * cph 2000/09//23: buggy code was only in Boom v2.01 + */ + + if (!P_TryMove(mo, mo->x, mo->y + mo->momy, true)) + if (!P_TryMove(mo, mo->x + mo->momx, mo->y, true)) + if (compatibility_level == boom_201_compatibility) + mo->momx = mo->momy = 0; + + break; + } + + // fudge a bit to make sure it doesn't hit + + if ((bestslidefrac -= 0x800) > 0) + { + fixed_t newx = FixedMul(mo->momx, bestslidefrac); + fixed_t newy = FixedMul(mo->momy, bestslidefrac); + + // killough 3/15/98: Allow objects to drop off ledges + + if (!P_TryMove(mo, mo->x+newx, mo->y+newy, true)) + goto stairstep; + } + + // Now continue along the wall. + // First calculate remainder. + + bestslidefrac = FRACUNIT-(bestslidefrac+0x800); + + if (bestslidefrac > FRACUNIT) + bestslidefrac = FRACUNIT; + + if (bestslidefrac <= 0) + break; + + tmxmove = FixedMul(mo->momx, bestslidefrac); + tmymove = FixedMul(mo->momy, bestslidefrac); + + P_HitSlideLine(bestslideline); // clip the moves + + mo->momx = tmxmove; + mo->momy = tmymove; + + /* killough 10/98: affect the bobbing the same way (but not voodoo dolls) + * cph - DEMOSYNC? */ + if (mo->player && mo->player->mo == mo) + { + if (D_abs(mo->player->momx) > D_abs(tmxmove)) + mo->player->momx = tmxmove; + if (D_abs(mo->player->momy) > D_abs(tmymove)) + mo->player->momy = tmymove; + } + } // killough 3/15/98: Allow objects to drop off ledges: + while (!P_TryMove(mo, mo->x+tmxmove, mo->y+tmymove, true)); +} + +// +// P_LineAttack +// +mobj_t* linetarget; // who got hit (or NULL) +static mobj_t* shootthing; + +/* killough 8/2/98: for more intelligent autoaiming */ +static uint_64_t aim_flags_mask; + +// Height if not aiming up or down +fixed_t shootz; + +int la_damage; +fixed_t attackrange; + +static fixed_t aimslope; + +// slopes to top and bottom of target +// killough 4/20/98: make static instead of using ones in p_sight.c + +static fixed_t topslope; +static fixed_t bottomslope; + + +// +// PTR_AimTraverse +// Sets linetaget and aimslope when a target is aimed at. +// +boolean PTR_AimTraverse (intercept_t* in) + { + line_t* li; + mobj_t* th; + fixed_t slope; + fixed_t thingtopslope; + fixed_t thingbottomslope; + fixed_t dist; + + if (in->isaline) + { + li = in->d.line; + + if ( !(li->flags & ML_TWOSIDED) ) + return false; // stop + + // Crosses a two sided line. + // A two sided line will restrict + // the possible target ranges. + + P_LineOpening (li); + + if (openbottom >= opentop) + return false; // stop + + dist = FixedMul (attackrange, in->frac); + + if (li->frontsector->floorheight != li->backsector->floorheight) + { + slope = FixedDiv (openbottom - shootz , dist); + if (slope > bottomslope) + bottomslope = slope; + } + + if (li->frontsector->ceilingheight != li->backsector->ceilingheight) + { + slope = FixedDiv (opentop - shootz , dist); + if (slope < topslope) + topslope = slope; + } + + if (topslope <= bottomslope) + return false; // stop + + return true; // shot continues + } + + // shoot a thing + + th = in->d.thing; + if (th == shootthing) + return true; // can't shoot self + + if (!(th->flags&MF_SHOOTABLE)) + return true; // corpse or something + + /* killough 7/19/98, 8/2/98: + * friends don't aim at friends (except players), at least not first + */ + if (th->flags & shootthing->flags & aim_flags_mask && !th->player) + return true; + + // check angles to see if the thing can be aimed at + + dist = FixedMul (attackrange, in->frac); + thingtopslope = FixedDiv (th->z+th->height - shootz , dist); + + if (thingtopslope < bottomslope) + return true; // shot over the thing + + thingbottomslope = FixedDiv (th->z - shootz, dist); + + if (thingbottomslope > topslope) + return true; // shot under the thing + + // this thing can be hit! + + if (thingtopslope > topslope) + thingtopslope = topslope; + + if (thingbottomslope < bottomslope) + thingbottomslope = bottomslope; + + aimslope = (thingtopslope+thingbottomslope)/2; + linetarget = th; + + return false; // don't go any farther + } + + +// +// PTR_ShootTraverse +// +boolean PTR_ShootTraverse (intercept_t* in) + { + fixed_t x; + fixed_t y; + fixed_t z; + fixed_t frac; + + mobj_t* th; + + fixed_t slope; + fixed_t dist; + fixed_t thingtopslope; + fixed_t thingbottomslope; + + if (in->isaline) + { + line_t *li = in->d.line; + + if (li->special) + P_ShootSpecialLine (shootthing, li); + + if (li->flags & ML_TWOSIDED) + { // crosses a two sided (really 2s) line + P_LineOpening (li); + dist = FixedMul(attackrange, in->frac); + + // killough 11/98: simplify + + if ((li->frontsector->floorheight==li->backsector->floorheight || + (slope = FixedDiv(openbottom - shootz , dist)) <= aimslope) && + (li->frontsector->ceilingheight==li->backsector->ceilingheight || + (slope = FixedDiv (opentop - shootz , dist)) >= aimslope)) + return true; // shot continues + } + + // hit line + // position a bit closer + + frac = in->frac - FixedDiv (4*FRACUNIT,attackrange); + x = trace.x + FixedMul (trace.dx, frac); + y = trace.y + FixedMul (trace.dy, frac); + z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange)); + + if (li->frontsector->ceilingpic == skyflatnum) + { + // don't shoot the sky! + + if (z > li->frontsector->ceilingheight) + return false; + + // it's a sky hack wall + + if (li->backsector && li->backsector->ceilingpic == skyflatnum) + + // fix bullet-eaters -- killough: + // WARNING: Almost all demos will lose sync without this + // demo_compatibility flag check!!! killough 1/18/98 + if (demo_compatibility || li->backsector->ceilingheight < z) + return false; + } + + // Spawn bullet puffs. + + P_SpawnPuff (x,y,z); + + // don't go any farther + + return false; + } + + // shoot a thing + + th = in->d.thing; + if (th == shootthing) + return true; // can't shoot self + + if (!(th->flags&MF_SHOOTABLE)) + return true; // corpse or something + + // check angles to see if the thing can be aimed at + + dist = FixedMul (attackrange, in->frac); + thingtopslope = FixedDiv (th->z+th->height - shootz , dist); + + if (thingtopslope < aimslope) + return true; // shot over the thing + + thingbottomslope = FixedDiv (th->z - shootz, dist); + + if (thingbottomslope > aimslope) + return true; // shot under the thing + + // hit thing + // position a bit closer + + frac = in->frac - FixedDiv (10*FRACUNIT,attackrange); + + x = trace.x + FixedMul (trace.dx, frac); + y = trace.y + FixedMul (trace.dy, frac); + z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange)); + + // Spawn bullet puffs or blod spots, + // depending on target type. + if (in->d.thing->flags & MF_NOBLOOD) + P_SpawnPuff (x,y,z); + else + P_SpawnBlood (x,y,z, la_damage); + + if (la_damage) + P_DamageMobj (th, shootthing, shootthing, la_damage); + + // don't go any farther + return false; + } + + +// +// P_AimLineAttack +// +fixed_t P_AimLineAttack(mobj_t* t1,angle_t angle,fixed_t distance, uint_64_t mask) + { + fixed_t x2; + fixed_t y2; + + angle >>= ANGLETOFINESHIFT; + shootthing = t1; + + x2 = t1->x + (distance>>FRACBITS)*finecosine[angle]; + y2 = t1->y + (distance>>FRACBITS)*finesine[angle]; + shootz = t1->z + (t1->height>>1) + 8*FRACUNIT; + + // can't shoot outside view angles + + topslope = 100*FRACUNIT/160; + bottomslope = -100*FRACUNIT/160; + + attackrange = distance; + linetarget = NULL; + + /* killough 8/2/98: prevent friends from aiming at friends */ + aim_flags_mask = mask; + + P_PathTraverse(t1->x,t1->y,x2,y2,PT_ADDLINES|PT_ADDTHINGS,PTR_AimTraverse); + + if (linetarget) + return aimslope; + + return 0; + } + + +// +// P_LineAttack +// If damage == 0, it is just a test trace +// that will leave linetarget set. +// + +void P_LineAttack +(mobj_t* t1, + angle_t angle, + fixed_t distance, + fixed_t slope, + int damage) + { + fixed_t x2; + fixed_t y2; + + angle >>= ANGLETOFINESHIFT; + shootthing = t1; + la_damage = damage; + x2 = t1->x + (distance>>FRACBITS)*finecosine[angle]; + y2 = t1->y + (distance>>FRACBITS)*finesine[angle]; + shootz = t1->z + (t1->height>>1) + 8*FRACUNIT; + attackrange = distance; + aimslope = slope; + + P_PathTraverse(t1->x,t1->y,x2,y2,PT_ADDLINES|PT_ADDTHINGS,PTR_ShootTraverse); + } + + +// +// USE LINES +// + +mobj_t* usething; + +boolean PTR_UseTraverse (intercept_t* in) + { + int side; + + if (!in->d.line->special) + { + P_LineOpening (in->d.line); + if (openrange <= 0) + { + S_StartSound (usething, sfx_noway); + + // can't use through a wall + return false; + } + + // not a special line, but keep checking + + return true; + } + + side = 0; + if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1) + side = 1; + + // return false; // don't use back side + + P_UseSpecialLine (usething, in->d.line, side); + + //WAS can't use for than one special line in a row + //jff 3/21/98 NOW multiple use allowed with enabling line flag + + return (!demo_compatibility && (in->d.line->flags&ML_PASSUSE))? + true : false; +} + +// Returns false if a "oof" sound should be made because of a blocking +// linedef. Makes 2s middles which are impassable, as well as 2s uppers +// and lowers which block the player, cause the sound effect when the +// player tries to activate them. Specials are excluded, although it is +// assumed that all special linedefs within reach have been considered +// and rejected already (see P_UseLines). +// +// by Lee Killough +// + +boolean PTR_NoWayTraverse(intercept_t* in) + { + line_t *ld = in->d.line; + // This linedef + return ld->special || !( // Ignore specials + ld->flags & ML_BLOCKING || ( // Always blocking + P_LineOpening(ld), // Find openings + openrange <= 0 || // No opening + openbottom > usething->z+24*FRACUNIT || // Too high it blocks + opentop < usething->z+usething->height // Too low it blocks + ) + ); + } + +// +// P_UseLines +// Looks for special lines in front of the player to activate. +// +void P_UseLines (player_t* player) + { + int angle; + fixed_t x1; + fixed_t y1; + fixed_t x2; + fixed_t y2; + + usething = player->mo; + + angle = player->mo->angle >> ANGLETOFINESHIFT; + + x1 = player->mo->x; + y1 = player->mo->y; + x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle]; + y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle]; + + // old code: + // + // P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse ); + // + // This added test makes the "oof" sound work on 2s lines -- killough: + + if (P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse )) + if (!comp[comp_sound] && !P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_NoWayTraverse )) + S_StartSound (usething, sfx_noway); + } + + +// +// RADIUS ATTACK +// + +static mobj_t *bombsource, *bombspot; +static int bombdamage; + + +// +// PIT_RadiusAttack +// "bombsource" is the creature +// that caused the explosion at "bombspot". +// + +boolean PIT_RadiusAttack (mobj_t* thing) + { + fixed_t dx; + fixed_t dy; + fixed_t dist; + + /* killough 8/20/98: allow bouncers to take damage + * (missile bouncers are already excluded with MF_NOBLOCKMAP) + */ + + if (!(thing->flags & (MF_SHOOTABLE | MF_BOUNCES))) + return true; + + // Boss spider and cyborg + // take no damage from concussion. + + // killough 8/10/98: allow grenades to hurt anyone, unless + // fired by Cyberdemons, in which case it won't hurt Cybers. + + if (bombspot->flags & MF_BOUNCES ? + thing->type == MT_CYBORG && bombsource->type == MT_CYBORG : + thing->type == MT_CYBORG || thing->type == MT_SPIDER) + return true; + + dx = D_abs(thing->x - bombspot->x); + dy = D_abs(thing->y - bombspot->y); + + dist = dx>dy ? dx : dy; + dist = (dist - thing->radius) >> FRACBITS; + + if (dist < 0) + dist = 0; + + if (dist >= bombdamage) + return true; // out of range + + if ( P_CheckSight (thing, bombspot) ) + { + // must be in direct path + P_DamageMobj (thing, bombspot, bombsource, bombdamage - dist); + } + + return true; + } + + +// +// P_RadiusAttack +// Source is the creature that caused the explosion at spot. +// +void P_RadiusAttack(mobj_t* spot,mobj_t* source,int damage) + { + int x; + int y; + + int xl; + int xh; + int yl; + int yh; + + fixed_t dist; + + dist = (damage+MAXRADIUS)<y + dist - bmaporgy)>>MAPBLOCKSHIFT; + yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT; + xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT; + xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT; + bombspot = spot; + bombsource = source; + bombdamage = damage; + + for (y=yl ; y<=yh ; y++) + for (x=xl ; x<=xh ; x++) + P_BlockThingsIterator (x, y, PIT_RadiusAttack ); + } + + + +// +// SECTOR HEIGHT CHANGING +// After modifying a sectors floor or ceiling height, +// call this routine to adjust the positions +// of all things that touch the sector. +// +// If anything doesn't fit anymore, true will be returned. +// If crunch is true, they will take damage +// as they are being crushed. +// If Crunch is false, you should set the sector height back +// the way it was and call P_ChangeSector again +// to undo the changes. +// + +static boolean crushchange, nofit; + +// +// PIT_ChangeSector +// + +boolean PIT_ChangeSector (mobj_t* thing) + { + mobj_t* mo; + + if (P_ThingHeightClip (thing)) + return true; // keep checking + + // crunch bodies to giblets + + if (thing->health <= 0) + { + P_SetMobjState (thing, S_GIBS); + + thing->flags &= ~MF_SOLID; + thing->height = 0; + thing->radius = 0; + return true; // keep checking + } + + // crunch dropped items + + if (thing->flags & MF_DROPPED) + { + P_RemoveMobj (thing); + + // keep checking + return true; + } + + /* killough 11/98: kill touchy things immediately */ + if (thing->flags & MF_TOUCHY && + (thing->intflags & MIF_ARMED || sentient(thing))) + { + P_DamageMobj(thing, NULL, NULL, thing->health); // kill object + return true; // keep checking + } + + if (! (thing->flags & MF_SHOOTABLE) ) + { + // assume it is bloody gibs or something + return true; + } + + nofit = true; + + if (crushchange && !(leveltime&3)) { + int t; + P_DamageMobj(thing,NULL,NULL,10); + + // spray blood in a random direction + mo = P_SpawnMobj (thing->x, + thing->y, + thing->z + thing->height/2, MT_BLOOD); + + /* killough 8/10/98: remove dependence on order of evaluation */ + t = P_Random(pr_crush); + mo->momx = (t - P_Random (pr_crush))<<12; + t = P_Random(pr_crush); + mo->momy = (t - P_Random (pr_crush))<<12; + } + + // keep checking (crush other things) + return true; + } + + +// +// P_ChangeSector +// +boolean P_ChangeSector(sector_t* sector,boolean crunch) + { + int x; + int y; + + nofit = false; + crushchange = crunch; + + // ARRGGHHH!!!! + // This is horrendously slow!!! + // killough 3/14/98 + + // re-check heights for all things near the moving sector + + for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++) + for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++) + P_BlockThingsIterator (x, y, PIT_ChangeSector); + + return nofit; + } + +// +// P_CheckSector +// jff 3/19/98 added to just check monsters on the periphery +// of a moving sector instead of all in bounding box of the +// sector. Both more accurate and faster. +// + +boolean P_CheckSector(sector_t* sector,boolean crunch) + { + msecnode_t *n; + + if (comp[comp_floors]) /* use the old routine for old demos though */ + return P_ChangeSector(sector,crunch); + + nofit = false; + crushchange = crunch; + + // killough 4/4/98: scan list front-to-back until empty or exhausted, + // restarting from beginning after each thing is processed. Avoids + // crashes, and is sure to examine all things in the sector, and only + // the things which are in the sector, until a steady-state is reached. + // Things can arbitrarily be inserted and removed and it won't mess up. + // + // killough 4/7/98: simplified to avoid using complicated counter + + // Mark all things invalid + + for (n=sector->touching_thinglist; n; n=n->m_snext) + n->visited = false; + + do + for (n=sector->touching_thinglist; n; n=n->m_snext) // go through list + if (!n->visited) // unprocessed thing found + { + n->visited = true; // mark thing as processed + if (!(n->m_thing->flags & MF_NOBLOCKMAP)) //jff 4/7/98 don't do these + PIT_ChangeSector(n->m_thing); // process it + break; // exit and start over + } + while (n); // repeat from scratch until all things left are marked valid + + return nofit; + } + + +// CPhipps - +// Use block memory allocator here + +#include "z_bmalloc.h" + +IMPLEMENT_BLOCK_MEMORY_ALLOC_ZONE(secnodezone, sizeof(msecnode_t), PU_LEVEL, 32, "SecNodes"); + +inline static msecnode_t* P_GetSecnode(void) +{ + return (msecnode_t*)Z_BMalloc(&secnodezone); +} + +// P_PutSecnode() returns a node to the freelist. + +inline static void P_PutSecnode(msecnode_t* node) +{ + Z_BFree(&secnodezone, node); +} + +// phares 3/16/98 +// +// P_AddSecnode() searches the current list to see if this sector is +// already there. If not, it adds a sector node at the head of the list of +// sectors this object appears in. This is called when creating a list of +// nodes that will get linked in later. Returns a pointer to the new node. + +msecnode_t* P_AddSecnode(sector_t* s, mobj_t* thing, msecnode_t* nextnode) + { + msecnode_t* node; + + node = nextnode; + while (node) + { + if (node->m_sector == s) // Already have a node for this sector? + { + node->m_thing = thing; // Yes. Setting m_thing says 'keep it'. + return(nextnode); + } + node = node->m_tnext; + } + + // Couldn't find an existing node for this sector. Add one at the head + // of the list. + + node = P_GetSecnode(); + + // killough 4/4/98, 4/7/98: mark new nodes unvisited. + node->visited = 0; + + node->m_sector = s; // sector + node->m_thing = thing; // mobj + node->m_tprev = NULL; // prev node on Thing thread + node->m_tnext = nextnode; // next node on Thing thread + if (nextnode) + nextnode->m_tprev = node; // set back link on Thing + + // Add new node at head of sector thread starting at s->touching_thinglist + + node->m_sprev = NULL; // prev node on sector thread + node->m_snext = s->touching_thinglist; // next node on sector thread + if (s->touching_thinglist) + node->m_snext->m_sprev = node; + s->touching_thinglist = node; + return(node); + } + + +// P_DelSecnode() deletes a sector node from the list of +// sectors this object appears in. Returns a pointer to the next node +// on the linked list, or NULL. + +msecnode_t* P_DelSecnode(msecnode_t* node) + { + msecnode_t* tp; // prev node on thing thread + msecnode_t* tn; // next node on thing thread + msecnode_t* sp; // prev node on sector thread + msecnode_t* sn; // next node on sector thread + + if (node) + { + + // Unlink from the Thing thread. The Thing thread begins at + // sector_list and not from mobj_t->touching_sectorlist. + + tp = node->m_tprev; + tn = node->m_tnext; + if (tp) + tp->m_tnext = tn; + if (tn) + tn->m_tprev = tp; + + // Unlink from the sector thread. This thread begins at + // sector_t->touching_thinglist. + + sp = node->m_sprev; + sn = node->m_snext; + if (sp) + sp->m_snext = sn; + else + node->m_sector->touching_thinglist = sn; + if (sn) + sn->m_sprev = sp; + + // Return this node to the freelist + + P_PutSecnode(node); + return(tn); + } + return(NULL); + } // phares 3/13/98 + +// Delete an entire sector list + +void P_DelSeclist(msecnode_t* node) + + { + while (node) + node = P_DelSecnode(node); + } + + +// phares 3/14/98 +// +// PIT_GetSectors +// Locates all the sectors the object is in by looking at the lines that +// cross through it. You have already decided that the object is allowed +// at this location, so don't bother with checking impassable or +// blocking lines. + +boolean PIT_GetSectors(line_t* ld) + { + if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || + tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || + tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || + tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) + return true; + + if (P_BoxOnLineSide(tmbbox, ld) != -1) + return true; + + // This line crosses through the object. + + // Collect the sector(s) from the line and add to the + // sector_list you're examining. If the Thing ends up being + // allowed to move to this position, then the sector_list + // will be attached to the Thing's mobj_t at touching_sectorlist. + + sector_list = P_AddSecnode(ld->frontsector,tmthing,sector_list); + + /* Don't assume all lines are 2-sided, since some Things + * like MT_TFOG are allowed regardless of whether their radius takes + * them beyond an impassable linedef. + * + * killough 3/27/98, 4/4/98: + * Use sidedefs instead of 2s flag to determine two-sidedness. + * killough 8/1/98: avoid duplicate if same sector on both sides + * cph - DEMOSYNC? */ + + if (ld->backsector && ld->backsector != ld->frontsector) + sector_list = P_AddSecnode(ld->backsector, tmthing, sector_list); + + return true; + } + + +// phares 3/14/98 +// +// P_CreateSecNodeList alters/creates the sector_list that shows what sectors +// the object resides in. + +void P_CreateSecNodeList(mobj_t* thing,fixed_t x,fixed_t y) +{ + int xl; + int xh; + int yl; + int yh; + int bx; + int by; + msecnode_t* node; + mobj_t* saved_tmthing = tmthing; /* cph - see comment at func end */ + fixed_t saved_tmx = tmx, saved_tmy = tmy; /* ditto */ + + // First, clear out the existing m_thing fields. As each node is + // added or verified as needed, m_thing will be set properly. When + // finished, delete all nodes where m_thing is still NULL. These + // represent the sectors the Thing has vacated. + + node = sector_list; + while (node) + { + node->m_thing = NULL; + node = node->m_tnext; + } + + tmthing = thing; + + tmx = x; + tmy = y; + + tmbbox[BOXTOP] = y + tmthing->radius; + tmbbox[BOXBOTTOM] = y - tmthing->radius; + tmbbox[BOXRIGHT] = x + tmthing->radius; + tmbbox[BOXLEFT] = x - tmthing->radius; + + validcount++; // used to make sure we only process a line once + + xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + P_BlockLinesIterator(bx,by,PIT_GetSectors); + + // Add the sector of the (x,y) point to sector_list. + + sector_list = P_AddSecnode(thing->subsector->sector,thing,sector_list); + + // Now delete any nodes that won't be used. These are the ones where + // m_thing is still NULL. + + node = sector_list; + while (node) + { + if (node->m_thing == NULL) + { + if (node == sector_list) + sector_list = node->m_tnext; + node = P_DelSecnode(node); + } + else + node = node->m_tnext; + } + + /* cph - + * This is the strife we get into for using global variables. tmthing + * is being used by several different functions calling + * P_BlockThingIterator, including functions that can be called *from* + * P_BlockThingIterator. Using a global tmthing is not reentrant. + * OTOH for Boom/MBF demos we have to preserve the buggy behavior. + * Fun. We restore its previous value unless we're in a Boom/MBF demo. + */ + if ((compatibility_level < boom_compatibility_compatibility) || + (compatibility_level >= prboom_3_compatibility)) + tmthing = saved_tmthing; + /* And, duh, the same for tmx/y - cph 2002/09/22 + * And for tmbbox - cph 2003/08/10 */ + if ((compatibility_level < boom_compatibility_compatibility) /* || + (compatibility_level >= prboom_4_compatibility) */) { + tmx = saved_tmx, tmy = saved_tmy; + if (tmthing) { + tmbbox[BOXTOP] = tmy + tmthing->radius; + tmbbox[BOXBOTTOM] = tmy - tmthing->radius; + tmbbox[BOXRIGHT] = tmx + tmthing->radius; + tmbbox[BOXLEFT] = tmx - tmthing->radius; + } + } +} + +/* cphipps 2004/08/30 - + * Must clear tmthing at tic end, as it might contain a pointer to a removed thinker, or the level might have ended/been ended and we clear the objects it was pointing too. Hopefully we don't need to carry this between tics for sync. */ +void P_MapStart(void) { + if (tmthing) I_Error("P_MapStart: tmthing set!"); +} +void P_MapEnd(void) { + tmthing = NULL; +} + +// e6y +// Code to emulate the behavior of Vanilla Doom when encountering an overrun +// of the spechit array. +// No more desyncs on compet-n\hr.wad\hr18*.lmp, all strain.wad\map07 demos etc. +// http://www.doomworld.com/vb/showthread.php?s=&threadid=35214 +static void SpechitOverrun(line_t *ld) +{ + //int addr = 0x01C09C98 + (ld - lines) * 0x3E; + int addr = 0x00C09C98 + (ld - lines) * 0x3E; + + if (compatibility_level == dosdoom_compatibility || compatibility_level == tasdoom_compatibility) + { + // e6y + // There are no more desyncs in the following dosdoom demos: + // flsofdth.wad\fod3uv.lmp - http://www.doomworld.com/sda/flsofdth.htm + // hr.wad\hf181430.lmp - http://www.doomworld.com/tas/hf181430.zip + // hr.wad\hr181329.lmp - http://www.doomworld.com/tas/hr181329.zip + // icarus.wad\ic09uv.lmp - http://competn.doom2.net/pub/sda/i-o/icuvlmps.zip + + switch(numspechit) + { + case 8: break; /* strange cph's code */ + case 9: + tmfloorz = addr; + break; + case 10: + tmceilingz = addr; + break; + + default: + lprintf(LO_ERROR, "SpechitOverrun: Warning: unable to emulate" + " an overrun where numspechit=%i\n", + numspechit); + break; + } + } + else + { + switch(numspechit) + { + case 8: break; /* numspechit, not significant it seems - cph */ + case 9: + case 10: + case 11: + case 12: + tmbbox[numspechit-9] = addr; + break; + case 13: + nofit = addr; + break; + case 14: + crushchange = addr; + break; + default: + lprintf(LO_ERROR, "SpechitOverrun: Warning: unable to emulate" + " an overrun where numspechit=%i\n", + numspechit); + break; + } + } +} diff --git a/src/p_map.h b/src/p_map.h new file mode 100644 index 0000000..8da2f62 --- /dev/null +++ b/src/p_map.h @@ -0,0 +1,92 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Map functions + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_MAP__ +#define __P_MAP__ + +#include "r_defs.h" +#include "d_player.h" + +#define USERANGE (64*FRACUNIT) +#define MELEERANGE (64*FRACUNIT) +#define MISSILERANGE (32*64*FRACUNIT) + +// MAXRADIUS is for precalculated sector block boxes the spider demon +// is larger, but we do not have any moving sectors nearby +#define MAXRADIUS (32*FRACUNIT) + +// killough 3/15/98: add fourth argument to P_TryMove +boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean dropoff); + +// killough 8/9/98: extra argument for telefragging +boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y,boolean boss); +void P_SlideMove(mobj_t *mo); +boolean P_CheckSight(mobj_t *t1, mobj_t *t2); +void P_UseLines(player_t *player); + +// killough 8/2/98: add 'mask' argument to prevent friends autoaiming at others +fixed_t P_AimLineAttack(mobj_t *t1,angle_t angle,fixed_t distance, uint_64_t mask); + +void P_LineAttack(mobj_t *t1, angle_t angle, fixed_t distance, + fixed_t slope, int damage ); +void P_RadiusAttack(mobj_t *spot, mobj_t *source, int damage); +boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y); + +//jff 3/19/98 P_CheckSector(): new routine to replace P_ChangeSector() +boolean P_ChangeSector(sector_t* sector,boolean crunch); +boolean P_CheckSector(sector_t *sector, boolean crunch); +void P_DelSeclist(msecnode_t*); // phares 3/16/98 +void P_CreateSecNodeList(mobj_t*,fixed_t,fixed_t); // phares 3/14/98 +boolean Check_Sides(mobj_t *, int, int); // phares + +int P_GetMoveFactor(const mobj_t *mo, int *friction); // killough 8/28/98 +int P_GetFriction(const mobj_t *mo, int *factor); // killough 8/28/98 +void P_ApplyTorque(mobj_t *mo); // killough 9/12/98 + +/* cphipps 2004/08/30 */ +void P_MapStart(void); +void P_MapEnd(void); + +// If "floatok" true, move would be ok if within "tmfloorz - tmceilingz". +extern boolean floatok; +extern boolean felldown; // killough 11/98: indicates object pushed off ledge +extern fixed_t tmfloorz; +extern fixed_t tmceilingz; +extern line_t *ceilingline; +extern line_t *floorline; // killough 8/23/98 +extern mobj_t *linetarget; // who got hit (or NULL) +extern msecnode_t *sector_list; // phares 3/16/98 +extern fixed_t tmbbox[4]; // phares 3/20/98 +extern line_t *blockline; // killough 8/11/98 + +#endif // __P_MAP__ diff --git a/src/p_maputl.c b/src/p_maputl.c new file mode 100644 index 0000000..62ce91c --- /dev/null +++ b/src/p_maputl.c @@ -0,0 +1,683 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Movement/collision utility functions, + * as used by function in p_map.c. + * BLOCKMAP Iterator functions, + * and some PIT_* functions to use for iteration. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "m_bbox.h" +#include "r_main.h" +#include "p_maputl.h" +#include "p_map.h" +#include "p_setup.h" + +// +// P_AproxDistance +// Gives an estimation of distance (not exact) +// + +fixed_t CONSTFUNC P_AproxDistance(fixed_t dx, fixed_t dy) +{ + dx = D_abs(dx); + dy = D_abs(dy); + if (dx < dy) + return dx+dy-(dx>>1); + return dx+dy-(dy>>1); +} + +// +// P_PointOnLineSide +// Returns 0 or 1 +// +// killough 5/3/98: reformatted, cleaned up + +int PUREFUNC P_PointOnLineSide(fixed_t x, fixed_t y, const line_t *line) +{ + return + !line->dx ? x <= line->v1->x ? line->dy > 0 : line->dy < 0 : + !line->dy ? y <= line->v1->y ? line->dx < 0 : line->dx > 0 : + FixedMul(y-line->v1->y, line->dx>>FRACBITS) >= + FixedMul(line->dy>>FRACBITS, x-line->v1->x); +} + +// +// P_BoxOnLineSide +// Considers the line to be infinite +// Returns side 0 or 1, -1 if box crosses the line. +// +// killough 5/3/98: reformatted, cleaned up + +int PUREFUNC P_BoxOnLineSide(const fixed_t *tmbox, const line_t *ld) +{ + switch (ld->slopetype) + { + int p; + default: // shut up compiler warnings -- killough + case ST_HORIZONTAL: + return + (tmbox[BOXBOTTOM] > ld->v1->y) == (p = tmbox[BOXTOP] > ld->v1->y) ? + p ^ (ld->dx < 0) : -1; + case ST_VERTICAL: + return + (tmbox[BOXLEFT] < ld->v1->x) == (p = tmbox[BOXRIGHT] < ld->v1->x) ? + p ^ (ld->dy < 0) : -1; + case ST_POSITIVE: + return + P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld) == + (p = P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXTOP], ld)) ? p : -1; + case ST_NEGATIVE: + return + (P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld)) == + (p = P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXTOP], ld)) ? p : -1; + } +} + +// +// P_PointOnDivlineSide +// Returns 0 or 1. +// +// killough 5/3/98: reformatted, cleaned up + +static int PUREFUNC P_PointOnDivlineSide(fixed_t x, fixed_t y, const divline_t *line) +{ + return + !line->dx ? x <= line->x ? line->dy > 0 : line->dy < 0 : + !line->dy ? y <= line->y ? line->dx < 0 : line->dx > 0 : + (line->dy^line->dx^(x -= line->x)^(y -= line->y)) < 0 ? (line->dy^x) < 0 : + FixedMul(y>>8, line->dx>>8) >= FixedMul(line->dy>>8, x>>8); +} + +// +// P_MakeDivline +// + +static void P_MakeDivline(const line_t *li, divline_t *dl) +{ + dl->x = li->v1->x; + dl->y = li->v1->y; + dl->dx = li->dx; + dl->dy = li->dy; +} + +// +// P_InterceptVector +// Returns the fractional intercept point +// along the first divline. +// This is only called by the addthings +// and addlines traversers. +// + +/* cph - this is killough's 4/19/98 version of P_InterceptVector and + * P_InterceptVector2 (which were interchangeable). We still use this + * in compatibility mode. */ +fixed_t PUREFUNC P_InterceptVector2(const divline_t *v2, const divline_t *v1) +{ + fixed_t den; + return (den = FixedMul(v1->dy>>8, v2->dx) - FixedMul(v1->dx>>8, v2->dy)) ? + FixedDiv(FixedMul((v1->x - v2->x)>>8, v1->dy) + + FixedMul((v2->y - v1->y)>>8, v1->dx), den) : 0; +} + +fixed_t PUREFUNC P_InterceptVector(const divline_t *v2, const divline_t *v1) +{ + if (compatibility_level < prboom_4_compatibility) + return P_InterceptVector2(v2, v1); + else { + /* cph - This was introduced at prboom_4_compatibility - no precision/overflow problems */ + int_64_t den = (int_64_t)v1->dy * v2->dx - (int_64_t)v1->dx * v2->dy; + den >>= 16; + if (!den) + return 0; + return (fixed_t)(((int_64_t)(v1->x - v2->x) * v1->dy - (int_64_t)(v1->y - v2->y) * v1->dx) / den); + } +} + +// +// P_LineOpening +// Sets opentop and openbottom to the window +// through a two sided line. +// OPTIMIZE: keep this precalculated +// + +fixed_t opentop; +fixed_t openbottom; +fixed_t openrange; +fixed_t lowfloor; + +// moved front and back outside P-LineOpening and changed // phares 3/7/98 +// them to these so we can pick up the new friction value +// in PIT_CheckLine() +sector_t *openfrontsector; // made global // phares +sector_t *openbacksector; // made global + +void P_LineOpening(const line_t *linedef) +{ + if (linedef->sidenum[1] == NO_INDEX) // single sided line + { + openrange = 0; + return; + } + + openfrontsector = linedef->frontsector; + openbacksector = linedef->backsector; + + if (openfrontsector->ceilingheight < openbacksector->ceilingheight) + opentop = openfrontsector->ceilingheight; + else + opentop = openbacksector->ceilingheight; + + if (openfrontsector->floorheight > openbacksector->floorheight) + { + openbottom = openfrontsector->floorheight; + lowfloor = openbacksector->floorheight; + } + else + { + openbottom = openbacksector->floorheight; + lowfloor = openfrontsector->floorheight; + } + openrange = opentop - openbottom; +} + +// +// THING POSITION SETTING +// + +// +// P_UnsetThingPosition +// Unlinks a thing from block map and sectors. +// On each position change, BLOCKMAP and other +// lookups maintaining lists ot things inside +// these structures need to be updated. +// + +void P_UnsetThingPosition (mobj_t *thing) +{ + if (!(thing->flags & MF_NOSECTOR)) + { + /* invisible things don't need to be in sector list + * unlink from subsector + * + * killough 8/11/98: simpler scheme using pointers-to-pointers for prev + * pointers, allows head node pointers to be treated like everything else + */ + + mobj_t **sprev = thing->sprev; + mobj_t *snext = thing->snext; + if ((*sprev = snext)) // unlink from sector list + snext->sprev = sprev; + + // phares 3/14/98 + // + // Save the sector list pointed to by touching_sectorlist. + // In P_SetThingPosition, we'll keep any nodes that represent + // sectors the Thing still touches. We'll add new ones then, and + // delete any nodes for sectors the Thing has vacated. Then we'll + // put it back into touching_sectorlist. It's done this way to + // avoid a lot of deleting/creating for nodes, when most of the + // time you just get back what you deleted anyway. + // + // If this Thing is being removed entirely, then the calling + // routine will clear out the nodes in sector_list. + + sector_list = thing->touching_sectorlist; + thing->touching_sectorlist = NULL; //to be restored by P_SetThingPosition + } + + if (!(thing->flags & MF_NOBLOCKMAP)) + { + /* inert things don't need to be in blockmap + * + * killough 8/11/98: simpler scheme using pointers-to-pointers for prev + * pointers, allows head node pointers to be treated like everything else + * + * Also more robust, since it doesn't depend on current position for + * unlinking. Old method required computing head node based on position + * at time of unlinking, assuming it was the same position as during + * linking. + */ + + mobj_t *bnext, **bprev = thing->bprev; + if (bprev && (*bprev = bnext = thing->bnext)) // unlink from block map + bnext->bprev = bprev; + } +} + +// +// P_SetThingPosition +// Links a thing into both a block and a subsector +// based on it's x y. +// Sets thing->subsector properly +// +// killough 5/3/98: reformatted, cleaned up + +void P_SetThingPosition(mobj_t *thing) +{ // link into subsector + subsector_t *ss = thing->subsector = R_PointInSubsector(thing->x, thing->y); + if (!(thing->flags & MF_NOSECTOR)) + { + // invisible things don't go into the sector links + + // killough 8/11/98: simpler scheme using pointer-to-pointer prev + // pointers, allows head nodes to be treated like everything else + + mobj_t **link = &ss->sector->thinglist; + mobj_t *snext = *link; + if ((thing->snext = snext)) + snext->sprev = &thing->snext; + thing->sprev = link; + *link = thing; + + // phares 3/16/98 + // + // If sector_list isn't NULL, it has a collection of sector + // nodes that were just removed from this Thing. + + // Collect the sectors the object will live in by looking at + // the existing sector_list and adding new nodes and deleting + // obsolete ones. + + // When a node is deleted, its sector links (the links starting + // at sector_t->touching_thinglist) are broken. When a node is + // added, new sector links are created. + + P_CreateSecNodeList(thing,thing->x,thing->y); + thing->touching_sectorlist = sector_list; // Attach to Thing's mobj_t + sector_list = NULL; // clear for next time + } + + // link into blockmap + if (!(thing->flags & MF_NOBLOCKMAP)) + { + // inert things don't need to be in blockmap + int blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT; + int blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT; + if (blockx>=0 && blockx < bmapwidth && blocky>=0 && blocky < bmapheight) + { + // killough 8/11/98: simpler scheme using pointer-to-pointer prev + // pointers, allows head nodes to be treated like everything else + + mobj_t **link = &blocklinks[blocky*bmapwidth+blockx]; + mobj_t *bnext = *link; + if ((thing->bnext = bnext)) + bnext->bprev = &thing->bnext; + thing->bprev = link; + *link = thing; + } + else // thing is off the map + thing->bnext = NULL, thing->bprev = NULL; + } +} + +// +// BLOCK MAP ITERATORS +// For each line/thing in the given mapblock, +// call the passed PIT_* function. +// If the function returns false, +// exit with false without checking anything else. +// + +// +// P_BlockLinesIterator +// The validcount flags are used to avoid checking lines +// that are marked in multiple mapblocks, +// so increment validcount before the first call +// to P_BlockLinesIterator, then make one or more calls +// to it. +// +// killough 5/3/98: reformatted, cleaned up + +boolean P_BlockLinesIterator(int x, int y, boolean func(line_t*)) +{ + int offset; + const long *list; // killough 3/1/98: for removal of blockmap limit + + if (x<0 || y<0 || x>=bmapwidth || y>=bmapheight) + return true; + offset = y*bmapwidth+x; + offset = *(blockmap+offset); + list = blockmaplump+offset; // original was reading // phares + // delmiting 0 as linedef 0 // phares + + // killough 1/31/98: for compatibility we need to use the old method. + // Most demos go out of sync, and maybe other problems happen, if we + // don't consider linedef 0. For safety this should be qualified. + + if (!demo_compatibility) // killough 2/22/98: demo_compatibility check + list++; // skip 0 starting delimiter // phares + for ( ; *list != -1 ; list++) // phares + { + line_t *ld = &lines[*list]; + if (ld->validcount == validcount) + continue; // line has already been checked + ld->validcount = validcount; + if (!func(ld)) + return false; + } + return true; // everything was checked +} + +// +// P_BlockThingsIterator +// +// killough 5/3/98: reformatted, cleaned up + +boolean P_BlockThingsIterator(int x, int y, boolean func(mobj_t*)) +{ + mobj_t *mobj; + if (!(x<0 || y<0 || x>=bmapwidth || y>=bmapheight)) + for (mobj = blocklinks[y*bmapwidth+x]; mobj; mobj = mobj->bnext) + if (!func(mobj)) + return false; + return true; +} + +// +// INTERCEPT ROUTINES +// + +// 1/11/98 killough: Intercept limit removed +static intercept_t *intercepts, *intercept_p; + +// Check for limit and double size if necessary -- killough +static void check_intercept(void) +{ + static size_t num_intercepts; + size_t offset = intercept_p - intercepts; + if (offset >= num_intercepts) + { + num_intercepts = num_intercepts ? num_intercepts*2 : 128; + intercepts = realloc(intercepts, sizeof(*intercepts)*num_intercepts); + intercept_p = intercepts + offset; + } +} + +divline_t trace; + +// PIT_AddLineIntercepts. +// Looks for lines in the given block +// that intercept the given trace +// to add to the intercepts list. +// +// A line is crossed if its endpoints +// are on opposite sides of the trace. +// +// killough 5/3/98: reformatted, cleaned up + +boolean PIT_AddLineIntercepts(line_t *ld) +{ + int s1; + int s2; + fixed_t frac; + divline_t dl; + + // avoid precision problems with two routines + if (trace.dx > FRACUNIT*16 || trace.dy > FRACUNIT*16 || + trace.dx < -FRACUNIT*16 || trace.dy < -FRACUNIT*16) + { + s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace); + s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace); + } + else + { + s1 = P_PointOnLineSide (trace.x, trace.y, ld); + s2 = P_PointOnLineSide (trace.x+trace.dx, trace.y+trace.dy, ld); + } + + if (s1 == s2) + return true; // line isn't crossed + + // hit the line + P_MakeDivline(ld, &dl); + frac = P_InterceptVector(&trace, &dl); + + if (frac < 0) + return true; // behind source + + check_intercept(); // killough + + intercept_p->frac = frac; + intercept_p->isaline = true; + intercept_p->d.line = ld; + intercept_p++; + + return true; // continue +} + +// +// PIT_AddThingIntercepts +// +// killough 5/3/98: reformatted, cleaned up + +boolean PIT_AddThingIntercepts(mobj_t *thing) +{ + fixed_t x1, y1; + fixed_t x2, y2; + int s1, s2; + divline_t dl; + fixed_t frac; + + // check a corner to corner crossection for hit + if ((trace.dx ^ trace.dy) > 0) + { + x1 = thing->x - thing->radius; + y1 = thing->y + thing->radius; + x2 = thing->x + thing->radius; + y2 = thing->y - thing->radius; + } + else + { + x1 = thing->x - thing->radius; + y1 = thing->y - thing->radius; + x2 = thing->x + thing->radius; + y2 = thing->y + thing->radius; + } + + s1 = P_PointOnDivlineSide (x1, y1, &trace); + s2 = P_PointOnDivlineSide (x2, y2, &trace); + + if (s1 == s2) + return true; // line isn't crossed + + dl.x = x1; + dl.y = y1; + dl.dx = x2-x1; + dl.dy = y2-y1; + + frac = P_InterceptVector (&trace, &dl); + + if (frac < 0) + return true; // behind source + + check_intercept(); // killough + + intercept_p->frac = frac; + intercept_p->isaline = false; + intercept_p->d.thing = thing; + intercept_p++; + + return true; // keep going +} + +// +// P_TraverseIntercepts +// Returns true if the traverser function returns true +// for all lines. +// +// killough 5/3/98: reformatted, cleaned up + +boolean P_TraverseIntercepts(traverser_t func, fixed_t maxfrac) +{ + intercept_t *in = NULL; + int count = intercept_p - intercepts; + while (count--) + { + fixed_t dist = INT_MAX; + intercept_t *scan; + for (scan = intercepts; scan < intercept_p; scan++) + if (scan->frac < dist) + dist = (in=scan)->frac; + if (dist > maxfrac) + return true; // checked everything in range + if (!func(in)) + return false; // don't bother going farther + in->frac = INT_MAX; + } + return true; // everything was traversed +} + +// +// P_PathTraverse +// Traces a line from x1,y1 to x2,y2, +// calling the traverser function for each. +// Returns true if the traverser function returns true +// for all lines. +// +// killough 5/3/98: reformatted, cleaned up + +boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, + int flags, boolean trav(intercept_t *)) +{ + fixed_t xt1, yt1; + fixed_t xt2, yt2; + fixed_t xstep, ystep; + fixed_t partial; + fixed_t xintercept, yintercept; + int mapx, mapy; + int mapxstep, mapystep; + int count; + + validcount++; + intercept_p = intercepts; + + if (!((x1-bmaporgx)&(MAPBLOCKSIZE-1))) + x1 += FRACUNIT; // don't side exactly on a line + + if (!((y1-bmaporgy)&(MAPBLOCKSIZE-1))) + y1 += FRACUNIT; // don't side exactly on a line + + trace.x = x1; + trace.y = y1; + trace.dx = x2 - x1; + trace.dy = y2 - y1; + + x1 -= bmaporgx; + y1 -= bmaporgy; + xt1 = x1>>MAPBLOCKSHIFT; + yt1 = y1>>MAPBLOCKSHIFT; + + x2 -= bmaporgx; + y2 -= bmaporgy; + xt2 = x2>>MAPBLOCKSHIFT; + yt2 = y2>>MAPBLOCKSHIFT; + + if (xt2 > xt1) + { + mapxstep = 1; + partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1)); + ystep = FixedDiv (y2-y1,D_abs(x2-x1)); + } + else + if (xt2 < xt1) + { + mapxstep = -1; + partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1); + ystep = FixedDiv (y2-y1,D_abs(x2-x1)); + } + else + { + mapxstep = 0; + partial = FRACUNIT; + ystep = 256*FRACUNIT; + } + + yintercept = (y1>>MAPBTOFRAC) + FixedMul(partial, ystep); + + if (yt2 > yt1) + { + mapystep = 1; + partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1)); + xstep = FixedDiv (x2-x1,D_abs(y2-y1)); + } + else + if (yt2 < yt1) + { + mapystep = -1; + partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1); + xstep = FixedDiv (x2-x1,D_abs(y2-y1)); + } + else + { + mapystep = 0; + partial = FRACUNIT; + xstep = 256*FRACUNIT; + } + + xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep); + + // Step through map blocks. + // Count is present to prevent a round off error + // from skipping the break. + + mapx = xt1; + mapy = yt1; + + for (count = 0; count < 64; count++) + { + if (flags & PT_ADDLINES) + if (!P_BlockLinesIterator(mapx, mapy,PIT_AddLineIntercepts)) + return false; // early out + + if (flags & PT_ADDTHINGS) + if (!P_BlockThingsIterator(mapx, mapy,PIT_AddThingIntercepts)) + return false; // early out + + if (mapx == xt2 && mapy == yt2) + break; + + if ((yintercept >> FRACBITS) == mapy) + { + yintercept += ystep; + mapx += mapxstep; + } + else + if ((xintercept >> FRACBITS) == mapx) + { + xintercept += xstep; + mapy += mapystep; + } + } + + // go through the sorted list + return P_TraverseIntercepts(trav, FRACUNIT); +} diff --git a/src/p_maputl.h b/src/p_maputl.h new file mode 100644 index 0000000..8a70ba0 --- /dev/null +++ b/src/p_maputl.h @@ -0,0 +1,89 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Map utility functions + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_MAPUTL__ +#define __P_MAPUTL__ + +#include "r_defs.h" + +/* mapblocks are used to check movement against lines and things */ +#define MAPBLOCKUNITS 128 +#define MAPBLOCKSIZE (MAPBLOCKUNITS*FRACUNIT) +#define MAPBLOCKSHIFT (FRACBITS+7) +#define MAPBMASK (MAPBLOCKSIZE-1) +#define MAPBTOFRAC (MAPBLOCKSHIFT-FRACBITS) + +#define PT_ADDLINES 1 +#define PT_ADDTHINGS 2 +#define PT_EARLYOUT 4 + +typedef struct { + fixed_t x; + fixed_t y; + fixed_t dx; + fixed_t dy; +} divline_t; + +typedef struct { + fixed_t frac; /* along trace line */ + boolean isaline; + union { + mobj_t* thing; + line_t* line; + } d; +} intercept_t; + +typedef boolean (*traverser_t)(intercept_t *in); + +fixed_t CONSTFUNC P_AproxDistance (fixed_t dx, fixed_t dy); +int PUREFUNC P_PointOnLineSide (fixed_t x, fixed_t y, const line_t *line); +int PUREFUNC P_BoxOnLineSide (const fixed_t *tmbox, const line_t *ld); +fixed_t PUREFUNC P_InterceptVector (const divline_t *v2, const divline_t *v1); +/* cph - old compatibility version below */ +fixed_t PUREFUNC P_InterceptVector2(const divline_t *v2, const divline_t *v1); + +void P_LineOpening (const line_t *linedef); +void P_UnsetThingPosition(mobj_t *thing); +void P_SetThingPosition(mobj_t *thing); +boolean P_BlockLinesIterator (int x, int y, boolean func(line_t *)); +boolean P_BlockThingsIterator(int x, int y, boolean func(mobj_t *)); +boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, + int flags, boolean trav(intercept_t *)); + +extern fixed_t opentop; +extern fixed_t openbottom; +extern fixed_t openrange; +extern fixed_t lowfloor; +extern divline_t trace; + +#endif /* __P_MAPUTL__ */ diff --git a/src/p_mobj.c b/src/p_mobj.c new file mode 100644 index 0000000..0f8c8e3 --- /dev/null +++ b/src/p_mobj.c @@ -0,0 +1,1526 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2004 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Moving object handling. Spawn functions. + * + *-----------------------------------------------------------------------------*/ + +#include "doomdef.h" +#include "doomstat.h" +#include "m_random.h" +#include "r_main.h" +#include "p_maputl.h" +#include "p_map.h" +#include "p_tick.h" +#include "sounds.h" +#include "st_stuff.h" +#include "hu_stuff.h" +#include "s_sound.h" +#include "info.h" +#include "g_game.h" +#include "p_inter.h" +#include "lprintf.h" +#include "r_demo.h" + +// +// P_SetMobjState +// Returns true if the mobj is still present. +// + +boolean P_SetMobjState(mobj_t* mobj,statenum_t state) + { + state_t* st; + + // killough 4/9/98: remember states seen, to detect cycles: + + static statenum_t seenstate_tab[NUMSTATES]; // fast transition table + statenum_t *seenstate = seenstate_tab; // pointer to table + static int recursion; // detects recursion + statenum_t i = state; // initial state + boolean ret = true; // return value + statenum_t tempstate[NUMSTATES]; // for use with recursion + + if (recursion++) // if recursion detected, + memset(seenstate=tempstate,0,sizeof tempstate); // clear state table + + do + { + if (state == S_NULL) + { + mobj->state = (state_t *) S_NULL; + P_RemoveMobj (mobj); + ret = false; + break; // killough 4/9/98 + } + + st = &states[state]; + mobj->state = st; + mobj->tics = st->tics; + mobj->sprite = st->sprite; + mobj->frame = st->frame; + + // Modified handling. + // Call action functions when the state is set + + if (st->action) + st->action(mobj); + + seenstate[state] = 1 + st->nextstate; // killough 4/9/98 + + state = st->nextstate; + } while (!mobj->tics && !seenstate[state]); // killough 4/9/98 + + if (ret && !mobj->tics) // killough 4/9/98: detect state cycles + doom_printf("Warning: State Cycle Detected"); + + if (!--recursion) + for (;(state=seenstate[i]);i=state-1) + seenstate[i] = 0; // killough 4/9/98: erase memory of states + + return ret; + } + + +// +// P_ExplodeMissile +// + +void P_ExplodeMissile (mobj_t* mo) + { + mo->momx = mo->momy = mo->momz = 0; + + P_SetMobjState (mo, mobjinfo[mo->type].deathstate); + + mo->tics -= P_Random(pr_explode)&3; + + if (mo->tics < 1) + mo->tics = 1; + + mo->flags &= ~MF_MISSILE; + + if (mo->info->deathsound) + S_StartSound (mo, mo->info->deathsound); + } + + +// +// P_XYMovement +// +// Attempts to move something if it has momentum. +// + +static void P_XYMovement (mobj_t* mo) + { + player_t *player; + fixed_t xmove, ymove; + + //e6y + fixed_t oldx,oldy; // phares 9/10/98: reducing bobbing/momentum on ice + +#if 0 + fixed_t ptryx; + fixed_t ptryy; + fixed_t xmove; + fixed_t ymove; + fixed_t oldx,oldy; // phares 9/10/98: reducing bobbing/momentum on ice + // when up against walls +#endif + if (!(mo->momx | mo->momy)) // Any momentum? + { + if (mo->flags & MF_SKULLFLY) + { + + // the skull slammed into something + + mo->flags &= ~MF_SKULLFLY; + mo->momz = 0; + + P_SetMobjState (mo, mo->info->spawnstate); + } + return; + } + + player = mo->player; + + if (mo->momx > MAXMOVE) + mo->momx = MAXMOVE; + else if (mo->momx < -MAXMOVE) + mo->momx = -MAXMOVE; + + if (mo->momy > MAXMOVE) + mo->momy = MAXMOVE; + else if (mo->momy < -MAXMOVE) + mo->momy = -MAXMOVE; + + xmove = mo->momx; + ymove = mo->momy; + + oldx = mo->x; // phares 9/10/98: new code to reduce bobbing/momentum + oldy = mo->y; // when on ice & up against wall. These will be compared + // to your x,y values later to see if you were able to move + + do + { + fixed_t ptryx, ptryy; + // killough 8/9/98: fix bug in original Doom source: + // Large negative displacements were never considered. + // This explains the tendency for Mancubus fireballs + // to pass through walls. + // CPhipps - compatibility optioned + + if (xmove > MAXMOVE/2 || ymove > MAXMOVE/2 || + (!comp[comp_moveblock] + && (xmove < -MAXMOVE/2 || ymove < -MAXMOVE/2))) + { + ptryx = mo->x + xmove/2; + ptryy = mo->y + ymove/2; + xmove >>= 1; + ymove >>= 1; + } + else + { + ptryx = mo->x + xmove; + ptryy = mo->y + ymove; + xmove = ymove = 0; + } + + // killough 3/15/98: Allow objects to drop off + + if (!P_TryMove (mo, ptryx, ptryy, true)) + { + // blocked move + + // killough 8/11/98: bouncing off walls + // killough 10/98: + // Add ability for objects other than players to bounce on ice + + if (!(mo->flags & MF_MISSILE) && + mbf_features && + (mo->flags & MF_BOUNCES || + (!player && blockline && + variable_friction && mo->z <= mo->floorz && + P_GetFriction(mo, NULL) > ORIG_FRICTION))) + { + if (blockline) + { + fixed_t r = ((blockline->dx >> FRACBITS) * mo->momx + + (blockline->dy >> FRACBITS) * mo->momy) / + ((blockline->dx >> FRACBITS)*(blockline->dx >> FRACBITS)+ + (blockline->dy >> FRACBITS)*(blockline->dy >> FRACBITS)); + fixed_t x = FixedMul(r, blockline->dx); + fixed_t y = FixedMul(r, blockline->dy); + + // reflect momentum away from wall + + mo->momx = x*2 - mo->momx; + mo->momy = y*2 - mo->momy; + + // if under gravity, slow down in + // direction perpendicular to wall. + + if (!(mo->flags & MF_NOGRAVITY)) + { + mo->momx = (mo->momx + x)/2; + mo->momy = (mo->momy + y)/2; + } + } + else + mo->momx = mo->momy = 0; + } + else + if (player) // try to slide along it + P_SlideMove (mo); + else + if (mo->flags & MF_MISSILE) + { + // explode a missile + + if (ceilingline && + ceilingline->backsector && + ceilingline->backsector->ceilingpic == skyflatnum) + if (demo_compatibility || // killough + mo->z > ceilingline->backsector->ceilingheight) + { + // Hack to prevent missiles exploding + // against the sky. + // Does not handle sky floors. + + P_RemoveMobj (mo); + return; + } + P_ExplodeMissile (mo); + } + else // whatever else it is, it is now standing still in (x,y) + mo->momx = mo->momy = 0; + } + } while (xmove || ymove); + + // slow down + +#if 0 /* killough 10/98: this is unused code (except maybe in .deh files?) */ + if (player && player->cheats & CF_NOMOMENTUM) + { + // debug option for no sliding at all + mo->momx = mo->momy = 0; + player->momx = player->momy = 0; /* killough 10/98 */ + return; + } +#endif + + /* no friction for missiles or skulls ever, no friction when airborne */ + if (mo->flags & (MF_MISSILE | MF_SKULLFLY) || mo->z > mo->floorz) + return; + + /* killough 8/11/98: add bouncers + * killough 9/15/98: add objects falling off ledges + * killough 11/98: only include bouncers hanging off ledges + */ + if (((mo->flags & MF_BOUNCES && mo->z > mo->dropoffz) || + mo->flags & MF_CORPSE || mo->intflags & MIF_FALLING) && + (mo->momx > FRACUNIT/4 || mo->momx < -FRACUNIT/4 || + mo->momy > FRACUNIT/4 || mo->momy < -FRACUNIT/4) && + mo->floorz != mo->subsector->sector->floorheight) + return; // do not stop sliding if halfway off a step with some momentum + + // killough 11/98: + // Stop voodoo dolls that have come to rest, despite any + // moving corresponding player, except in old demos: + + if (mo->momx > -STOPSPEED && mo->momx < STOPSPEED && + mo->momy > -STOPSPEED && mo->momy < STOPSPEED && + (!player || !(player->cmd.forwardmove | player->cmd.sidemove) || + (player->mo != mo && compatibility_level >= lxdoom_1_compatibility))) + { + // if in a walking frame, stop moving + + // killough 10/98: + // Don't affect main player when voodoo dolls stop, except in old demos: + +// if ( player&&(unsigned)((player->mo->state - states)- S_PLAY_RUN1) < 4) +// P_SetMobjState (player->mo, S_PLAY); + if (player && (unsigned)(player->mo->state - states - S_PLAY_RUN1) < 4 + && (player->mo == mo || compatibility_level >= lxdoom_1_compatibility)) + P_SetMobjState(player->mo, S_PLAY); + + mo->momx = mo->momy = 0; + + /* killough 10/98: kill any bobbing momentum too (except in voodoo dolls) + * cph - DEMOSYNC - needs compatibility check? + */ + if (player && player->mo == mo) + player->momx = player->momy = 0; + } + else + { + /* phares 3/17/98 + * + * Friction will have been adjusted by friction thinkers for + * icy or muddy floors. Otherwise it was never touched and + * remained set at ORIG_FRICTION + * + * killough 8/28/98: removed inefficient thinker algorithm, + * instead using touching_sectorlist in P_GetFriction() to + * determine friction (and thus only when it is needed). + * + * killough 10/98: changed to work with new bobbing method. + * Reducing player momentum is no longer needed to reduce + * bobbing, so ice works much better now. + * + * cph - DEMOSYNC - need old code for Boom demos? + */ + + //e6y + if (compatibility_level <= boom_201_compatibility) + { + // phares 3/17/98 + // Friction will have been adjusted by friction thinkers for icy + // or muddy floors. Otherwise it was never touched and + // remained set at ORIG_FRICTION + mo->momx = FixedMul(mo->momx,mo->friction); + mo->momy = FixedMul(mo->momy,mo->friction); + mo->friction = ORIG_FRICTION; // reset to normal for next tic + } + else if (compatibility_level <= lxdoom_1_compatibility) + { + // phares 9/10/98: reduce bobbing/momentum when on ice & up against wall + + if ((oldx == mo->x) && (oldy == mo->y)) // Did you go anywhere? + { // No. Use original friction. This allows you to not bob so much + // if you're on ice, but keeps enough momentum around to break free + // when you're mildly stuck in a wall. + mo->momx = FixedMul(mo->momx,ORIG_FRICTION); + mo->momy = FixedMul(mo->momy,ORIG_FRICTION); + } + else + { // Yes. Use stored friction. + mo->momx = FixedMul(mo->momx,mo->friction); + mo->momy = FixedMul(mo->momy,mo->friction); + } + mo->friction = ORIG_FRICTION; // reset to normal for next tic + } + else + { + + fixed_t friction = P_GetFriction(mo, NULL); + + mo->momx = FixedMul(mo->momx, friction); + mo->momy = FixedMul(mo->momy, friction); + + /* killough 10/98: Always decrease player bobbing by ORIG_FRICTION. + * This prevents problems with bobbing on ice, where it was not being + * reduced fast enough, leading to all sorts of kludges being developed. + */ + + if (player && player->mo == mo) /* Not voodoo dolls */ + { + player->momx = FixedMul(player->momx, ORIG_FRICTION); + player->momy = FixedMul(player->momy, ORIG_FRICTION); + } + + } + + } + } + + +// +// P_ZMovement +// +// Attempt vertical movement. + +static void P_ZMovement (mobj_t* mo) +{ + /* killough 7/11/98: + * BFG fireballs bounced on floors and ceilings in Pre-Beta Doom + * killough 8/9/98: added support for non-missile objects bouncing + * (e.g. grenade, mine, pipebomb) + */ + + if (mo->flags & MF_BOUNCES && mo->momz) { + mo->z += mo->momz; + if (mo->z <= mo->floorz) { /* bounce off floors */ + mo->z = mo->floorz; + if (mo->momz < 0) { + mo->momz = -mo->momz; + if (!(mo->flags & MF_NOGRAVITY)) { /* bounce back with decay */ + mo->momz = mo->flags & MF_FLOAT ? // floaters fall slowly + mo->flags & MF_DROPOFF ? // DROPOFF indicates rate + FixedMul(mo->momz, (fixed_t)(FRACUNIT*.85)) : + FixedMul(mo->momz, (fixed_t)(FRACUNIT*.70)) : + FixedMul(mo->momz, (fixed_t)(FRACUNIT*.45)) ; + + /* Bring it to rest below a certain speed */ + if (D_abs(mo->momz) <= mo->info->mass*(GRAVITY*4/256)) + mo->momz = 0; + } + + /* killough 11/98: touchy objects explode on impact */ + if (mo->flags & MF_TOUCHY && mo->intflags & MIF_ARMED + && mo->health > 0) + P_DamageMobj(mo, NULL, NULL, mo->health); + else if (mo->flags & MF_FLOAT && sentient(mo)) + goto floater; + return; + } + } else if (mo->z >= mo->ceilingz - mo->height) { + /* bounce off ceilings */ + mo->z = mo->ceilingz - mo->height; + if (mo->momz > 0) { + if (mo->subsector->sector->ceilingpic != skyflatnum) + mo->momz = -mo->momz; /* always bounce off non-sky ceiling */ + else if (mo->flags & MF_MISSILE) + P_RemoveMobj(mo); /* missiles don't bounce off skies */ + else if (mo->flags & MF_NOGRAVITY) + mo->momz = -mo->momz; // bounce unless under gravity + + if (mo->flags & MF_FLOAT && sentient(mo)) + goto floater; + + return; + } + } else { + if (!(mo->flags & MF_NOGRAVITY)) /* free-fall under gravity */ + mo->momz -= mo->info->mass*(GRAVITY/256); + + if (mo->flags & MF_FLOAT && sentient(mo)) goto floater; + return; + } + + /* came to a stop */ + mo->momz = 0; + + if (mo->flags & MF_MISSILE) { + if (ceilingline && + ceilingline->backsector && + ceilingline->backsector->ceilingpic == skyflatnum && + mo->z > ceilingline->backsector->ceilingheight) + P_RemoveMobj(mo); /* don't explode on skies */ + else + P_ExplodeMissile(mo); + } + + if (mo->flags & MF_FLOAT && sentient(mo)) goto floater; + return; + } + + /* killough 8/9/98: end bouncing object code */ + + // check for smooth step up + + if (mo->player && + mo->player->mo == mo && // killough 5/12/98: exclude voodoo dolls + mo->z < mo->floorz) + { + mo->player->viewheight -= mo->floorz-mo->z; + mo->player->deltaviewheight = (VIEWHEIGHT - mo->player->viewheight)>>3; + } + + // adjust altitude + + mo->z += mo->momz; + +floater: + if ((mo->flags & MF_FLOAT) && mo->target) + + // float down towards target if too close + + if (!((mo->flags ^ MF_FLOAT) & (MF_FLOAT | MF_SKULLFLY | MF_INFLOAT)) && + mo->target) /* killough 11/98: simplify */ + { + fixed_t delta; + if (P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y) < + D_abs(delta = mo->target->z + (mo->height>>1) - mo->z)*3) + mo->z += delta < 0 ? -FLOATSPEED : FLOATSPEED; + } + + // clip movement + + if (mo->z <= mo->floorz) + { + // hit the floor + + /* Note (id): + * somebody left this after the setting momz to 0, + * kinda useless there. + * 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. + * cph - revised 2001/04/15 - + * This was a bug in the Doom/Doom 2 source; the following code + * is meant to make charging lost souls bounce off of floors, but it + * was incorrectly placed after momz was set to 0. + * However, this bug was fixed in Doom95, Final/Ultimate Doom, and + * the v1.10 source release (which is one reason why it failed to sync + * some Doom2 v1.9 demos) + * I've added a comp_soul compatibility option to make this behavior + * selectable for PrBoom v2.3+. For older demos, we do this here only + * if we're in a compatibility level above Doom 2 v1.9 (in which case we + * mimic the bug and do it further down instead) + */ + + if (mo->flags & MF_SKULLFLY && + (!comp[comp_soul] || + (compatibility_level > doom2_19_compatibility && + compatibility_level < prboom_4_compatibility) + )) + mo->momz = -mo->momz; // the skull slammed into something + + if (mo->momz < 0) + { + /* killough 11/98: touchy objects explode on impact */ + if (mo->flags & MF_TOUCHY && mo->intflags & MIF_ARMED && mo->health > 0) + P_DamageMobj(mo, NULL, NULL, mo->health); + else + if (mo->player && /* killough 5/12/98: exclude voodoo dolls */ + mo->player->mo == mo && mo->momz < -GRAVITY*8) + { + // Squat down. + // Decrease viewheight for a moment + // after hitting the ground (hard), + // and utter appropriate sound. + + mo->player->deltaviewheight = mo->momz>>3; + if (mo->health > 0) /* cph - prevent "oof" when dead */ + S_StartSound (mo, sfx_oof); + } + mo->momz = 0; + } + mo->z = mo->floorz; + + /* cph 2001/04/15 - + * This is the buggy lost-soul bouncing code referenced above. + * We've already set momz = 0 normally by this point, so it's useless. + * However we might still have upward momentum, in which case this will + * incorrectly reverse it, so we might still need this for demo sync + */ + if (mo->flags & MF_SKULLFLY && + compatibility_level <= doom2_19_compatibility) + mo->momz = -mo->momz; // the skull slammed into something + + if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) ) + { + P_ExplodeMissile (mo); + return; + } + } + else // still above the floor // phares + if (!(mo->flags & MF_NOGRAVITY)) + { + if (!mo->momz) + mo->momz = -GRAVITY; + mo->momz -= GRAVITY; + } + + if (mo->z + mo->height > mo->ceilingz) + { + /* cph 2001/04/15 - + * Lost souls were meant to bounce off of ceilings; + * new comp_soul compatibility option added + */ + if (!comp[comp_soul] && mo->flags & MF_SKULLFLY) + mo->momz = -mo->momz; // the skull slammed into something + + // hit the ceiling + + if (mo->momz > 0) + mo->momz = 0; + + mo->z = mo->ceilingz - mo->height; + + /* cph 2001/04/15 - + * We might have hit a ceiling but had downward momentum (e.g. ceiling is + * lowering on us), so for old demos we must still do the buggy + * momentum reversal here + */ + if (comp[comp_soul] && mo->flags & MF_SKULLFLY) + mo->momz = -mo->momz; // the skull slammed into something + + if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) ) + { + P_ExplodeMissile (mo); + return; + } + } + } + +// +// P_NightmareRespawn +// + +static void P_NightmareRespawn(mobj_t* mobj) + { + fixed_t x; + fixed_t y; + fixed_t z; + subsector_t* ss; + mobj_t* mo; + mapthing_t* mthing; + + x = mobj->spawnpoint.x << FRACBITS; + y = mobj->spawnpoint.y << FRACBITS; + + /* haleyjd: stupid nightmare respawning bug fix + * + * 08/09/00: compatibility added, time to ramble :) + * This fixes the notorious nightmare respawning bug that causes monsters + * that didn't spawn at level startup to respawn at the point (0,0) + * regardless of that point's nature. SMMU and Eternity need this for + * script-spawned things like Halif Swordsmythe, as well. + * + * cph - copied from eternity, except comp_respawnfix becomes comp_respawn + * and the logic is reversed (i.e. like the rest of comp_ it *disables* + * the fix) + */ + if(!comp[comp_respawn] && !x && !y) + { + // spawnpoint was zeroed out, so use point of death instead + x = mobj->x; + y = mobj->y; + } + + // something is occupying its position? + + if (!P_CheckPosition (mobj, x, y) ) + return; // no respwan + + // spawn a teleport fog at old spot + // because of removal of the body? + + mo = P_SpawnMobj (mobj->x, + mobj->y, + mobj->subsector->sector->floorheight, + MT_TFOG); + + // initiate teleport sound + + S_StartSound (mo, sfx_telept); + + // spawn a teleport fog at the new spot + + ss = R_PointInSubsector (x,y); + + mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_TFOG); + + S_StartSound (mo, sfx_telept); + + // spawn the new monster + + mthing = &mobj->spawnpoint; + if (mobj->info->flags & MF_SPAWNCEILING) + z = ONCEILINGZ; + else + z = ONFLOORZ; + + // inherit attributes from deceased one + + mo = P_SpawnMobj (x,y,z, mobj->type); + mo->spawnpoint = mobj->spawnpoint; + mo->angle = ANG45 * (mthing->angle/45); + + if (mthing->options & MTF_AMBUSH) + mo->flags |= MF_AMBUSH; + + /* killough 11/98: transfer friendliness from deceased */ + mo->flags = (mo->flags & ~MF_FRIEND) | (mobj->flags & MF_FRIEND); + + mo->reactiontime = 18; + + // remove the old monster, + + P_RemoveMobj (mobj); + } + + +// +// P_MobjThinker +// + +void P_MobjThinker (mobj_t* mobj) + { + // killough 11/98: + // removed old code which looked at target references + // (we use pointer reference counting now) + + mobj->PrevX = mobj->x; + mobj->PrevY = mobj->y; + mobj->PrevZ = mobj->z; + + // momentum movement + if (mobj->momx | mobj->momy || mobj->flags & MF_SKULLFLY) + { + P_XYMovement(mobj); + if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed + return; // killough - mobj was removed + } + + if (mobj->z != mobj->floorz || mobj->momz) + { + P_ZMovement(mobj); + if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed + return; // killough - mobj was removed + } + else + if (!(mobj->momx | mobj->momy) && !sentient(mobj)) + { // non-sentient objects at rest + mobj->intflags |= MIF_ARMED; // arm a mine which has come to rest + + // killough 9/12/98: objects fall off ledges if they are hanging off + // slightly push off of ledge if hanging more than halfway off + + if (mobj->z > mobj->dropoffz && // Only objects contacting dropoff + !(mobj->flags & MF_NOGRAVITY) && // Only objects which fall + !comp[comp_falloff]) // Not in old demos + P_ApplyTorque(mobj); // Apply torque + else + mobj->intflags &= ~MIF_FALLING, mobj->gear = 0; // Reset torque + } + + // cycle through states, + // calling action functions at transitions + + if (mobj->tics != -1) + { + mobj->tics--; + + // you can cycle through multiple states in a tic + + if (!mobj->tics) + if (!P_SetMobjState (mobj, mobj->state->nextstate) ) + return; // freed itself + } + else + { + + // check for nightmare respawn + + if (! (mobj->flags & MF_COUNTKILL) ) + return; + + if (!respawnmonsters) + return; + + mobj->movecount++; + + if (mobj->movecount < 12*35) + return; + + if (leveltime & 31) + return; + + if (P_Random (pr_respawn) > 4) + return; + + P_NightmareRespawn (mobj); + } + + } + + +// +// P_SpawnMobj +// +mobj_t* P_SpawnMobj(fixed_t x,fixed_t y,fixed_t z,mobjtype_t type) + { + mobj_t* mobj; + state_t* st; + mobjinfo_t* info; + + mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL); + memset (mobj, 0, sizeof (*mobj)); + info = &mobjinfo[type]; + mobj->type = type; + mobj->info = info; + mobj->x = x; + mobj->y = y; + mobj->radius = info->radius; + mobj->height = info->height; // phares + mobj->flags = info->flags; + + /* killough 8/23/98: no friends, bouncers, or touchy things in old demos */ + if (!mbf_features) + mobj->flags &= ~(MF_BOUNCES | MF_FRIEND | MF_TOUCHY); + else + if (type == MT_PLAYER) // Except in old demos, players + mobj->flags |= MF_FRIEND; // are always friends. + + mobj->health = info->spawnhealth; + + if (gameskill != sk_nightmare) + mobj->reactiontime = info->reactiontime; + + mobj->lastlook = P_Random (pr_lastlook) % MAXPLAYERS; + + // do not set the state with P_SetMobjState, + // because action routines can not be called yet + + st = &states[info->spawnstate]; + + mobj->state = st; + mobj->tics = st->tics; + mobj->sprite = st->sprite; + mobj->frame = st->frame; + mobj->touching_sectorlist = NULL; // NULL head of sector list // phares 3/13/98 + + // set subsector and/or block links + + P_SetThingPosition (mobj); + + mobj->dropoffz = /* killough 11/98: for tracking dropoffs */ + mobj->floorz = mobj->subsector->sector->floorheight; + mobj->ceilingz = mobj->subsector->sector->ceilingheight; + + mobj->z = z == ONFLOORZ ? mobj->floorz : z == ONCEILINGZ ? + mobj->ceilingz - mobj->height : z; + + mobj->PrevX = mobj->x; + mobj->PrevY = mobj->y; + mobj->PrevZ = mobj->z; + + mobj->thinker.function = P_MobjThinker; + + //e6y + mobj->friction = ORIG_FRICTION; // phares 3/17/98 + + mobj->target = mobj->tracer = mobj->lastenemy = NULL; + P_AddThinker (&mobj->thinker); + if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL))) + totallive++; + return mobj; + } + + +static mapthing_t itemrespawnque[ITEMQUESIZE]; +static int itemrespawntime[ITEMQUESIZE]; +int iquehead; +int iquetail; + + +// +// P_RemoveMobj +// + +void P_RemoveMobj (mobj_t* mobj) +{ + if ((mobj->flags & MF_SPECIAL) + && !(mobj->flags & MF_DROPPED) + && (mobj->type != MT_INV) + && (mobj->type != MT_INS)) + { + itemrespawnque[iquehead] = mobj->spawnpoint; + itemrespawntime[iquehead] = leveltime; + iquehead = (iquehead+1)&(ITEMQUESIZE-1); + + // lose one off the end? + + if (iquehead == iquetail) + iquetail = (iquetail+1)&(ITEMQUESIZE-1); + } + + // unlink from sector and block lists + + P_UnsetThingPosition (mobj); + + // Delete all nodes on the current sector_list phares 3/16/98 + + if (sector_list) + { + P_DelSeclist(sector_list); + sector_list = NULL; + } + + // stop any playing sound + + S_StopSound (mobj); + + // killough 11/98: + // + // Remove any references to other mobjs. + // + // Older demos might depend on the fields being left alone, however, + // if multiple thinkers reference each other indirectly before the + // end of the current tic. + // CPhipps - only leave dead references in old demos; I hope lxdoom_1 level + // demos are rare and don't rely on this. I hope. + + if ((compatibility_level >= lxdoom_1_compatibility) || + (!demorecording && !demoplayback)) { + P_SetTarget(&mobj->target, NULL); + P_SetTarget(&mobj->tracer, NULL); + P_SetTarget(&mobj->lastenemy, NULL); + } + // free block + + P_RemoveThinker (&mobj->thinker); +} + + +/* + * P_FindDoomedNum + * + * Finds a mobj type with a matching doomednum + * + * killough 8/24/98: rewrote to use hashing + */ + +static PUREFUNC int P_FindDoomedNum(unsigned type) +{ + static struct { int first, next; } *hash; + register int i; + + if (!hash) + { + hash = Z_Malloc(sizeof *hash * NUMMOBJTYPES, PU_CACHE, (void **) &hash); + for (i=0; ix << FRACBITS; + y = mthing->y << FRACBITS; + + // spawn a teleport fog at the new spot + + ss = R_PointInSubsector (x,y); + mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_IFOG); + S_StartSound (mo, sfx_itmbk); + + // find which type to spawn + + /* killough 8/23/98: use table for faster lookup */ + i = P_FindDoomedNum(mthing->type); + + // spawn it + + if (mobjinfo[i].flags & MF_SPAWNCEILING) + z = ONCEILINGZ; + else + z = ONFLOORZ; + + mo = P_SpawnMobj (x,y,z, i); + mo->spawnpoint = *mthing; + mo->angle = ANG45 * (mthing->angle/45); + + // pull it from the queue + + iquetail = (iquetail+1)&(ITEMQUESIZE-1); + } + +// +// P_SpawnPlayer +// Called when a player is spawned on the level. +// Most of the player structure stays unchanged +// between levels. +// + +extern byte playernumtotrans[MAXPLAYERS]; + +void P_SpawnPlayer (int n, const mapthing_t* mthing) + { + player_t* p; + fixed_t x; + fixed_t y; + fixed_t z; + mobj_t* mobj; + int i; + + // not playing? + + if (!playeringame[n]) + return; + + p = &players[n]; + + if (p->playerstate == PST_REBORN) + G_PlayerReborn (mthing->type-1); + + /* cph 2001/08/14 - use the options field of memorised player starts to + * indicate whether the start really exists in the level. + */ + if (!mthing->options) + I_Error("P_SpawnPlayer: attempt to spawn player at unavailable start point"); + + x = mthing->x << FRACBITS; + y = mthing->y << FRACBITS; + z = ONFLOORZ; + mobj = P_SpawnMobj (x,y,z, MT_PLAYER); + + // set color translations for player sprites + + mobj->flags |= playernumtotrans[n]<angle = ANG45 * (mthing->angle/45); + mobj->player = p; + mobj->health = p->health; + + p->mo = mobj; + p->playerstate = PST_LIVE; + p->refire = 0; + p->message = NULL; + p->damagecount = 0; + p->bonuscount = 0; + p->extralight = 0; + p->fixedcolormap = 0; + p->viewheight = VIEWHEIGHT; + + p->momx = p->momy = 0; // killough 10/98: initialize bobbing to 0. + + // setup gun psprite + + P_SetupPsprites (p); + + // give all cards in death match mode + + if (deathmatch) + for (i = 0 ; i < NUMCARDS ; i++) + p->cards[i] = true; + + if (mthing->type-1 == consoleplayer) + { + ST_Start(); // wake up the status bar + HU_Start(); // wake up the heads up text + } + R_SmoothPlaying_Reset(p); // e6y + } + +/* + * P_IsDoomnumAllowed() + * Based on code taken from P_LoadThings() in src/p_setup.c Return TRUE + * if the thing in question is expected to be available in the gamemode used. + */ + +boolean P_IsDoomnumAllowed(int doomnum) +{ + // Do not spawn cool, new monsters if !commercial + if (gamemode != commercial) + switch(doomnum) + { + case 64: // Archvile + case 65: // Former Human Commando + case 66: // Revenant + case 67: // Mancubus + case 68: // Arachnotron + case 69: // Hell Knight + case 71: // Pain Elemental + case 84: // Wolf SS + case 88: // Boss Brain + case 89: // Boss Shooter + return false; + } + + return true; +} + +// +// P_SpawnMapThing +// The fields of the mapthing should +// already be in host byte order. +// + +void P_SpawnMapThing (const mapthing_t* mthing) + { + int i; + //int bit; + mobj_t* mobj; + fixed_t x; + fixed_t y; + fixed_t z; + int options = mthing->options; /* cph 2001/07/07 - make writable copy */ + + // killough 2/26/98: Ignore type-0 things as NOPs + // phares 5/14/98: Ignore Player 5-8 starts (for now) + + switch(mthing->type) + { + case 0: + case DEN_PLAYER5: + case DEN_PLAYER6: + case DEN_PLAYER7: + case DEN_PLAYER8: + return; + } + + // killough 11/98: clear flags unused by Doom + // + // We clear the flags unused in Doom if we see flag mask 256 set, since + // it is reserved to be 0 under the new scheme. A 1 in this reserved bit + // indicates it's a Doom wad made by a Doom editor which puts 1's in + // bits that weren't used in Doom (such as HellMaker wads). So we should + // then simply ignore all upper bits. + + if (demo_compatibility || + (compatibility_level >= lxdoom_1_compatibility && + options & MTF_RESERVED)) { + if (!demo_compatibility) // cph - Add warning about bad thing flags + lprintf(LO_WARN, "P_SpawnMapThing: correcting bad flags (%u) (thing type %d)\n", + options, mthing->type); + options &= MTF_EASY|MTF_NORMAL|MTF_HARD|MTF_AMBUSH|MTF_NOTSINGLE; + } + + // count deathmatch start positions + + // doom2.exe has at most 10 deathmatch starts + if (mthing->type == 11) + { + if (!(!compatibility || deathmatch_p-deathmatchstarts < 10)) { + return; + } else { + // 1/11/98 killough -- new code removes limit on deathmatch starts: + + size_t offset = deathmatch_p - deathmatchstarts; + + if (offset >= num_deathmatchstarts) + { + num_deathmatchstarts = num_deathmatchstarts ? + num_deathmatchstarts*2 : 16; + deathmatchstarts = realloc(deathmatchstarts, + num_deathmatchstarts * + sizeof(*deathmatchstarts)); + deathmatch_p = deathmatchstarts + offset; + } + memcpy(deathmatch_p++, mthing, sizeof(*mthing)); + (deathmatch_p-1)->options = 1; + return; + } + } + + // check for players specially + + if (mthing->type <= 4 && mthing->type > 0) // killough 2/26/98 -- fix crashes + { +#ifdef DOGS + // killough 7/19/98: Marine's best friend :) + if (!netgame && mthing->type > 1 && mthing->type <= dogs+1 && + !players[mthing->type-1].secretcount) + { // use secretcount to avoid multiple dogs in case of multiple starts + players[mthing->type-1].secretcount = 1; + + // killough 10/98: force it to be a friend + options |= MTF_FRIEND; + if(HelperThing != -1) // haleyjd 9/22/99: deh substitution + { + int type = HelperThing - 1; + if(type >= 0 && type < NUMMOBJTYPES) + { + i = type; + } + else + { + doom_printf("Invalid value %i for helper, ignored.", HelperThing); + i = MT_DOGS; + } + } + else { + i = MT_DOGS; + } + goto spawnit; + } +#endif + + // save spots for respawning in coop games + playerstarts[mthing->type-1] = *mthing; + /* cph 2006/07/24 - use the otherwise-unused options field to flag that + * this start is present (so we know which elements of the array are filled + * in, in effect). Also note that the call below to P_SpawnPlayer must use + * the playerstarts version with this field set */ + playerstarts[mthing->type-1].options = 1; + + if (!deathmatch) + P_SpawnPlayer (mthing->type-1, &playerstarts[mthing->type-1]); + return; + } + + // check for apropriate skill level + + /* jff "not single" thing flag */ + if (!netgame && options & MTF_NOTSINGLE) + return; + + //jff 3/30/98 implement "not deathmatch" thing flag + + if (netgame && deathmatch && options & MTF_NOTDM) + return; + + //jff 3/30/98 implement "not cooperative" thing flag + + if (netgame && !deathmatch && options & MTF_NOTCOOP) + return; + + // killough 11/98: simplify + if (gameskill == sk_baby || gameskill == sk_easy ? + !(options & MTF_EASY) : + gameskill == sk_hard || gameskill == sk_nightmare ? + !(options & MTF_HARD) : !(options & MTF_NORMAL)) + return; + + // find which type to spawn + + // killough 8/23/98: use table for faster lookup + i = P_FindDoomedNum(mthing->type); + + // phares 5/16/98: + // Do not abort because of an unknown thing. Ignore it, but post a + // warning message for the player. + + if (i == NUMMOBJTYPES) + { + doom_printf("Unknown Thing type %i at (%i, %i)",mthing->type,mthing->x,mthing->y); + return; + } + + // don't spawn keycards and players in deathmatch + + if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH) + return; + + // don't spawn any monsters if -nomonsters + + if (nomonsters && (i == MT_SKULL || (mobjinfo[i].flags & MF_COUNTKILL))) + return; + + // spawn it +#ifdef DOGS +spawnit: +#endif + + x = mthing->x << FRACBITS; + y = mthing->y << FRACBITS; + + if (mobjinfo[i].flags & MF_SPAWNCEILING) + z = ONCEILINGZ; + else + z = ONFLOORZ; + + mobj = P_SpawnMobj (x,y,z, i); + mobj->spawnpoint = *mthing; + + if (mobj->tics > 0) + mobj->tics = 1 + (P_Random (pr_spawnthing) % mobj->tics); + + if (!(mobj->flags & MF_FRIEND) && + options & MTF_FRIEND && + mbf_features) + { + mobj->flags |= MF_FRIEND; // killough 10/98: + P_UpdateThinker(&mobj->thinker); // transfer friendliness flag + } + + /* killough 7/20/98: exclude friends */ + if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL))) + totalkills++; + + if (mobj->flags & MF_COUNTITEM) + totalitems++; + + mobj->angle = ANG45 * (mthing->angle/45); + if (options & MTF_AMBUSH) + mobj->flags |= MF_AMBUSH; + } + + +// +// GAME SPAWN FUNCTIONS +// + +// +// P_SpawnPuff +// + +extern fixed_t attackrange; + +void P_SpawnPuff(fixed_t x,fixed_t y,fixed_t z) + { + mobj_t* th; + // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_spawnpuff); + z += (t - P_Random(pr_spawnpuff))<<10; + + th = P_SpawnMobj (x,y,z, MT_PUFF); + th->momz = FRACUNIT; + th->tics -= P_Random(pr_spawnpuff)&3; + + if (th->tics < 1) + th->tics = 1; + + // don't make punches spark on the wall + + if (attackrange == MELEERANGE) + P_SetMobjState (th, S_PUFF3); + } + + +// +// P_SpawnBlood +// +void P_SpawnBlood(fixed_t x,fixed_t y,fixed_t z,int damage) + { + mobj_t* th; + // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_spawnblood); + z += (t - P_Random(pr_spawnblood))<<10; + th = P_SpawnMobj(x,y,z, MT_BLOOD); + th->momz = FRACUNIT*2; + th->tics -= P_Random(pr_spawnblood)&3; + + if (th->tics < 1) + th->tics = 1; + + if (damage <= 12 && damage >= 9) + P_SetMobjState (th,S_BLOOD2); + else if (damage < 9) + P_SetMobjState (th,S_BLOOD3); + } + + +// +// P_CheckMissileSpawn +// Moves the missile forward a bit +// and possibly explodes it right there. +// + +void P_CheckMissileSpawn (mobj_t* th) + { + th->tics -= P_Random(pr_missile)&3; + if (th->tics < 1) + th->tics = 1; + + // move a little forward so an angle can + // be computed if it immediately explodes + + th->x += (th->momx>>1); + th->y += (th->momy>>1); + th->z += (th->momz>>1); + + // killough 8/12/98: for non-missile objects (e.g. grenades) + if (!(th->flags & MF_MISSILE) && mbf_features) + return; + + // killough 3/15/98: no dropoff (really = don't care for missiles) + + if (!P_TryMove (th, th->x, th->y, false)) + P_ExplodeMissile (th); + } + + +// +// P_SpawnMissile +// + +mobj_t* P_SpawnMissile(mobj_t* source,mobj_t* dest,mobjtype_t type) + { + mobj_t* th; + angle_t an; + int dist; + + th = P_SpawnMobj (source->x,source->y,source->z + 4*8*FRACUNIT,type); + + if (th->info->seesound) + S_StartSound (th, th->info->seesound); + + P_SetTarget(&th->target, source); // where it came from + an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y); + + // fuzzy player + + if (dest->flags & MF_SHADOW) + { // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_shadow); + an += (t - P_Random(pr_shadow))<<20; + } + + th->angle = an; + an >>= ANGLETOFINESHIFT; + th->momx = FixedMul (th->info->speed, finecosine[an]); + th->momy = FixedMul (th->info->speed, finesine[an]); + + dist = P_AproxDistance (dest->x - source->x, dest->y - source->y); + dist = dist / th->info->speed; + + if (dist < 1) + dist = 1; + + th->momz = (dest->z - source->z) / dist; + P_CheckMissileSpawn (th); + + return th; + } + + +// +// P_SpawnPlayerMissile +// Tries to aim at a nearby monster +// + +void P_SpawnPlayerMissile(mobj_t* source,mobjtype_t type) +{ + mobj_t *th; + fixed_t x, y, z, slope = 0; + + // see which target is to be aimed at + + angle_t an = source->angle; + + // killough 7/19/98: autoaiming was not in original beta + { + // killough 8/2/98: prefer autoaiming at enemies + uint_64_t mask = mbf_features ? MF_FRIEND : 0; + + do + { + slope = P_AimLineAttack(source, an, 16*64*FRACUNIT, mask); + if (!linetarget) + slope = P_AimLineAttack(source, an += 1<<26, 16*64*FRACUNIT, mask); + if (!linetarget) + slope = P_AimLineAttack(source, an -= 2<<26, 16*64*FRACUNIT, mask); + if (!linetarget) + an = source->angle, slope = 0; + } + while (mask && (mask=0, !linetarget)); // killough 8/2/98 + } + + x = source->x; + y = source->y; + z = source->z + 4*8*FRACUNIT; + + th = P_SpawnMobj (x,y,z, type); + + if (th->info->seesound) + S_StartSound (th, th->info->seesound); + + P_SetTarget(&th->target, source); + th->angle = an; + th->momx = FixedMul(th->info->speed,finecosine[an>>ANGLETOFINESHIFT]); + th->momy = FixedMul(th->info->speed,finesine[an>>ANGLETOFINESHIFT]); + th->momz = FixedMul(th->info->speed,slope); + + P_CheckMissileSpawn(th); + } diff --git a/src/p_mobj.h b/src/p_mobj.h new file mode 100644 index 0000000..ccd66f3 --- /dev/null +++ b/src/p_mobj.h @@ -0,0 +1,403 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Map Objects, MObj, definition and handling. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_MOBJ__ +#define __P_MOBJ__ + +// Basics. +#include "tables.h" +#include "m_fixed.h" + +// We need the thinker_t stuff. +#include "d_think.h" + +// We need the WAD data structure for Map things, +// from the THINGS lump. +#include "doomdata.h" + +// States are tied to finite states are +// tied to animation frames. +// Needs precompiled tables/data structures. +#include "info.h" + +// +// NOTES: mobj_t +// +// mobj_ts are used to tell the refresh where to draw an image, +// tell the world simulation when objects are contacted, +// and tell the sound driver how to position a sound. +// +// The refresh uses the next and prev links to follow +// lists of things in sectors as they are being drawn. +// The sprite, frame, and angle elements determine which patch_t +// is used to draw the sprite if it is visible. +// The sprite and frame values are allmost allways set +// from state_t structures. +// The statescr.exe utility generates the states.h and states.c +// files that contain the sprite/frame numbers from the +// statescr.txt source file. +// The xyz origin point represents a point at the bottom middle +// of the sprite (between the feet of a biped). +// This is the default origin position for patch_ts grabbed +// with lumpy.exe. +// A walking creature will have its z equal to the floor +// it is standing on. +// +// The sound code uses the x,y, and subsector fields +// to do stereo positioning of any sound effited by the mobj_t. +// +// The play simulation uses the blocklinks, x,y,z, radius, height +// to determine when mobj_ts are touching each other, +// touching lines in the map, or hit by trace lines (gunshots, +// lines of sight, etc). +// The mobj_t->flags element has various bit flags +// used by the simulation. +// +// Every mobj_t is linked into a single sector +// based on its origin coordinates. +// The subsector_t is found with R_PointInSubsector(x,y), +// and the sector_t can be found with subsector->sector. +// The sector links are only used by the rendering code, +// the play simulation does not care about them at all. +// +// Any mobj_t that needs to be acted upon by something else +// in the play world (block movement, be shot, etc) will also +// need to be linked into the blockmap. +// If the thing has the MF_NOBLOCK flag set, it will not use +// the block links. It can still interact with other things, +// but only as the instigator (missiles will run into other +// things, but nothing can run into a missile). +// Each block in the grid is 128*128 units, and knows about +// every line_t that it contains a piece of, and every +// interactable mobj_t that has its origin contained. +// +// A valid mobj_t is a mobj_t that has the proper subsector_t +// filled in for its xy coordinates and is linked into the +// sector from which the subsector was made, or has the +// MF_NOSECTOR flag set (the subsector_t needs to be valid +// even if MF_NOSECTOR is set), and is linked into a blockmap +// block or has the MF_NOBLOCKMAP flag set. +// Links should only be modified by the P_[Un]SetThingPosition() +// functions. +// Do not change the MF_NO? flags while a thing is valid. +// +// Any questions? +// + +// +// Misc. mobj flags +// + +// Call P_SpecialThing when touched. +#define MF_SPECIAL (uint_64_t)(0x0000000000000001) +// Blocks. +#define MF_SOLID (uint_64_t)(0x0000000000000002) +// Can be hit. +#define MF_SHOOTABLE (uint_64_t)(0x0000000000000004) +// Don't use the sector links (invisible but touchable). +#define MF_NOSECTOR (uint_64_t)(0x0000000000000008) +// Don't use the blocklinks (inert but displayable) +#define MF_NOBLOCKMAP (uint_64_t)(0x0000000000000010) + +// Not to be activated by sound, deaf monster. +#define MF_AMBUSH (uint_64_t)(0x0000000000000020) +// Will try to attack right back. +#define MF_JUSTHIT (uint_64_t)(0x0000000000000040) +// Will take at least one step before attacking. +#define MF_JUSTATTACKED (uint_64_t)(0x0000000000000080) +// On level spawning (initial position), +// hang from ceiling instead of stand on floor. +#define MF_SPAWNCEILING (uint_64_t)(0x0000000000000100) +// Don't apply gravity (every tic), +// that is, object will float, keeping current height +// or changing it actively. +#define MF_NOGRAVITY (uint_64_t)(0x0000000000000200) + +// Movement flags. +// This allows jumps from high places. +#define MF_DROPOFF (uint_64_t)(0x0000000000000400) +// For players, will pick up items. +#define MF_PICKUP (uint_64_t)(0x0000000000000800) +// Player cheat. ??? +#define MF_NOCLIP (uint_64_t)(0x0000000000001000) +// Player: keep info about sliding along walls. +#define MF_SLIDE (uint_64_t)(0x0000000000002000) +// Allow moves to any height, no gravity. +// For active floaters, e.g. cacodemons, pain elementals. +#define MF_FLOAT (uint_64_t)(0x0000000000004000) +// Don't cross lines +// ??? or look at heights on teleport. +#define MF_TELEPORT (uint_64_t)(0x0000000000008000) +// Don't hit same species, explode on block. +// Player missiles as well as fireballs of various kinds. +#define MF_MISSILE (uint_64_t)(0x0000000000010000) +// Dropped by a demon, not level spawned. +// E.g. ammo clips dropped by dying former humans. +#define MF_DROPPED (uint_64_t)(0x0000000000020000) +// Use fuzzy draw (shadow demons or spectres), +// temporary player invisibility powerup. +#define MF_SHADOW (uint_64_t)(0x0000000000040000) +// Flag: don't bleed when shot (use puff), +// barrels and shootable furniture shall not bleed. +#define MF_NOBLOOD (uint_64_t)(0x0000000000080000) +// Don't stop moving halfway off a step, +// that is, have dead bodies slide down all the way. +#define MF_CORPSE (uint_64_t)(0x0000000000100000) +// Floating to a height for a move, ??? +// don't auto float to target's height. +#define MF_INFLOAT (uint_64_t)(0x0000000000200000) + +// On kill, count this enemy object +// towards intermission kill total. +// Happy gathering. +#define MF_COUNTKILL (uint_64_t)(0x0000000000400000) + +// On picking up, count this item object +// towards intermission item total. +#define MF_COUNTITEM (uint_64_t)(0x0000000000800000) + +// Special handling: skull in flight. +// Neither a cacodemon nor a missile. +#define MF_SKULLFLY (uint_64_t)(0x0000000001000000) + +// Don't spawn this object +// in death match mode (e.g. key cards). +#define MF_NOTDMATCH (uint_64_t)(0x0000000002000000) + +// Player sprites in multiplayer modes are modified +// using an internal color lookup table for re-indexing. +// If 0x4 0x8 or 0xc, +// use a translation table for player colormaps +#define MF_TRANSLATION (uint_64_t)(0x000000000c000000) +#define MF_TRANSLATION1 (uint_64_t)(0x0000000004000000) +#define MF_TRANSLATION2 (uint_64_t)(0x0000000008000000) +// Hmm ???. +#define MF_TRANSSHIFT 26 + +#define MF_UNUSED2 (uint_64_t)(0x0000000010000000) +#define MF_UNUSED3 (uint_64_t)(0x0000000020000000) + + // Translucent sprite? // phares +#define MF_TRANSLUCENT (uint_64_t)(0x0000000040000000) + +// this is free LONGLONG(0x0000000100000000) + +// these are greater than an int. That's why the flags below are now uint_64_t + +#define MF_TOUCHY LONGLONG(0x0000000100000000) +#define MF_BOUNCES LONGLONG(0x0000000200000000) +#define MF_FRIEND LONGLONG(0x0000000400000000) + +// killough 9/15/98: Same, but internal flags, not intended for .deh +// (some degree of opaqueness is good, to avoid compatibility woes) + +enum { + MIF_FALLING = 1, // Object is falling + MIF_ARMED = 2, // Object is armed (for MF_TOUCHY objects) +}; + +// Map Object definition. +// +// +// killough 2/20/98: +// +// WARNING: Special steps must be taken in p_saveg.c if C pointers are added to +// this mobj_s struct, or else savegames will crash when loaded. See p_saveg.c. +// Do not add "struct mobj_s *fooptr" without adding code to p_saveg.c to +// convert the pointers to ordinals and back for savegames. This was the whole +// reason behind monsters going to sleep when loading savegames (the "target" +// pointer was simply nullified after loading, to prevent Doom from crashing), +// and the whole reason behind loadgames crashing on savegames of AV attacks. +// + +// killough 9/8/98: changed some fields to shorts, +// for better memory usage (if only for cache). +/* cph 2006/08/28 - move Prev[XYZ] fields to the end of the struct. Add any + * other new fields to the end, and make sure you don't break savegames! */ + +typedef struct mobj_s +{ + // List: thinker links. + thinker_t thinker; + + // Info for drawing: position. + fixed_t x; + fixed_t y; + fixed_t z; + + // More list: links in sector (if needed) + struct mobj_s* snext; + struct mobj_s** sprev; // killough 8/10/98: change to ptr-to-ptr + + //More drawing info: to determine current sprite. + angle_t angle; // orientation + spritenum_t sprite; // used to find patch_t and flip value + int frame; // might be ORed with FF_FULLBRIGHT + + // Interaction info, by BLOCKMAP. + // Links in blocks (if needed). + struct mobj_s* bnext; + struct mobj_s** bprev; // killough 8/11/98: change to ptr-to-ptr + + struct subsector_s* subsector; + + // The closest interval over all contacted Sectors. + fixed_t floorz; + fixed_t ceilingz; + + // killough 11/98: the lowest floor over all contacted Sectors. + fixed_t dropoffz; + + // For movement checking. + fixed_t radius; + fixed_t height; + + // Momentums, used to update position. + fixed_t momx; + fixed_t momy; + fixed_t momz; + + // If == validcount, already checked. + int validcount; + + mobjtype_t type; + mobjinfo_t* info; // &mobjinfo[mobj->type] + + int tics; // state tic counter + state_t* state; + uint_64_t flags; + int intflags; // killough 9/15/98: internal flags + int health; + + // Movement direction, movement generation (zig-zagging). + short movedir; // 0-7 + short movecount; // when 0, select a new dir + short strafecount; // killough 9/8/98: monster strafing + + // Thing being chased/attacked (or NULL), + // also the originator for missiles. + struct mobj_s* target; + + // Reaction time: if non 0, don't attack yet. + // Used by player to freeze a bit after teleporting. + short reactiontime; + + // If >0, the current target will be chased no + // matter what (even if shot by another object) + short threshold; + + // killough 9/9/98: How long a monster pursues a target. + short pursuecount; + + short gear; // killough 11/98: used in torque simulation + + // Additional info record for player avatars only. + // Only valid if type == MT_PLAYER + struct player_s* player; + + // Player number last looked for. + short lastlook; + + // For nightmare respawn. + mapthing_t spawnpoint; + + // Thing being chased/attacked for tracers. + struct mobj_s* tracer; + + // new field: last known enemy -- killough 2/15/98 + struct mobj_s* lastenemy; + + // killough 8/2/98: friction properties part of sectors, + // not objects -- removed friction properties from here + // e6y: restored friction properties here + // Friction values for the sector the object is in + int friction; // phares 3/17/98 + int movefactor; + + // a linked list of sectors where this object appears + struct msecnode_s* touching_sectorlist; // phares 3/14/98 + + fixed_t PrevX; + fixed_t PrevY; + fixed_t PrevZ; + + fixed_t pad; // cph - needed so I can get the size unambiguously on amd64 + + // SEE WARNING ABOVE ABOUT POINTER FIELDS!!! +} mobj_t; + +// External declarations (fomerly in p_local.h) -- killough 5/2/98 + +#define VIEWHEIGHT (41*FRACUNIT) + +#define GRAVITY FRACUNIT +#define MAXMOVE (30*FRACUNIT) + +#define ONFLOORZ INT_MIN +#define ONCEILINGZ INT_MAX + +// Time interval for item respawning. +#define ITEMQUESIZE 128 + +#define FLOATSPEED (FRACUNIT*4) +#define STOPSPEED (FRACUNIT/16) + +// killough 11/98: +// For torque simulation: + +#define OVERDRIVE 6 +#define MAXGEAR (OVERDRIVE+16) + +// killough 11/98: +// Whether an object is "sentient" or not. Used for environmental influences. +#define sentient(mobj) ((mobj)->health > 0 && (mobj)->info->seestate) + +extern int iquehead; +extern int iquetail; + +void P_RespawnSpecials(void); +mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type); +void P_RemoveMobj(mobj_t *th); +boolean P_SetMobjState(mobj_t *mobj, statenum_t state); +void P_MobjThinker(mobj_t *mobj); +void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z); +void P_SpawnBlood(fixed_t x, fixed_t y, fixed_t z, int damage); +mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type); +void P_SpawnPlayerMissile(mobj_t *source, mobjtype_t type); +boolean P_IsDoomnumAllowed(int doomnum); +void P_SpawnMapThing (const mapthing_t* mthing); +void P_SpawnPlayer(int n, const mapthing_t *mthing); +void P_CheckMissileSpawn(mobj_t*); // killough 8/2/98 +void P_ExplodeMissile(mobj_t*); // killough +#endif + diff --git a/src/p_plats.c b/src/p_plats.c new file mode 100644 index 0000000..9bea240 --- /dev/null +++ b/src/p_plats.c @@ -0,0 +1,437 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Plats (i.e. elevator platforms) code, raising/lowering. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "m_random.h" +#include "r_main.h" +#include "p_spec.h" +#include "p_tick.h" +#include "s_sound.h" +#include "sounds.h" + +platlist_t *activeplats; // killough 2/14/98: made global again + +// +// T_PlatRaise() +// +// Action routine to move a plat up and down +// +// Passed a plat structure containing all pertinent information about the move +// No return +// +// jff 02/08/98 all cases with labels beginning with gen added to support +// generalized line type behaviors. + +void T_PlatRaise(plat_t* plat) +{ + result_e res; + + // handle plat moving, up, down, waiting, or in stasis, + switch(plat->status) + { + case up: // plat moving up + res = T_MovePlane(plat->sector,plat->speed,plat->high,plat->crush,0,1); + + // if a pure raise type, make the plat moving sound + if (plat->type == raiseAndChange + || plat->type == raiseToNearestAndChange) + { + if (!(leveltime&7)) + S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_stnmov); + } + + // if encountered an obstacle, and not a crush type, reverse direction + if (res == crushed && (!plat->crush)) + { + plat->count = plat->wait; + plat->status = down; + S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_pstart); + } + else // else handle reaching end of up stroke + { + if (res == pastdest) // end of stroke + { + // if not an instant toggle type, wait, make plat stop sound + if (plat->type!=toggleUpDn) + { + plat->count = plat->wait; + plat->status = waiting; + S_StartSound((mobj_t *)&plat->sector->soundorg, sfx_pstop); + } + else // else go into stasis awaiting next toggle activation + { + plat->oldstatus = plat->status;//jff 3/14/98 after action wait + plat->status = in_stasis; //for reactivation of toggle + } + + // lift types and pure raise types are done at end of up stroke + // only the perpetual type waits then goes back up + switch(plat->type) + { + case blazeDWUS: + case downWaitUpStay: + case raiseAndChange: + case raiseToNearestAndChange: + case genLift: + P_RemoveActivePlat(plat); // killough + default: + break; + } + } + } + break; + + case down: // plat moving down + res = T_MovePlane(plat->sector,plat->speed,plat->low,false,0,-1); + + // handle reaching end of down stroke + if (res == pastdest) + { + // if not an instant toggle, start waiting, make plat stop sound + if (plat->type!=toggleUpDn) //jff 3/14/98 toggle up down + { // is silent, instant, no waiting + plat->count = plat->wait; + plat->status = waiting; + S_StartSound((mobj_t *)&plat->sector->soundorg,sfx_pstop); + } + else // instant toggles go into stasis awaiting next activation + { + plat->oldstatus = plat->status;//jff 3/14/98 after action wait + plat->status = in_stasis; //for reactivation of toggle + } + + //jff 1/26/98 remove the plat if it bounced so it can be tried again + //only affects plats that raise and bounce + //killough 1/31/98: relax compatibility to demo_compatibility + + // remove the plat if its a pure raise type + if (!comp[comp_floors]) + { + switch(plat->type) + { + case raiseAndChange: + case raiseToNearestAndChange: + P_RemoveActivePlat(plat); + default: + break; + } + } + } + break; + + case waiting: // plat is waiting + if (!--plat->count) // downcount and check for delay elapsed + { + if (plat->sector->floorheight == plat->low) + plat->status = up; // if at bottom, start up + else + plat->status = down; // if at top, start down + + // make plat start sound + S_StartSound((mobj_t *)&plat->sector->soundorg,sfx_pstart); + } + break; //jff 1/27/98 don't pickup code added later to in_stasis + + case in_stasis: // do nothing if in stasis + break; + } +} + + +// +// EV_DoPlat +// +// Handle Plat linedef types +// +// Passed the linedef that activated the plat, the type of plat action, +// and for some plat types, an amount to raise +// Returns true if a thinker is started, or restarted from stasis +// +int EV_DoPlat +( line_t* line, + plattype_e type, + int amount ) +{ + plat_t* plat; + int secnum; + int rtn; + sector_t* sec; + + secnum = -1; + rtn = 0; + + + // Activate all plats that are in_stasis + switch(type) + { + case perpetualRaise: + P_ActivateInStasis(line->tag); + break; + + case toggleUpDn: + P_ActivateInStasis(line->tag); + rtn=1; + break; + + default: + break; + } + + // act on all sectors tagged the same as the activating linedef + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + + // don't start a second floor function if already moving + if (P_SectorActive(floor_special,sec)) //jff 2/23/98 multiple thinkers + continue; + + // Create a thinker + rtn = 1; + plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0); + memset(plat, 0, sizeof(*plat)); + P_AddThinker(&plat->thinker); + + plat->type = type; + plat->sector = sec; + plat->sector->floordata = plat; //jff 2/23/98 multiple thinkers + plat->thinker.function = T_PlatRaise; + plat->crush = false; + plat->tag = line->tag; + + //jff 1/26/98 Avoid raise plat bouncing a head off a ceiling and then + //going down forever -- default low to plat height when triggered + plat->low = sec->floorheight; + + // set up plat according to type + switch(type) + { + case raiseToNearestAndChange: + plat->speed = PLATSPEED/2; + sec->floorpic = sides[line->sidenum[0]].sector->floorpic; + plat->high = P_FindNextHighestFloor(sec,sec->floorheight); + plat->wait = 0; + plat->status = up; + sec->special = 0; + //jff 3/14/98 clear old field as well + sec->oldspecial = 0; + + S_StartSound((mobj_t *)&sec->soundorg,sfx_stnmov); + break; + + case raiseAndChange: + plat->speed = PLATSPEED/2; + sec->floorpic = sides[line->sidenum[0]].sector->floorpic; + plat->high = sec->floorheight + amount*FRACUNIT; + plat->wait = 0; + plat->status = up; + + S_StartSound((mobj_t *)&sec->soundorg,sfx_stnmov); + break; + + case downWaitUpStay: + plat->speed = PLATSPEED * 4; + plat->low = P_FindLowestFloorSurrounding(sec); + + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + + plat->high = sec->floorheight; + plat->wait = 35*PLATWAIT; + plat->status = down; + S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart); + break; + + case blazeDWUS: + plat->speed = PLATSPEED * 8; + plat->low = P_FindLowestFloorSurrounding(sec); + + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + + plat->high = sec->floorheight; + plat->wait = 35*PLATWAIT; + plat->status = down; + S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart); + break; + + case perpetualRaise: + plat->speed = PLATSPEED; + plat->low = P_FindLowestFloorSurrounding(sec); + + if (plat->low > sec->floorheight) + plat->low = sec->floorheight; + + plat->high = P_FindHighestFloorSurrounding(sec); + + if (plat->high < sec->floorheight) + plat->high = sec->floorheight; + + plat->wait = 35*PLATWAIT; + plat->status = P_Random(pr_plats)&1; + + S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart); + break; + + case toggleUpDn: //jff 3/14/98 add new type to support instant toggle + plat->speed = PLATSPEED; //not used + plat->wait = 35*PLATWAIT; //not used + plat->crush = true; //jff 3/14/98 crush anything in the way + + // set up toggling between ceiling, floor inclusive + plat->low = sec->ceilingheight; + plat->high = sec->floorheight; + plat->status = down; + break; + + default: + break; + } + P_AddActivePlat(plat); // add plat to list of active plats + } + return rtn; +} + +// The following were all rewritten by Lee Killough +// to use the new structure which places no limits +// on active plats. It also avoids spending as much +// time searching for active plats. Previously a +// fixed-size array was used, with NULL indicating +// empty entries, while now a doubly-linked list +// is used. + +// +// P_ActivateInStasis() +// +// Activate a plat that has been put in stasis +// (stopped perpetual floor, instant floor/ceil toggle) +// +// Passed the tag of the plat that should be reactivated +// Returns nothing +// +void P_ActivateInStasis(int tag) +{ + platlist_t *pl; + for (pl=activeplats; pl; pl=pl->next) // search the active plats + { + plat_t *plat = pl->plat; // for one in stasis with right tag + if (plat->tag == tag && plat->status == in_stasis) + { + if (plat->type==toggleUpDn) //jff 3/14/98 reactivate toggle type + plat->status = plat->oldstatus==up? down : up; + else + plat->status = plat->oldstatus; + plat->thinker.function = T_PlatRaise; + } + } +} + +// +// EV_StopPlat() +// +// Handler for "stop perpetual floor" linedef type +// +// Passed the linedef that stopped the plat +// Returns true if a plat was put in stasis +// +// jff 2/12/98 added int return value, fixed return +// +int EV_StopPlat(line_t* line) +{ + platlist_t *pl; + for (pl=activeplats; pl; pl=pl->next) // search the active plats + { + plat_t *plat = pl->plat; // for one with the tag not in stasis + if (plat->status != in_stasis && plat->tag == line->tag) + { + plat->oldstatus = plat->status; // put it in stasis + plat->status = in_stasis; + plat->thinker.function = NULL; + } + } + return 1; +} + +// +// P_AddActivePlat() +// +// Add a plat to the head of the active plat list +// +// Passed a pointer to the plat to add +// Returns nothing +// +void P_AddActivePlat(plat_t* plat) +{ + platlist_t *list = malloc(sizeof *list); + list->plat = plat; + plat->list = list; + if ((list->next = activeplats)) + list->next->prev = &list->next; + list->prev = &activeplats; + activeplats = list; +} + +// +// P_RemoveActivePlat() +// +// Remove a plat from the active plat list +// +// Passed a pointer to the plat to remove +// Returns nothing +// +void P_RemoveActivePlat(plat_t* plat) +{ + platlist_t *list = plat->list; + plat->sector->floordata = NULL; //jff 2/23/98 multiple thinkers + P_RemoveThinker(&plat->thinker); + if ((*list->prev = list->next)) + list->next->prev = list->prev; + free(list); +} + +// +// P_RemoveAllActivePlats() +// +// Remove all plats from the active plat list +// +// Passed nothing, returns nothing +// +void P_RemoveAllActivePlats(void) +{ + while (activeplats) + { + platlist_t *next = activeplats->next; + free(activeplats); + activeplats = next; + } +} diff --git a/src/p_pspr.c b/src/p_pspr.c new file mode 100644 index 0000000..afac1fc --- /dev/null +++ b/src/p_pspr.c @@ -0,0 +1,829 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Weapon sprite animation, weapon objects. + * Action functions for weapons. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "r_main.h" +#include "p_map.h" +#include "p_inter.h" +#include "p_pspr.h" +#include "p_enemy.h" +#include "m_random.h" +#include "s_sound.h" +#include "sounds.h" +#include "d_event.h" +#include "r_demo.h" + +#define LOWERSPEED (FRACUNIT*6) +#define RAISESPEED (FRACUNIT*6) +#define WEAPONBOTTOM (FRACUNIT*128) +#define WEAPONTOP (FRACUNIT*32) + +#define BFGCELLS bfgcells /* Ty 03/09/98 externalized in p_inter.c */ + +extern void P_Thrust(player_t *, angle_t, fixed_t); + +// The following array holds the recoil values // phares + +static const int recoil_values[] = { // phares + 10, // wp_fist + 10, // wp_pistol + 30, // wp_shotgun + 10, // wp_chaingun + 100,// wp_missile + 20, // wp_plasma + 100,// wp_bfg + 0, // wp_chainsaw + 80 // wp_supershotgun +}; + +// +// P_SetPsprite +// + +static void P_SetPsprite(player_t *player, int position, statenum_t stnum) +{ + pspdef_t *psp = &player->psprites[position]; + + do + { + state_t *state; + + if (!stnum) + { + // object removed itself + psp->state = NULL; + break; + } + + state = &states[stnum]; + psp->state = state; + psp->tics = state->tics; // could be 0 + + if (state->misc1) + { + // coordinate set + psp->sx = state->misc1 << FRACBITS; + psp->sy = state->misc2 << FRACBITS; + } + + // Call action routine. + // Modified handling. + if (state->action) + { + state->action(player, psp); + if (!psp->state) + break; + } + stnum = psp->state->nextstate; + } + while (!psp->tics); // an initial state of 0 could cycle through +} + +// +// P_BringUpWeapon +// Starts bringing the pending weapon up +// from the bottom of the screen. +// Uses player +// + +static void P_BringUpWeapon(player_t *player) +{ + statenum_t newstate; + + if (player->pendingweapon == wp_nochange) + player->pendingweapon = player->readyweapon; + + if (player->pendingweapon == wp_chainsaw) + S_StartSound (player->mo, sfx_sawup); + + newstate = weaponinfo[player->pendingweapon].upstate; + + player->pendingweapon = wp_nochange; + // killough 12/98: prevent pistol from starting visibly at bottom of screen: + player->psprites[ps_weapon].sy = + mbf_features ? WEAPONBOTTOM+FRACUNIT*2 : WEAPONBOTTOM; + + P_SetPsprite(player, ps_weapon, newstate); +} + +// The first set is where the weapon preferences from // killough, +// default.cfg are stored. These values represent the keys used // phares +// in DOOM2 to bring up the weapon, i.e. 6 = plasma gun. These // | +// are NOT the wp_* constants. // V + +int weapon_preferences[2][NUMWEAPONS+1] = { + {6, 9, 4, 3, 2, 8, 5, 7, 1, 0}, // !compatibility preferences + {6, 9, 4, 3, 2, 8, 5, 7, 1, 0}, // compatibility preferences +}; + +// P_SwitchWeapon checks current ammo levels and gives you the +// most preferred weapon with ammo. It will not pick the currently +// raised weapon. When called from P_CheckAmmo this won't matter, +// because the raised weapon has no ammo anyway. When called from +// G_BuildTiccmd you want to toggle to a different weapon regardless. + +int P_SwitchWeapon(player_t *player) +{ + int *prefer = weapon_preferences[demo_compatibility!=0]; // killough 3/22/98 + int currentweapon = player->readyweapon; + int newweapon = currentweapon; + int i = NUMWEAPONS+1; // killough 5/2/98 + + // killough 2/8/98: follow preferences and fix BFG/SSG bugs + + do + switch (*prefer++) + { + case 1: + if (!player->powers[pw_strength]) // allow chainsaw override + break; + case 0: + newweapon = wp_fist; + break; + case 2: + if (player->ammo[am_clip]) + newweapon = wp_pistol; + break; + case 3: + if (player->weaponowned[wp_shotgun] && player->ammo[am_shell]) + newweapon = wp_shotgun; + break; + case 4: + if (player->weaponowned[wp_chaingun] && player->ammo[am_clip]) + newweapon = wp_chaingun; + break; + case 5: + if (player->weaponowned[wp_missile] && player->ammo[am_misl]) + newweapon = wp_missile; + break; + case 6: + if (player->weaponowned[wp_plasma] && player->ammo[am_cell] && + gamemode != shareware) + newweapon = wp_plasma; + break; + case 7: + if (player->weaponowned[wp_bfg] && gamemode != shareware && + player->ammo[am_cell] >= (demo_compatibility ? 41 : 40)) + newweapon = wp_bfg; + break; + case 8: + if (player->weaponowned[wp_chainsaw]) + newweapon = wp_chainsaw; + break; + case 9: + if (player->weaponowned[wp_supershotgun] && gamemode == commercial && + player->ammo[am_shell] >= (demo_compatibility ? 3 : 2)) + newweapon = wp_supershotgun; + break; + } + while (newweapon==currentweapon && --i); // killough 5/2/98 + return newweapon; +} + +// killough 5/2/98: whether consoleplayer prefers weapon w1 over weapon w2. +int P_WeaponPreferred(int w1, int w2) +{ + return + (weapon_preferences[0][0] != ++w2 && (weapon_preferences[0][0] == ++w1 || + (weapon_preferences[0][1] != w2 && (weapon_preferences[0][1] == w1 || + (weapon_preferences[0][2] != w2 && (weapon_preferences[0][2] == w1 || + (weapon_preferences[0][3] != w2 && (weapon_preferences[0][3] == w1 || + (weapon_preferences[0][4] != w2 && (weapon_preferences[0][4] == w1 || + (weapon_preferences[0][5] != w2 && (weapon_preferences[0][5] == w1 || + (weapon_preferences[0][6] != w2 && (weapon_preferences[0][6] == w1 || + (weapon_preferences[0][7] != w2 && (weapon_preferences[0][7] == w1 + )))))))))))))))); +} + +// +// P_CheckAmmo +// Returns true if there is enough ammo to shoot. +// If not, selects the next weapon to use. +// (only in demo_compatibility mode -- killough 3/22/98) +// + +boolean P_CheckAmmo(player_t *player) +{ + ammotype_t ammo = weaponinfo[player->readyweapon].ammo; + int count = 1; // Regular + + if (player->readyweapon == wp_bfg) // Minimal amount for one shot varies. + count = BFGCELLS; + else + if (player->readyweapon == wp_supershotgun) // Double barrel. + count = 2; + + // Some do not need ammunition anyway. + // Return if current ammunition sufficient. + + if (ammo == am_noammo || player->ammo[ammo] >= count) + return true; + + // Out of ammo, pick a weapon to change to. + // + // killough 3/22/98: for old demos we do the switch here and now; + // for Boom games we cannot do this, and have different player + // preferences across demos or networks, so we have to use the + // G_BuildTiccmd() interface instead of making the switch here. + + if (demo_compatibility) + { + player->pendingweapon = P_SwitchWeapon(player); // phares + // Now set appropriate weapon overlay. + P_SetPsprite(player,ps_weapon,weaponinfo[player->readyweapon].downstate); + } + + return false; +} + +// +// P_FireWeapon. +// + +static void P_FireWeapon(player_t *player) +{ + statenum_t newstate; + + if (!P_CheckAmmo(player)) + return; + + P_SetMobjState(player->mo, S_PLAY_ATK1); + newstate = weaponinfo[player->readyweapon].atkstate; + P_SetPsprite(player, ps_weapon, newstate); + P_NoiseAlert(player->mo, player->mo); +} + +// +// P_DropWeapon +// Player died, so put the weapon away. +// + +void P_DropWeapon(player_t *player) +{ + P_SetPsprite(player, ps_weapon, weaponinfo[player->readyweapon].downstate); +} + +// +// A_WeaponReady +// The player can fire the weapon +// or change to another weapon at this time. +// Follows after getting weapon up, +// or after previous attack/fire sequence. +// + +void A_WeaponReady(player_t *player, pspdef_t *psp) +{ + // get out of attack state + if (player->mo->state == &states[S_PLAY_ATK1] + || player->mo->state == &states[S_PLAY_ATK2] ) + P_SetMobjState(player->mo, S_PLAY); + + if (player->readyweapon == wp_chainsaw && psp->state == &states[S_SAW]) + S_StartSound(player->mo, sfx_sawidl); + + // check for change + // if player is dead, put the weapon away + + if (player->pendingweapon != wp_nochange || !player->health) + { + // change weapon (pending weapon should already be validated) + statenum_t newstate = weaponinfo[player->readyweapon].downstate; + P_SetPsprite(player, ps_weapon, newstate); + return; + } + + // check for fire + // the missile launcher and bfg do not auto fire + + if (player->cmd.buttons & BT_ATTACK) + { + if (!player->attackdown || (player->readyweapon != wp_missile && + player->readyweapon != wp_bfg)) + { + player->attackdown = true; + P_FireWeapon(player); + return; + } + } + else + player->attackdown = false; + + // bob the weapon based on movement speed + { + int angle = (128*leveltime) & FINEMASK; + psp->sx = FRACUNIT + FixedMul(player->bob, finecosine[angle]); + angle &= FINEANGLES/2-1; + psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]); + } +} + +// +// A_ReFire +// The player can re-fire the weapon +// without lowering it entirely. +// + +void A_ReFire(player_t *player, pspdef_t *psp) +{ + // check for fire + // (if a weaponchange is pending, let it go through instead) + + if ( (player->cmd.buttons & BT_ATTACK) + && player->pendingweapon == wp_nochange && player->health) + { + player->refire++; + P_FireWeapon(player); + } + else + { + player->refire = 0; + P_CheckAmmo(player); + } +} + +void A_CheckReload(player_t *player, pspdef_t *psp) +{ + if (!P_CheckAmmo(player) && compatibility_level >= prboom_4_compatibility) { + /* cph 2002/08/08 - In old Doom, P_CheckAmmo would start the weapon lowering + * immediately. This was lost in Boom when the weapon switching logic was + * rewritten. But we must tell Doom that we don't need to complete the + * reload frames for the weapon here. G_BuildTiccmd will set ->pendingweapon + * for us later on. */ + P_SetPsprite(player,ps_weapon,weaponinfo[player->readyweapon].downstate); + } +} + +// +// A_Lower +// Lowers current weapon, +// and changes weapon at bottom. +// + +void A_Lower(player_t *player, pspdef_t *psp) +{ + psp->sy += LOWERSPEED; + + // Is already down. + if (psp->sy < WEAPONBOTTOM) + return; + + // Player is dead. + if (player->playerstate == PST_DEAD) + { + psp->sy = WEAPONBOTTOM; + return; // don't bring weapon back up + } + + // The old weapon has been lowered off the screen, + // so change the weapon and start raising it + + if (!player->health) + { // Player is dead, so keep the weapon off screen. + P_SetPsprite(player, ps_weapon, S_NULL); + return; + } + + player->readyweapon = player->pendingweapon; + + P_BringUpWeapon(player); +} + +// +// A_Raise +// + +void A_Raise(player_t *player, pspdef_t *psp) +{ + statenum_t newstate; + + psp->sy -= RAISESPEED; + + if (psp->sy > WEAPONTOP) + return; + + psp->sy = WEAPONTOP; + + // The weapon has been raised all the way, + // so change to the ready state. + + newstate = weaponinfo[player->readyweapon].readystate; + + P_SetPsprite(player, ps_weapon, newstate); +} + + +// Weapons now recoil, amount depending on the weapon. // phares +// // | +// The P_SetPsprite call in each of the weapon firing routines // V +// was moved here so the recoil could be synched with the +// muzzle flash, rather than the pressing of the trigger. +// The BFG delay caused this to be necessary. + +static void A_FireSomething(player_t* player,int adder) +{ + P_SetPsprite(player, ps_flash, + weaponinfo[player->readyweapon].flashstate+adder); + + // killough 3/27/98: prevent recoil in no-clipping mode + if (!(player->mo->flags & MF_NOCLIP)) + if (!compatibility && weapon_recoil) + P_Thrust(player, + ANG180+player->mo->angle, // ^ + 2048*recoil_values[player->readyweapon]); // | +} // phares + +// +// A_GunFlash +// + +void A_GunFlash(player_t *player, pspdef_t *psp) +{ + P_SetMobjState(player->mo, S_PLAY_ATK2); + + A_FireSomething(player,0); // phares +} + +// +// WEAPON ATTACKS +// + +// +// A_Punch +// + +void A_Punch(player_t *player, pspdef_t *psp) +{ + angle_t angle; + int t, slope, damage = (P_Random(pr_punch)%10+1)<<1; + + if (player->powers[pw_strength]) + damage *= 10; + + angle = player->mo->angle; + + // killough 5/5/98: remove dependence on order of evaluation: + t = P_Random(pr_punchangle); + angle += (t - P_Random(pr_punchangle))<<18; + + /* killough 8/2/98: make autoaiming prefer enemies */ + if (!mbf_features || + (slope = P_AimLineAttack(player->mo, angle, MELEERANGE, MF_FRIEND), + !linetarget)) + slope = P_AimLineAttack(player->mo, angle, MELEERANGE, 0); + + P_LineAttack(player->mo, angle, MELEERANGE, slope, damage); + + if (!linetarget) + return; + + S_StartSound(player->mo, sfx_punch); + + // turn to face target + + player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, + linetarget->x, linetarget->y); + R_SmoothPlaying_Reset(player); // e6y +} + +// +// A_Saw +// + +void A_Saw(player_t *player, pspdef_t *psp) +{ + int slope, damage = 2*(P_Random(pr_saw)%10+1); + angle_t angle = player->mo->angle; + // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_saw); + angle += (t - P_Random(pr_saw))<<18; + + /* Use meleerange + 1 so that the puff doesn't skip the flash + * killough 8/2/98: make autoaiming prefer enemies */ + if (!mbf_features || + (slope = P_AimLineAttack(player->mo, angle, MELEERANGE+1, MF_FRIEND), + !linetarget)) + slope = P_AimLineAttack(player->mo, angle, MELEERANGE+1, 0); + + P_LineAttack(player->mo, angle, MELEERANGE+1, slope, damage); + + if (!linetarget) + { + S_StartSound(player->mo, sfx_sawful); + return; + } + + S_StartSound(player->mo, sfx_sawhit); + + // turn to face target + angle = R_PointToAngle2(player->mo->x, player->mo->y, + linetarget->x, linetarget->y); + + if (angle - player->mo->angle > ANG180) { + if (angle - player->mo->angle < -ANG90/20) + player->mo->angle = angle + ANG90/21; + else + player->mo->angle -= ANG90/20; + } else { + if (angle - player->mo->angle > ANG90/20) + player->mo->angle = angle - ANG90/21; + else + player->mo->angle += ANG90/20; + } + + player->mo->flags |= MF_JUSTATTACKED; + R_SmoothPlaying_Reset(player); // e6y +} + +// +// A_FireMissile +// + +void A_FireMissile(player_t *player, pspdef_t *psp) +{ + player->ammo[weaponinfo[player->readyweapon].ammo]--; + P_SpawnPlayerMissile(player->mo, MT_ROCKET); +} + +// +// A_FireBFG +// + +void A_FireBFG(player_t *player, pspdef_t *psp) +{ + player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS; + P_SpawnPlayerMissile(player->mo, MT_BFG); +} + +// +// A_FirePlasma +// + +void A_FirePlasma(player_t *player, pspdef_t *psp) +{ + player->ammo[weaponinfo[player->readyweapon].ammo]--; + + A_FireSomething(player,P_Random(pr_plasma)&1); // phares + P_SpawnPlayerMissile(player->mo, MT_PLASMA); +} + +// +// P_BulletSlope +// Sets a slope so a near miss is at aproximately +// the height of the intended target +// + +static fixed_t bulletslope; + +static void P_BulletSlope(mobj_t *mo) +{ + angle_t an = mo->angle; // see which target is to be aimed at + + /* killough 8/2/98: make autoaiming prefer enemies */ + uint_64_t mask = mbf_features ? MF_FRIEND : 0; + + do + { + bulletslope = P_AimLineAttack(mo, an, 16*64*FRACUNIT, mask); + if (!linetarget) + bulletslope = P_AimLineAttack(mo, an += 1<<26, 16*64*FRACUNIT, mask); + if (!linetarget) + bulletslope = P_AimLineAttack(mo, an -= 2<<26, 16*64*FRACUNIT, mask); + } + while (mask && (mask=0, !linetarget)); /* killough 8/2/98 */ +} + +// +// P_GunShot +// + +static void P_GunShot(mobj_t *mo, boolean accurate) +{ + int damage = 5*(P_Random(pr_gunshot)%3+1); + angle_t angle = mo->angle; + + if (!accurate) + { // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_misfire); + angle += (t - P_Random(pr_misfire))<<18; + } + + P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage); +} + +// +// A_FirePistol +// + +void A_FirePistol(player_t *player, pspdef_t *psp) +{ + S_StartSound(player->mo, sfx_pistol); + + P_SetMobjState(player->mo, S_PLAY_ATK2); + player->ammo[weaponinfo[player->readyweapon].ammo]--; + + A_FireSomething(player,0); // phares + P_BulletSlope(player->mo); + P_GunShot(player->mo, !player->refire); +} + +// +// A_FireShotgun +// + +void A_FireShotgun(player_t *player, pspdef_t *psp) +{ + int i; + + S_StartSound(player->mo, sfx_shotgn); + P_SetMobjState(player->mo, S_PLAY_ATK2); + + player->ammo[weaponinfo[player->readyweapon].ammo]--; + + A_FireSomething(player,0); // phares + + P_BulletSlope(player->mo); + + for (i=0; i<7; i++) + P_GunShot(player->mo, false); +} + +// +// A_FireShotgun2 +// + +void A_FireShotgun2(player_t *player, pspdef_t *psp) +{ + int i; + + S_StartSound(player->mo, sfx_dshtgn); + P_SetMobjState(player->mo, S_PLAY_ATK2); + player->ammo[weaponinfo[player->readyweapon].ammo] -= 2; + + A_FireSomething(player,0); // phares + + P_BulletSlope(player->mo); + + for (i=0; i<20; i++) + { + int damage = 5*(P_Random(pr_shotgun)%3+1); + angle_t angle = player->mo->angle; + // killough 5/5/98: remove dependence on order of evaluation: + int t = P_Random(pr_shotgun); + angle += (t - P_Random(pr_shotgun))<<19; + t = P_Random(pr_shotgun); + P_LineAttack(player->mo, angle, MISSILERANGE, bulletslope + + ((t - P_Random(pr_shotgun))<<5), damage); + } +} + +// +// A_FireCGun +// + +void A_FireCGun(player_t *player, pspdef_t *psp) +{ + if (player->ammo[weaponinfo[player->readyweapon].ammo] || comp[comp_sound]) + S_StartSound(player->mo, sfx_pistol); + + if (!player->ammo[weaponinfo[player->readyweapon].ammo]) + return; + + P_SetMobjState(player->mo, S_PLAY_ATK2); + player->ammo[weaponinfo[player->readyweapon].ammo]--; + + A_FireSomething(player,psp->state - &states[S_CHAIN1]); // phares + + P_BulletSlope(player->mo); + + P_GunShot(player->mo, !player->refire); +} + +void A_Light0(player_t *player, pspdef_t *psp) +{ + player->extralight = 0; +} + +void A_Light1 (player_t *player, pspdef_t *psp) +{ + player->extralight = 1; +} + +void A_Light2 (player_t *player, pspdef_t *psp) +{ + player->extralight = 2; +} + +// +// A_BFGSpray +// Spawn a BFG explosion on every monster in view +// + +void A_BFGSpray(mobj_t *mo) +{ + int i; + + for (i=0 ; i<40 ; i++) // offset angles from its attack angle + { + int j, damage; + angle_t an = mo->angle - ANG90/2 + ANG90/40*i; + + // mo->target is the originator (player) of the missile + + // killough 8/2/98: make autoaiming prefer enemies + if (!mbf_features || + (P_AimLineAttack(mo->target, an, 16*64*FRACUNIT, MF_FRIEND), + !linetarget)) + P_AimLineAttack(mo->target, an, 16*64*FRACUNIT, 0); + + if (!linetarget) + continue; + + P_SpawnMobj(linetarget->x, linetarget->y, + linetarget->z + (linetarget->height>>2), MT_EXTRABFG); + + for (damage=j=0; j<15; j++) + damage += (P_Random(pr_bfg)&7) + 1; + + P_DamageMobj(linetarget, mo->target, mo->target, damage); + } +} + +// +// A_BFGsound +// + +void A_BFGsound(player_t *player, pspdef_t *psp) +{ + S_StartSound(player->mo, sfx_bfg); +} + +// +// P_SetupPsprites +// Called at start of level for each player. +// + +void P_SetupPsprites(player_t *player) +{ + int i; + + // remove all psprites + for (i=0; ipsprites[i].state = NULL; + + // spawn the gun + player->pendingweapon = player->readyweapon; + P_BringUpWeapon(player); +} + +// +// P_MovePsprites +// Called every tic by player thinking routine. +// + +void P_MovePsprites(player_t *player) +{ + pspdef_t *psp = player->psprites; + int i; + + // a null state means not active + // drop tic count and possibly change state + // a -1 tic count never changes + + for (i=0; istate && psp->tics != -1 && !--psp->tics) + P_SetPsprite(player, i, psp->state->nextstate); + + player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx; + player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy; +} diff --git a/src/p_pspr.h b/src/p_pspr.h new file mode 100644 index 0000000..46d9652 --- /dev/null +++ b/src/p_pspr.h @@ -0,0 +1,119 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Sprite animation. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_PSPR__ +#define __P_PSPR__ + +/* Basic data types. + * Needs fixed point, and BAM angles. */ + +#include "m_fixed.h" +#include "tables.h" + +/* Needs to include the precompiled sprite animation tables. + * + * Header generated by multigen utility. + * This includes all the data for thing animation, + * i.e. the Thing Atrributes table and the Frame Sequence table. + */ + +#include "info.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +/* + * Frame flags: + * handles maximum brightness (torches, muzzle flare, light sources) + */ + +#define FF_FULLBRIGHT 0x8000 /* flag in thing->frame */ +#define FF_FRAMEMASK 0x7fff + +/* + * Overlay psprites are scaled shapes + * drawn directly on the view screen, + * coordinates are given for a 320*200 view screen. + */ + +typedef enum +{ + ps_weapon, + ps_flash, + NUMPSPRITES +} psprnum_t; + +typedef struct +{ + state_t *state; /* a NULL state means not active */ + int tics; + fixed_t sx; + fixed_t sy; +} pspdef_t; + +extern int weapon_preferences[2][NUMWEAPONS+1]; /* killough 5/2/98 */ +int P_WeaponPreferred(int w1, int w2); + +struct player_s; +int P_SwitchWeapon(struct player_s *player); +boolean P_CheckAmmo(struct player_s *player); +void P_SetupPsprites(struct player_s *curplayer); +void P_MovePsprites(struct player_s *curplayer); +void P_DropWeapon(struct player_s *player); + +void A_Light0(); +void A_WeaponReady(); +void A_Lower(); +void A_Raise(); +void A_Punch(); +void A_ReFire(); +void A_FirePistol(); +void A_Light1(); +void A_FireShotgun(); +void A_Light2(); +void A_FireShotgun2(); +void A_CheckReload(); +void A_OpenShotgun2(); +void A_LoadShotgun2(); +void A_CloseShotgun2(); +void A_FireCGun(); +void A_GunFlash(); +void A_FireMissile(); +void A_Saw(); +void A_FirePlasma(); +void A_BFGsound(); +void A_FireBFG(); +void A_BFGSpray(); + +#endif diff --git a/src/p_saveg.c b/src/p_saveg.c new file mode 100644 index 0000000..7e3d63b --- /dev/null +++ b/src/p_saveg.c @@ -0,0 +1,1029 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Archiving: SaveGame I/O. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "r_main.h" +#include "p_maputl.h" +#include "p_spec.h" +#include "p_tick.h" +#include "p_saveg.h" +#include "m_random.h" +#include "am_map.h" +#include "p_enemy.h" +#include "lprintf.h" + +byte *save_p; + +// Pads save_p to a 4-byte boundary +// so that the load/save works on SGI&Gecko. +#define PADSAVEP() do { save_p += (4 - ((int) save_p & 3)) & 3; } while (0) +// +// P_ArchivePlayers +// +void P_ArchivePlayers (void) +{ + int i; + + CheckSaveGame(sizeof(player_t) * MAXPLAYERS); // killough + for (i=0 ; ipsprites[j].state) + dest->psprites[j].state = + (state_t *)(dest->psprites[j].state-states); + } +} + +// +// P_UnArchivePlayers +// +void P_UnArchivePlayers (void) +{ + int i; + + for (i=0 ; ifloorheight + sizeof sec->ceilingheight) + * numsectors + sizeof(short)*3*numlines + 4; + + for (i=0; itextureoffset + sizeof si->rowoffset; + if (lines[i].sidenum[1] != NO_INDEX) + size += + sizeof(short)*3 + sizeof si->textureoffset + sizeof si->rowoffset; + } + + CheckSaveGame(size); // killough + + PADSAVEP(); // killough 3/22/98 + + put = (short *)save_p; + + // do sectors + for (i=0, sec = sectors ; ifloorheight, sizeof sec->floorheight); + put = (void *)((char *) put + sizeof sec->floorheight); + memcpy(put, &sec->ceilingheight, sizeof sec->ceilingheight); + put = (void *)((char *) put + sizeof sec->ceilingheight); + + *put++ = sec->floorpic; + *put++ = sec->ceilingpic; + *put++ = sec->lightlevel; + *put++ = sec->special; // needed? yes -- transfer types + *put++ = sec->tag; // needed? need them -- killough + } + + // do lines + for (i=0, li = lines ; iflags; + *put++ = li->special; + *put++ = li->tag; + + for (j=0; j<2; j++) + if (li->sidenum[j] != NO_INDEX) + { + si = &sides[li->sidenum[j]]; + + // killough 10/98: save full sidedef offsets, + // preserving fractional scroll offsets + + memcpy(put, &si->textureoffset, sizeof si->textureoffset); + put = (void *)((char *) put + sizeof si->textureoffset); + memcpy(put, &si->rowoffset, sizeof si->rowoffset); + put = (void *)((char *) put + sizeof si->rowoffset); + + *put++ = si->toptexture; + *put++ = si->bottomtexture; + *put++ = si->midtexture; + } + } + save_p = (byte *) put; +} + + + +// +// P_UnArchiveWorld +// +void P_UnArchiveWorld (void) +{ + int i; + sector_t *sec; + line_t *li; + const short *get; + + PADSAVEP(); // killough 3/22/98 + + get = (short *) save_p; + + // do sectors + for (i=0, sec = sectors ; ifloorheight, get, sizeof sec->floorheight); + get = (void *)((char *) get + sizeof sec->floorheight); + memcpy(&sec->ceilingheight, get, sizeof sec->ceilingheight); + get = (void *)((char *) get + sizeof sec->ceilingheight); + + sec->floorpic = *get++; + sec->ceilingpic = *get++; + sec->lightlevel = *get++; + sec->special = *get++; + sec->tag = *get++; + sec->ceilingdata = 0; //jff 2/22/98 now three thinker fields, not two + sec->floordata = 0; + sec->lightingdata = 0; + sec->soundtarget = 0; + } + + // do lines + for (i=0, li = lines ; iflags = *get++; + li->special = *get++; + li->tag = *get++; + for (j=0 ; j<2 ; j++) + if (li->sidenum[j] != NO_INDEX) + { + side_t *si = &sides[li->sidenum[j]]; + + // killough 10/98: load full sidedef offsets, including fractions + + memcpy(&si->textureoffset, get, sizeof si->textureoffset); + get = (void *)((char *) get + sizeof si->textureoffset); + memcpy(&si->rowoffset, get, sizeof si->rowoffset); + get = (void *)((char *) get + sizeof si->rowoffset); + + si->toptexture = *get++; + si->bottomtexture = *get++; + si->midtexture = *get++; + } + } + save_p = (byte *) get; +} + +// +// Thinkers +// + +typedef enum { + tc_end, + tc_mobj +} thinkerclass_t; + +// phares 9/13/98: Moved this code outside of P_ArchiveThinkers so the +// thinker indices could be used by the code that saves sector info. + +static int number_of_thinkers; + +void P_ThinkerToIndex(void) + { + thinker_t *th; + + // killough 2/14/98: + // count the number of thinkers, and mark each one with its index, using + // the prev field as a placeholder, since it can be restored later. + + number_of_thinkers = 0; + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + if (th->function == P_MobjThinker) + th->prev = (thinker_t *) ++number_of_thinkers; + } + +// phares 9/13/98: Moved this code outside of P_ArchiveThinkers so the +// thinker indices could be used by the code that saves sector info. + +void P_IndexToThinker(void) + { + // killough 2/14/98: restore prev pointers + thinker_t *th; + thinker_t *prev = &thinkercap; + + for (th = thinkercap.next ; th != &thinkercap ; prev=th, th=th->next) + th->prev = prev; + } + +// +// P_ArchiveThinkers +// +// 2/14/98 killough: substantially modified to fix savegame bugs + +void P_ArchiveThinkers (void) +{ + thinker_t *th; + + CheckSaveGame(sizeof brain); // killough 3/26/98: Save boss brain state + memcpy(save_p, &brain, sizeof brain); + save_p += sizeof brain; + + /* check that enough room is available in savegame buffer + * - killough 2/14/98 + * cph - use number_of_thinkers saved by P_ThinkerToIndex above + * size per object is sizeof(mobj_t) - 2*sizeof(void*) - 4*sizeof(fixed_t) plus + * padded type (4) plus 5*sizeof(void*), i.e. sizeof(mobj_t) + 4 + + * 3*sizeof(void*) + * cph - +1 for the tc_end + */ + CheckSaveGame(number_of_thinkers*(sizeof(mobj_t)-3*sizeof(fixed_t)+4+3*sizeof(void*)) +1); + + // save off the current thinkers + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + if (th->function == P_MobjThinker) + { + mobj_t *mobj; + + *save_p++ = tc_mobj; + PADSAVEP(); + mobj = (mobj_t *)save_p; + /* cph 2006/07/30 - + * The end of mobj_t changed from + * boolean invisible; + * mobj_t* lastenemy; + * mobj_t* above_monster; + * mobj_t* below_monster; + * void* touching_sectorlist; + * to + * mobj_t* lastenemy; + * void* touching_sectorlist; + * fixed_t PrevX, PrevY, PrevZ, padding; + * at prboom 2.4.4. There is code here to preserve the savegame format. + * + * touching_sectorlist is reconstructed anyway, so we now leave off the + * last 2 words of mobj_t, write 5 words of 0 and then write lastenemy + * into the second of these. + */ + memcpy (mobj, th, sizeof(*mobj) - 2*sizeof(void*)); + save_p += sizeof(*mobj) - 2*sizeof(void*) - 4*sizeof(fixed_t); + memset (save_p, 0, 5*sizeof(void*)); + mobj->state = (state_t *)(mobj->state - states); + + // killough 2/14/98: convert pointers into indices. + // Fixes many savegame problems, by properly saving + // target and tracer fields. Note: we store NULL if + // the thinker pointed to by these fields is not a + // mobj thinker. + + if (mobj->target) + mobj->target = mobj->target->thinker.function == + P_MobjThinker ? + (mobj_t *) mobj->target->thinker.prev : NULL; + + if (mobj->tracer) + mobj->tracer = mobj->tracer->thinker.function == + P_MobjThinker ? + (mobj_t *) mobj->tracer->thinker.prev : NULL; + + // killough 2/14/98: new field: save last known enemy. Prevents + // monsters from going to sleep after killing monsters and not + // seeing player anymore. + + if (((mobj_t*)th)->lastenemy && ((mobj_t*)th)->lastenemy->thinker.function == P_MobjThinker) { + memcpy (save_p + sizeof(void*), &(((mobj_t*)th)->lastenemy->thinker.prev), sizeof(void*)); + } + + // killough 2/14/98: end changes + + save_p += 5*sizeof(void*); + + if (mobj->player) + mobj->player = (player_t *)((mobj->player-players) + 1); + } + + // add a terminating marker + *save_p++ = tc_end; + + // killough 9/14/98: save soundtargets + { + int i; + CheckSaveGame(numsectors * sizeof(mobj_t *)); // killough 9/14/98 + for (i = 0; i < numsectors; i++) + { + mobj_t *target = sectors[i].soundtarget; + // Fix crash on reload when a soundtarget points to a removed corpse + // (prboom bug #1590350) + if (target && target->thinker.function == P_MobjThinker) + target = (mobj_t *) target->thinker.prev; + else + target = NULL; + memcpy(save_p, &target, sizeof target); + save_p += sizeof target; + } + } +} + +/* + * killough 11/98 + * + * Same as P_SetTarget() in p_tick.c, except that the target is nullified + * first, so that no old target's reference count is decreased (when loading + * savegames, old targets are indices, not really pointers to targets). + */ + +static void P_SetNewTarget(mobj_t **mop, mobj_t *targ) +{ + *mop = NULL; + P_SetTarget(mop, targ); +} + +// +// P_UnArchiveThinkers +// +// 2/14/98 killough: substantially modified to fix savegame bugs +// + +// savegame file stores ints in the corresponding * field; this function +// safely casts them back to int. +static int P_GetMobj(mobj_t* mi, size_t s) +{ + size_t i = (size_t)mi; + if (i >= s) I_Error("Corrupt savegame"); + return i; +} + +void P_UnArchiveThinkers (void) +{ + thinker_t *th; + mobj_t **mobj_p; // killough 2/14/98: Translation table + size_t size; // killough 2/14/98: size of or index into table + + totallive = 0; + // killough 3/26/98: Load boss brain state + memcpy(&brain, save_p, sizeof brain); + save_p += sizeof brain; + + // remove all the current thinkers + for (th = thinkercap.next; th != &thinkercap; ) + { + thinker_t *next = th->next; + if (th->function == P_MobjThinker) + P_RemoveMobj ((mobj_t *) th); + else + Z_Free (th); + th = next; + } + P_InitThinkers (); + + // killough 2/14/98: count number of thinkers by skipping through them + { + byte *sp = save_p; // save pointer and skip header + for (size = 1; *save_p++ == tc_mobj; size++) // killough 2/14/98 + { // skip all entries, adding up count + PADSAVEP(); + /* cph 2006/07/30 - see comment below for change in layout of mobj_t */ + save_p += sizeof(mobj_t)+3*sizeof(void*)-4*sizeof(fixed_t); + } + + if (*--save_p != tc_end) + I_Error ("P_UnArchiveThinkers: Unknown tclass %i in savegame", *save_p); + + // first table entry special: 0 maps to NULL + *(mobj_p = malloc(size * sizeof *mobj_p)) = 0; // table of pointers + save_p = sp; // restore save pointer + } + + // read in saved thinkers + for (size = 1; *save_p++ == tc_mobj; size++) // killough 2/14/98 + { + mobj_t *mobj = Z_Malloc(sizeof(mobj_t), PU_LEVEL, NULL); + + // killough 2/14/98 -- insert pointers to thinkers into table, in order: + mobj_p[size] = mobj; + + PADSAVEP(); + /* cph 2006/07/30 - + * The end of mobj_t changed from + * boolean invisible; + * mobj_t* lastenemy; + * mobj_t* above_monster; + * mobj_t* below_monster; + * void* touching_sectorlist; + * to + * mobj_t* lastenemy; + * void* touching_sectorlist; + * fixed_t PrevX, PrevY, PrevZ; + * at prboom 2.4.4. There is code here to preserve the savegame format. + * + * touching_sectorlist is reconstructed anyway, so we now read in all + * but the last 5 words from the savegame (filling all but the last 2 + * fields of our current mobj_t. We then pull lastenemy from the 2nd of + * the 5 leftover words, and skip the others. + */ + memcpy (mobj, save_p, sizeof(mobj_t)-2*sizeof(void*)-4*sizeof(fixed_t)); + save_p += sizeof(mobj_t)-sizeof(void*)-4*sizeof(fixed_t); + memcpy (&(mobj->lastenemy), save_p, sizeof(void*)); + save_p += 4*sizeof(void*); + mobj->state = states + (int) mobj->state; + + if (mobj->player) + (mobj->player = &players[(int) mobj->player - 1]) -> mo = mobj; + + P_SetThingPosition (mobj); + mobj->info = &mobjinfo[mobj->type]; + + // killough 2/28/98: + // Fix for falling down into a wall after savegame loaded: + // mobj->floorz = mobj->subsector->sector->floorheight; + // mobj->ceilingz = mobj->subsector->sector->ceilingheight; + + mobj->thinker.function = P_MobjThinker; + P_AddThinker (&mobj->thinker); + + if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL | MF_CORPSE))) + totallive++; + } + + // killough 2/14/98: adjust target and tracer fields, plus + // lastenemy field, to correctly point to mobj thinkers. + // NULL entries automatically handled by first table entry. + // + // killough 11/98: use P_SetNewTarget() to set fields + + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + { + P_SetNewTarget(&((mobj_t *) th)->target, + mobj_p[P_GetMobj(((mobj_t *)th)->target,size)]); + + P_SetNewTarget(&((mobj_t *) th)->tracer, + mobj_p[P_GetMobj(((mobj_t *)th)->tracer,size)]); + + P_SetNewTarget(&((mobj_t *) th)->lastenemy, + mobj_p[P_GetMobj(((mobj_t *)th)->lastenemy,size)]); + } + + { // killough 9/14/98: restore soundtargets + int i; + for (i = 0; i < numsectors; i++) + { + mobj_t *target; + memcpy(&target, save_p, sizeof target); + save_p += sizeof target; + // Must verify soundtarget. See P_ArchiveThinkers. + P_SetNewTarget(§ors[i].soundtarget, mobj_p[P_GetMobj(target,size)]); + } + } + + free(mobj_p); // free translation table + + // killough 3/26/98: Spawn icon landings: + if (gamemode == commercial) + P_SpawnBrainTargets(); +} + +// +// P_ArchiveSpecials +// +enum { + tc_ceiling, + tc_door, + tc_floor, + tc_plat, + tc_flash, + tc_strobe, + tc_glow, + tc_elevator, //jff 2/22/98 new elevator type thinker + tc_scroll, // killough 3/7/98: new scroll effect thinker + tc_pusher, // phares 3/22/98: new push/pull effect thinker + tc_flicker, // killough 10/4/98 + tc_endspecials +} specials_e; + +// +// Things to handle: +// +// T_MoveCeiling, (ceiling_t: sector_t * swizzle), - active list +// T_VerticalDoor, (vldoor_t: sector_t * swizzle), +// T_MoveFloor, (floormove_t: sector_t * swizzle), +// T_LightFlash, (lightflash_t: sector_t * swizzle), +// T_StrobeFlash, (strobe_t: sector_t *), +// T_Glow, (glow_t: sector_t *), +// T_PlatRaise, (plat_t: sector_t *), - active list +// T_MoveElevator, (plat_t: sector_t *), - active list // jff 2/22/98 +// T_Scroll // killough 3/7/98 +// T_Pusher // phares 3/22/98 +// T_FireFlicker // killough 10/4/98 +// + +void P_ArchiveSpecials (void) +{ + thinker_t *th; + size_t size = 0; // killough + + // save off the current thinkers (memory size calculation -- killough) + + for (th = thinkercap.next ; th != &thinkercap ; th=th->next) + if (!th->function) + { + platlist_t *pl; + ceilinglist_t *cl; //jff 2/22/98 need this for ceilings too now + for (pl=activeplats; pl; pl=pl->next) + if (pl->plat == (plat_t *) th) // killough 2/14/98 + { + size += 4+sizeof(plat_t); + goto end; + } + for (cl=activeceilings; cl; cl=cl->next) // search for activeceiling + if (cl->ceiling == (ceiling_t *) th) //jff 2/22/98 + { + size += 4+sizeof(ceiling_t); + goto end; + } + end:; + } + else + size += + th->function==T_MoveCeiling ? 4+sizeof(ceiling_t) : + th->function==T_VerticalDoor ? 4+sizeof(vldoor_t) : + th->function==T_MoveFloor ? 4+sizeof(floormove_t): + th->function==T_PlatRaise ? 4+sizeof(plat_t) : + th->function==T_LightFlash ? 4+sizeof(lightflash_t): + th->function==T_StrobeFlash ? 4+sizeof(strobe_t) : + th->function==T_Glow ? 4+sizeof(glow_t) : + th->function==T_MoveElevator ? 4+sizeof(elevator_t): + th->function==T_Scroll ? 4+sizeof(scroll_t) : + th->function==T_Pusher ? 4+sizeof(pusher_t) : + th->function==T_FireFlicker? 4+sizeof(fireflicker_t) : + 0; + + CheckSaveGame(size + 1); // killough; cph: +1 for the tc_endspecials + + // save off the current thinkers + for (th=thinkercap.next; th!=&thinkercap; th=th->next) + { + if (!th->function) + { + platlist_t *pl; + ceilinglist_t *cl; //jff 2/22/98 add iter variable for ceilings + + // killough 2/8/98: fix plat original height bug. + // Since acv==NULL, this could be a plat in stasis. + // so check the active plats list, and save this + // plat (jff: or ceiling) even if it is in stasis. + + for (pl=activeplats; pl; pl=pl->next) + if (pl->plat == (plat_t *) th) // killough 2/14/98 + goto plat; + + for (cl=activeceilings; cl; cl=cl->next) + if (cl->ceiling == (ceiling_t *) th) //jff 2/22/98 + goto ceiling; + + continue; + } + + if (th->function == T_MoveCeiling) + { + ceiling_t *ceiling; + ceiling: // killough 2/14/98 + *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); + continue; + } + + if (th->function == T_VerticalDoor) + { + vldoor_t *door; + *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); + //jff 1/31/98 archive line remembered by door as well + door->line = (line_t *) (door->line ? door->line-lines : -1); + continue; + } + + if (th->function == T_MoveFloor) + { + floormove_t *floor; + *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); + continue; + } + + if (th->function == T_PlatRaise) + { + plat_t *plat; + plat: // killough 2/14/98: added fix for original plat height above + *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); + continue; + } + + if (th->function == T_LightFlash) + { + lightflash_t *flash; + *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); + continue; + } + + if (th->function == T_StrobeFlash) + { + strobe_t *strobe; + *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); + continue; + } + + if (th->function == T_Glow) + { + glow_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); + continue; + } + + // killough 10/4/98: save flickers + if (th->function == T_FireFlicker) + { + fireflicker_t *flicker; + *save_p++ = tc_flicker; + PADSAVEP(); + flicker = (fireflicker_t *)save_p; + memcpy (flicker, th, sizeof(*flicker)); + save_p += sizeof(*flicker); + flicker->sector = (sector_t *)(flicker->sector - sectors); + continue; + } + + //jff 2/22/98 new case for elevators + if (th->function == T_MoveElevator) + { + elevator_t *elevator; //jff 2/22/98 + *save_p++ = tc_elevator; + PADSAVEP(); + elevator = (elevator_t *)save_p; + memcpy (elevator, th, sizeof(*elevator)); + save_p += sizeof(*elevator); + elevator->sector = (sector_t *)(elevator->sector - sectors); + continue; + } + + // killough 3/7/98: Scroll effect thinkers + if (th->function == T_Scroll) + { + *save_p++ = tc_scroll; + memcpy (save_p, th, sizeof(scroll_t)); + save_p += sizeof(scroll_t); + continue; + } + + // phares 3/22/98: Push/Pull effect thinkers + + if (th->function == T_Pusher) + { + *save_p++ = tc_pusher; + memcpy (save_p, th, sizeof(pusher_t)); + save_p += sizeof(pusher_t); + continue; + } + } + + // add a terminating marker + *save_p++ = tc_endspecials; +} + + +// +// P_UnArchiveSpecials +// +void P_UnArchiveSpecials (void) +{ + byte tclass; + + // read in saved thinkers + while ((tclass = *save_p++) != tc_endspecials) // killough 2/14/98 + switch (tclass) + { + case tc_ceiling: + PADSAVEP(); + { + ceiling_t *ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVEL, NULL); + memcpy (ceiling, save_p, sizeof(*ceiling)); + save_p += sizeof(*ceiling); + ceiling->sector = §ors[(int)ceiling->sector]; + ceiling->sector->ceilingdata = ceiling; //jff 2/22/98 + + if (ceiling->thinker.function) + ceiling->thinker.function = T_MoveCeiling; + + P_AddThinker (&ceiling->thinker); + P_AddActiveCeiling(ceiling); + break; + } + + case tc_door: + PADSAVEP(); + { + vldoor_t *door = Z_Malloc (sizeof(*door), PU_LEVEL, NULL); + memcpy (door, save_p, sizeof(*door)); + save_p += sizeof(*door); + door->sector = §ors[(int)door->sector]; + + //jff 1/31/98 unarchive line remembered by door as well + door->line = (int)door->line!=-1? &lines[(int)door->line] : NULL; + + door->sector->ceilingdata = door; //jff 2/22/98 + door->thinker.function = T_VerticalDoor; + P_AddThinker (&door->thinker); + break; + } + + case tc_floor: + PADSAVEP(); + { + floormove_t *floor = Z_Malloc (sizeof(*floor), PU_LEVEL, NULL); + memcpy (floor, save_p, sizeof(*floor)); + save_p += sizeof(*floor); + floor->sector = §ors[(int)floor->sector]; + floor->sector->floordata = floor; //jff 2/22/98 + floor->thinker.function = T_MoveFloor; + P_AddThinker (&floor->thinker); + break; + } + + case tc_plat: + PADSAVEP(); + { + plat_t *plat = Z_Malloc (sizeof(*plat), PU_LEVEL, NULL); + memcpy (plat, save_p, sizeof(*plat)); + save_p += sizeof(*plat); + plat->sector = §ors[(int)plat->sector]; + plat->sector->floordata = plat; //jff 2/22/98 + + if (plat->thinker.function) + plat->thinker.function = T_PlatRaise; + + P_AddThinker (&plat->thinker); + P_AddActivePlat(plat); + break; + } + + case tc_flash: + PADSAVEP(); + { + lightflash_t *flash = Z_Malloc (sizeof(*flash), PU_LEVEL, NULL); + memcpy (flash, save_p, sizeof(*flash)); + save_p += sizeof(*flash); + flash->sector = §ors[(int)flash->sector]; + flash->thinker.function = T_LightFlash; + P_AddThinker (&flash->thinker); + break; + } + + case tc_strobe: + PADSAVEP(); + { + strobe_t *strobe = Z_Malloc (sizeof(*strobe), PU_LEVEL, NULL); + memcpy (strobe, save_p, sizeof(*strobe)); + save_p += sizeof(*strobe); + strobe->sector = §ors[(int)strobe->sector]; + strobe->thinker.function = T_StrobeFlash; + P_AddThinker (&strobe->thinker); + break; + } + + case tc_glow: + PADSAVEP(); + { + glow_t *glow = Z_Malloc (sizeof(*glow), PU_LEVEL, NULL); + memcpy (glow, save_p, sizeof(*glow)); + save_p += sizeof(*glow); + glow->sector = §ors[(int)glow->sector]; + glow->thinker.function = T_Glow; + P_AddThinker (&glow->thinker); + break; + } + + case tc_flicker: // killough 10/4/98 + PADSAVEP(); + { + fireflicker_t *flicker = Z_Malloc (sizeof(*flicker), PU_LEVEL, NULL); + memcpy (flicker, save_p, sizeof(*flicker)); + save_p += sizeof(*flicker); + flicker->sector = §ors[(int)flicker->sector]; + flicker->thinker.function = T_FireFlicker; + P_AddThinker (&flicker->thinker); + break; + } + + //jff 2/22/98 new case for elevators + case tc_elevator: + PADSAVEP(); + { + elevator_t *elevator = Z_Malloc (sizeof(*elevator), PU_LEVEL, NULL); + memcpy (elevator, save_p, sizeof(*elevator)); + save_p += sizeof(*elevator); + elevator->sector = §ors[(int)elevator->sector]; + elevator->sector->floordata = elevator; //jff 2/22/98 + elevator->sector->ceilingdata = elevator; //jff 2/22/98 + elevator->thinker.function = T_MoveElevator; + P_AddThinker (&elevator->thinker); + break; + } + + case tc_scroll: // killough 3/7/98: scroll effect thinkers + { + scroll_t *scroll = Z_Malloc (sizeof(scroll_t), PU_LEVEL, NULL); + memcpy (scroll, save_p, sizeof(scroll_t)); + save_p += sizeof(scroll_t); + scroll->thinker.function = T_Scroll; + P_AddThinker(&scroll->thinker); + break; + } + + case tc_pusher: // phares 3/22/98: new Push/Pull effect thinkers + { + pusher_t *pusher = Z_Malloc (sizeof(pusher_t), PU_LEVEL, NULL); + memcpy (pusher, save_p, sizeof(pusher_t)); + save_p += sizeof(pusher_t); + pusher->thinker.function = T_Pusher; + pusher->source = P_GetPushThing(pusher->affectee); + P_AddThinker(&pusher->thinker); + break; + } + + default: + I_Error("P_UnarchiveSpecials: Unknown tclass %i in savegame", tclass); + } +} + +// killough 2/16/98: save/restore random number generator state information + +void P_ArchiveRNG(void) +{ + CheckSaveGame(sizeof rng); + memcpy(save_p, &rng, sizeof rng); + save_p += sizeof rng; +} + +void P_UnArchiveRNG(void) +{ + memcpy(&rng, save_p, sizeof rng); + save_p += sizeof rng; +} + +// killough 2/22/98: Save/restore automap state +// killough 2/22/98: Save/restore automap state +void P_ArchiveMap(void) +{ + int zero = 0, one = 1; + CheckSaveGame(2 * sizeof zero + sizeof markpointnum + + markpointnum * sizeof *markpoints + + sizeof automapmode + sizeof one); + + memcpy(save_p, &automapmode, sizeof automapmode); + save_p += sizeof automapmode; + memcpy(save_p, &one, sizeof one); // CPhipps - used to be viewactive, now + save_p += sizeof one; // that's worked out locally by D_Display + memcpy(save_p, &zero, sizeof zero); // CPhipps - used to be followplayer + save_p += sizeof zero; // that is now part of automapmode + memcpy(save_p, &zero, sizeof zero); // CPhipps - used to be automap_grid, ditto + save_p += sizeof zero; + memcpy(save_p, &markpointnum, sizeof markpointnum); + save_p += sizeof markpointnum; + + if (markpointnum) + { + memcpy(save_p, markpoints, sizeof *markpoints * markpointnum); + save_p += markpointnum * sizeof *markpoints; + } +} + +void P_UnArchiveMap(void) +{ + int unused; + memcpy(&automapmode, save_p, sizeof automapmode); + save_p += sizeof automapmode; + memcpy(&unused, save_p, sizeof unused); + save_p += sizeof unused; + memcpy(&unused, save_p, sizeof unused); + save_p += sizeof unused; + memcpy(&unused, save_p, sizeof unused); + save_p += sizeof unused; + + if (automapmode & am_active) + AM_Start(); + + memcpy(&markpointnum, save_p, sizeof markpointnum); + save_p += sizeof markpointnum; + + if (markpointnum) + { + while (markpointnum >= markpointnum_max) + markpoints = realloc(markpoints, sizeof *markpoints * + (markpointnum_max = markpointnum_max ? markpointnum_max*2 : 16)); + memcpy(markpoints, save_p, markpointnum * sizeof *markpoints); + save_p += markpointnum * sizeof *markpoints; + } +} + diff --git a/src/p_saveg.h b/src/p_saveg.h new file mode 100644 index 0000000..dd986cf --- /dev/null +++ b/src/p_saveg.h @@ -0,0 +1,66 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Savegame I/O, archiving, persistence. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_SAVEG__ +#define __P_SAVEG__ + +#ifdef __GNUG__ +#pragma interface +#endif + +/* Persistent storage/archiving. + * These are the load / save game routines. */ +void P_ArchivePlayers(void); +void P_UnArchivePlayers(void); +void P_ArchiveWorld(void); +void P_UnArchiveWorld(void); +void P_ArchiveThinkers(void); +void P_UnArchiveThinkers(void); +void P_ArchiveSpecials(void); +void P_UnArchiveSpecials(void); +void P_ThinkerToIndex(void); /* phares 9/13/98: save soundtarget in savegame */ +void P_IndexToThinker(void); /* phares 9/13/98: save soundtarget in savegame */ + +/* 1/18/98 killough: add RNG info to savegame */ +void P_ArchiveRNG(void); +void P_UnArchiveRNG(void); + +/* 2/21/98 killough: add automap info to savegame */ +void P_ArchiveMap(void); +void P_UnArchiveMap(void); + +extern byte *save_p; +void CheckSaveGame(size_t,const char*, int); /* killough */ +#define CheckSaveGame(a) (CheckSaveGame)(a, __FILE__, __LINE__) + +#endif diff --git a/src/p_setup.c b/src/p_setup.c new file mode 100644 index 0000000..5247cb9 --- /dev/null +++ b/src/p_setup.c @@ -0,0 +1,1688 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Do all the WAD I/O, get map description, + * set up initial state and misc. LUTs. + * + *-----------------------------------------------------------------------------*/ + +#include + +#include "doomstat.h" +#include "m_bbox.h" +#include "m_argv.h" +#include "g_game.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_things.h" +#include "p_maputl.h" +#include "p_map.h" +#include "p_setup.h" +#include "p_spec.h" +#include "p_tick.h" +#include "p_enemy.h" +#include "s_sound.h" +#include "lprintf.h" //jff 10/6/98 for debug outputs +#include "v_video.h" +#include "r_demo.h" +#include "r_fps.h" + +// +// MAP related Lookup tables. +// Store VERTEXES, LINEDEFS, SIDEDEFS, etc. +// + +int numvertexes; +vertex_t *vertexes; + +int numsegs; +seg_t *segs; + +int numsectors; +sector_t *sectors; + +int numsubsectors; +subsector_t *subsectors; + +int numnodes; +node_t *nodes; + +int numlines; +line_t *lines; + +int numsides; +side_t *sides; + + +//////////////////////////////////////////////////////////////////////////////////////////// +// figgi 08/21/00 -- constants and globals for glBsp support +#define gNd2 0x32644E67 // figgi -- suppport for new GL_VERT format v2.0 +#define gNd3 0x33644E67 +#define gNd4 0x34644E67 +#define gNd5 0x35644E67 +#define ZNOD 0x444F4E5A +#define ZGLN 0x4E4C475A +#define GL_VERT_OFFSET 4 + +int firstglvertex = 0; +int nodesVersion = 0; +boolean forceOldBsp = false; + +// figgi 08/21/00 -- glSegs +typedef struct +{ + unsigned short v1; // start vertex (16 bit) + unsigned short v2; // end vertex (16 bit) + unsigned short linedef; // linedef, or -1 for minisegs + short side; // side on linedef: 0 for right, 1 for left + unsigned short partner; // corresponding partner seg, or -1 on one-sided walls +} glseg_t; + +// fixed 32 bit gl_vert format v2.0+ (glBsp 1.91) +typedef struct +{ + fixed_t x,y; +} mapglvertex_t; + +enum +{ + ML_GL_LABEL=0, // A separator name, GL_ExMx or GL_MAPxx + ML_GL_VERTS, // Extra Vertices + ML_GL_SEGS, // Segs, from linedefs & minisegs + ML_GL_SSECT, // SubSectors, list of segs + ML_GL_NODES // GL BSP nodes +}; +//////////////////////////////////////////////////////////////////////////////////////////// + + +// BLOCKMAP +// Created from axis aligned bounding box +// of the map, a rectangular array of +// blocks of size ... +// Used to speed up collision detection +// by spatial subdivision in 2D. +// +// Blockmap size. + +int bmapwidth, bmapheight; // size in mapblocks + +// killough 3/1/98: remove blockmap limit internally: +long *blockmap; // was short -- killough + +// offsets in blockmap are from here +long *blockmaplump; // was short -- killough + +fixed_t bmaporgx, bmaporgy; // origin of block map + +mobj_t **blocklinks; // for thing chains + +// +// REJECT +// For fast sight rejection. +// Speeds up enemy AI by skipping detailed +// LineOf Sight calculation. +// Without the special effect, this could +// be used as a PVS lookup as well. +// + +static int rejectlump = -1;// cph - store reject lump num if cached +const byte *rejectmatrix; // cph - const* + +// Maintain single and multi player starting spots. + +// 1/11/98 killough: Remove limit on deathmatch starts +mapthing_t *deathmatchstarts; // killough +size_t num_deathmatchstarts; // killough + +mapthing_t *deathmatch_p; +mapthing_t playerstarts[MAXPLAYERS]; + +// +// P_CheckForZDoomNodes +// + +static boolean P_CheckForZDoomNodes(int lumpnum, int gl_lumpnum) +{ + const void *data; + + data = W_CacheLumpNum(lumpnum + ML_NODES); + if (*(const int *)data == ZNOD) + I_Error("P_CheckForZDoomNodes: ZDoom nodes not supported yet"); + + data = W_CacheLumpNum(lumpnum + ML_SSECTORS); + if (*(const int *)data == ZGLN) + I_Error("P_CheckForZDoomNodes: ZDoom GL nodes not supported yet"); + + return false; +} + +// +// P_GetNodesVersion +// + +static void P_GetNodesVersion(int lumpnum, int gl_lumpnum) +{ + const void *data; + + data = W_CacheLumpNum(gl_lumpnum+ML_GL_VERTS); + if ( (gl_lumpnum > lumpnum) && (forceOldBsp == false) && (compatibility_level >= prboom_2_compatibility) ) { + if (*(const int *)data == gNd2) { + data = W_CacheLumpNum(gl_lumpnum+ML_GL_SEGS); + if (*(const int *)data == gNd3) { + nodesVersion = gNd3; + lprintf(LO_DEBUG, "P_GetNodesVersion: found version 3 nodes\n"); + I_Error("P_GetNodesVersion: version 3 nodes not supported\n"); + } else { + nodesVersion = gNd2; + lprintf(LO_DEBUG, "P_GetNodesVersion: found version 2 nodes\n"); + } + } + if (*(const int *)data == gNd4) { + nodesVersion = gNd4; + lprintf(LO_DEBUG, "P_GetNodesVersion: found version 4 nodes\n"); + I_Error("P_GetNodesVersion: version 4 nodes not supported\n"); + } + if (*(const int *)data == gNd5) { + nodesVersion = gNd5; + lprintf(LO_DEBUG, "P_GetNodesVersion: found version 5 nodes\n"); + I_Error("P_GetNodesVersion: version 5 nodes not supported\n"); + } + } else { + nodesVersion = 0; + lprintf(LO_DEBUG,"P_GetNodesVersion: using normal BSP nodes\n"); + if (P_CheckForZDoomNodes(lumpnum, gl_lumpnum)) + I_Error("P_GetNodesVersion: ZDoom nodes not supported yet"); + } +} + +// +// P_LoadVertexes +// +// killough 5/3/98: reformatted, cleaned up +// +static void P_LoadVertexes (int lump) +{ + const mapvertex_t *data; // cph - const + int i; + + // Determine number of lumps: + // total lump length / vertex record length. + numvertexes = W_LumpLength(lump) / sizeof(mapvertex_t); + + // Allocate zone memory for buffer. + vertexes = Z_Malloc(numvertexes*sizeof(vertex_t),PU_LEVEL,0); + + // Load data into cache. + // cph 2006/07/29 - cast to mapvertex_t here, making the loop below much neater + data = (const mapvertex_t *)W_CacheLumpNum(lump); + + // Copy and convert vertex coordinates, + // internal representation as fixed. + for (i=0; i= 0) // check for glVertices + { + gldata = W_CacheLumpNum(gllump); + + if (nodesVersion == gNd2) // 32 bit GL_VERT format (16.16 fixed) + { + const mapglvertex_t* mgl; + + numvertexes += (W_LumpLength(gllump) - GL_VERT_OFFSET)/sizeof(mapglvertex_t); + vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0); + mgl = (const mapglvertex_t *) (gldata + GL_VERT_OFFSET); + + for (i = firstglvertex; i < numvertexes; i++) + { + vertexes[i].x = mgl->x; + vertexes[i].y = mgl->y; + mgl++; + } + } + else + { + numvertexes += W_LumpLength(gllump)/sizeof(mapvertex_t); + vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0); + ml = (const mapvertex_t *)gldata; + + for (i = firstglvertex; i < numvertexes; i++) + { + vertexes[i].x = SHORT(ml->x)<y)<x)<y)<x - v2->x) / (float)FRACUNIT; + b = (float)(v1->y - v2->y) / (float)FRACUNIT; + r = (int)(sqrt(a*a+b*b) * (float)FRACUNIT); + return r; +} + + + +// +// P_LoadSegs +// +// killough 5/3/98: reformatted, cleaned up + +static void P_LoadSegs (int lump) +{ + int i; + const mapseg_t *data; // cph - const + + numsegs = W_LumpLength(lump) / sizeof(mapseg_t); + segs = Z_Calloc(numsegs,sizeof(seg_t),PU_LEVEL,0); + data = (const mapseg_t *)W_CacheLumpNum(lump); // cph - wad lump handling updated + + if ((!data) || (!numsegs)) + I_Error("P_LoadSegs: no segs in level"); + + for (i=0; iiSegID = i; // proff 11/05/2000: needed for OpenGL + + v1 = (unsigned short)SHORT(ml->v1); + v2 = (unsigned short)SHORT(ml->v2); + li->v1 = &vertexes[v1]; + li->v2 = &vertexes[v2]; + + li->miniseg = false; // figgi -- there are no minisegs in classic BSP nodes + li->length = GetDistance(li->v2->x - li->v1->x, li->v2->y - li->v1->y); + li->angle = (SHORT(ml->angle))<<16; + li->offset =(SHORT(ml->offset))<<16; + linedef = (unsigned short)SHORT(ml->linedef); + ldef = &lines[linedef]; + li->linedef = ldef; + side = SHORT(ml->side); + li->sidedef = &sides[ldef->sidenum[side]]; + + /* cph 2006/09/30 - our frontsector can be the second side of the + * linedef, so must check for NO_INDEX in case we are incorrectly + * referencing the back of a 1S line */ + if (ldef->sidenum[side] != NO_INDEX) + li->frontsector = sides[ldef->sidenum[side]].sector; + else { + li->frontsector = 0; + lprintf(LO_WARN, "P_LoadSegs: front of seg %i has no sidedef\n", i); + } + + if (ldef->flags & ML_TWOSIDED && ldef->sidenum[side^1]!=NO_INDEX) + li->backsector = sides[ldef->sidenum[side^1]].sector; + else + li->backsector = 0; + } + + W_UnlockLumpNum(lump); // cph - release the data +} + + + +/******************************************* + * Name : P_LoadGLSegs * + * created : 08/13/00 * + * modified : 09/18/00, adapted for PrBoom * + * author : figgi * + * what : support for gl nodes * + *******************************************/ +static void P_LoadGLSegs(int lump) +{ + int i; + const glseg_t *ml; + line_t *ldef; + + numsegs = W_LumpLength(lump) / sizeof(glseg_t); + segs = Z_Malloc(numsegs * sizeof(seg_t), PU_LEVEL, 0); + memset(segs, 0, numsegs * sizeof(seg_t)); + ml = (const glseg_t*)W_CacheLumpNum(lump); + + if ((!ml) || (!numsegs)) + I_Error("P_LoadGLSegs: no glsegs in level"); + + for(i = 0; i < numsegs; i++) + { // check for gl-vertices + segs[i].v1 = &vertexes[checkGLVertex(SHORT(ml->v1))]; + segs[i].v2 = &vertexes[checkGLVertex(SHORT(ml->v2))]; + segs[i].iSegID = i; + + if(ml->linedef != (unsigned short)-1) // skip minisegs + { + ldef = &lines[ml->linedef]; + segs[i].linedef = ldef; + segs[i].miniseg = false; + segs[i].angle = R_PointToAngle2(segs[i].v1->x,segs[i].v1->y,segs[i].v2->x,segs[i].v2->y); + + segs[i].sidedef = &sides[ldef->sidenum[ml->side]]; + segs[i].length = GetDistance(segs[i].v2->x - segs[i].v1->x, segs[i].v2->y - segs[i].v1->y); + segs[i].frontsector = sides[ldef->sidenum[ml->side]].sector; + if (ldef->flags & ML_TWOSIDED) + segs[i].backsector = sides[ldef->sidenum[ml->side^1]].sector; + else + segs[i].backsector = 0; + + if (ml->side) + segs[i].offset = GetOffset(segs[i].v1, ldef->v2); + else + segs[i].offset = GetOffset(segs[i].v1, ldef->v1); + } + else + { + segs[i].miniseg = true; + segs[i].angle = 0; + segs[i].offset = 0; + segs[i].length = 0; + segs[i].linedef = NULL; + segs[i].sidedef = NULL; + segs[i].frontsector = NULL; + segs[i].backsector = NULL; + } + ml++; + } + W_UnlockLumpNum(lump); +} + +// +// P_LoadSubsectors +// +// killough 5/3/98: reformatted, cleaned up + +static void P_LoadSubsectors (int lump) +{ + /* cph 2006/07/29 - make data a const mapsubsector_t *, so the loop below is simpler & gives no constness warnings */ + const mapsubsector_t *data; + int i; + + numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t); + subsectors = Z_Calloc(numsubsectors,sizeof(subsector_t),PU_LEVEL,0); + data = (const mapsubsector_t *)W_CacheLumpNum(lump); + + if ((!data) || (!numsubsectors)) + I_Error("P_LoadSubsectors: no subsectors in level"); + + for (i=0; iiSectorID=i; // proff 04/05/2000: needed for OpenGL + ss->floorheight = SHORT(ms->floorheight)<ceilingheight = SHORT(ms->ceilingheight)<floorpic = R_FlatNumForName(ms->floorpic); + ss->ceilingpic = R_FlatNumForName(ms->ceilingpic); + ss->lightlevel = SHORT(ms->lightlevel); + ss->special = SHORT(ms->special); + ss->oldspecial = SHORT(ms->special); + ss->tag = SHORT(ms->tag); + ss->thinglist = NULL; + ss->touching_thinglist = NULL; // phares 3/14/98 + + ss->nextsec = -1; //jff 2/26/98 add fields to support locking out + ss->prevsec = -1; // stair retriggering until build completes + + // killough 3/7/98: + ss->floor_xoffs = 0; + ss->floor_yoffs = 0; // floor and ceiling flats offsets + ss->ceiling_xoffs = 0; + ss->ceiling_yoffs = 0; + ss->heightsec = -1; // sector used to get floor and ceiling height + ss->floorlightsec = -1; // sector used to get floor lighting + // killough 3/7/98: end changes + + // killough 4/11/98 sector used to get ceiling lighting: + ss->ceilinglightsec = -1; + + // killough 4/4/98: colormaps: + ss->bottommap = ss->midmap = ss->topmap = 0; + + // killough 10/98: sky textures coming from sidedefs: + ss->sky = 0; + } + + W_UnlockLumpNum(lump); // cph - release the data +} + + +// +// P_LoadNodes +// +// killough 5/3/98: reformatted, cleaned up + +static void P_LoadNodes (int lump) +{ + const byte *data; // cph - const* + int i; + + numnodes = W_LumpLength (lump) / sizeof(mapnode_t); + nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0); + data = W_CacheLumpNum (lump); // cph - wad lump handling updated + + if ((!data) || (!numnodes)) + { + // allow trivial maps + if (numsubsectors == 1) + lprintf(LO_INFO, + "P_LoadNodes: trivial map (no nodes, one subsector)\n"); + else + I_Error("P_LoadNodes: no nodes in level"); + } + + for (i=0; ix = SHORT(mn->x)<y = SHORT(mn->y)<dx = SHORT(mn->dx)<dy = SHORT(mn->dy)<children[j] = SHORT(mn->children[j]); + for (k=0 ; k<4 ; k++) + no->bbox[j][k] = SHORT(mn->bbox[j][k])<flags = (unsigned short)SHORT(mld->flags); + ld->special = SHORT(mld->special); + ld->tag = SHORT(mld->tag); + v1 = ld->v1 = &vertexes[(unsigned short)SHORT(mld->v1)]; + v2 = ld->v2 = &vertexes[(unsigned short)SHORT(mld->v2)]; + ld->dx = v2->x - v1->x; + ld->dy = v2->y - v1->y; + + ld->tranlump = -1; // killough 4/11/98: no translucency by default + + ld->slopetype = !ld->dx ? ST_VERTICAL : !ld->dy ? ST_HORIZONTAL : + FixedDiv(ld->dy, ld->dx) > 0 ? ST_POSITIVE : ST_NEGATIVE; + + if (v1->x < v2->x) + { + ld->bbox[BOXLEFT] = v1->x; + ld->bbox[BOXRIGHT] = v2->x; + } + else + { + ld->bbox[BOXLEFT] = v2->x; + ld->bbox[BOXRIGHT] = v1->x; + } + if (v1->y < v2->y) + { + ld->bbox[BOXBOTTOM] = v1->y; + ld->bbox[BOXTOP] = v2->y; + } + else + { + ld->bbox[BOXBOTTOM] = v2->y; + ld->bbox[BOXTOP] = v1->y; + } + + /* calculate sound origin of line to be its midpoint */ + //e6y: fix sound origin for large levels + // no need for comp_sound test, these are only used when comp_sound = 0 + ld->soundorg.x = ld->bbox[BOXLEFT] / 2 + ld->bbox[BOXRIGHT] / 2; + ld->soundorg.y = ld->bbox[BOXTOP] / 2 + ld->bbox[BOXBOTTOM] / 2; + + ld->iLineID=i; // proff 04/05/2000: needed for OpenGL + ld->sidenum[0] = SHORT(mld->sidenum[0]); + ld->sidenum[1] = SHORT(mld->sidenum[1]); + + { + /* cph 2006/09/30 - fix sidedef errors right away. + * cph 2002/07/20 - these errors are fatal if not fixed, so apply them + * in compatibility mode - a desync is better than a crash! */ + int j; + + for (j=0; j < 2; j++) + { + if (ld->sidenum[j] != NO_INDEX && ld->sidenum[j] >= numsides) { + ld->sidenum[j] = NO_INDEX; + lprintf(LO_WARN, "P_LoadLineDefs: linedef %d has out-of-range sidedef number\n",numlines-i-1); + } + } + + // killough 11/98: fix common wad errors (missing sidedefs): + + if (ld->sidenum[0] == NO_INDEX) { + ld->sidenum[0] = 0; // Substitute dummy sidedef for missing right side + // cph - print a warning about the bug + lprintf(LO_WARN, "P_LoadLineDefs: linedef %d missing first sidedef\n",numlines-i-1); + } + + if ((ld->sidenum[1] == NO_INDEX) && (ld->flags & ML_TWOSIDED)) { + ld->flags &= ~ML_TWOSIDED; // Clear 2s flag for missing left side + // cph - print a warning about the bug + lprintf(LO_WARN, "P_LoadLineDefs: linedef %d has two-sided flag set, but no second sidedef\n",numlines-i-1); + } + } + + // killough 4/4/98: support special sidedef interpretation below + if (ld->sidenum[0] != NO_INDEX && ld->special) + sides[*ld->sidenum].special = ld->special; + } + + W_UnlockLumpNum(lump); // cph - release the lump +} + +// killough 4/4/98: delay using sidedefs until they are loaded +// killough 5/3/98: reformatted, cleaned up + +static void P_LoadLineDefs2(int lump) +{ + int i = numlines; + register line_t *ld = lines; + for (;i--;ld++) + { + ld->frontsector = sides[ld->sidenum[0]].sector; //e6y: Can't be NO_INDEX here + ld->backsector = ld->sidenum[1]!=NO_INDEX ? sides[ld->sidenum[1]].sector : 0; + switch (ld->special) + { // killough 4/11/98: handle special types + int lump, j; + + case 260: // killough 4/11/98: translucent 2s textures + lump = sides[*ld->sidenum].special; // translucency from sidedef + if (!ld->tag) // if tag==0, + ld->tranlump = lump; // affect this linedef only + else + for (j=0;jtag) // affect all matching linedefs + lines[j].tranlump = lump; + break; + } + } +} + +// +// P_LoadSideDefs +// +// killough 4/4/98: split into two functions + +static void P_LoadSideDefs (int lump) +{ + numsides = W_LumpLength(lump) / sizeof(mapsidedef_t); + sides = Z_Calloc(numsides,sizeof(side_t),PU_LEVEL,0); +} + +// killough 4/4/98: delay using texture names until +// after linedefs are loaded, to allow overloading. +// killough 5/3/98: reformatted, cleaned up + +static void P_LoadSideDefs2(int lump) +{ + const byte *data = W_CacheLumpNum(lump); // cph - const*, wad lump handling updated + int i; + + for (i=0; itextureoffset = SHORT(msd->textureoffset)<rowoffset = SHORT(msd->rowoffset)<sector); + if (sector_num >= numsectors) { + lprintf(LO_WARN,"P_LoadSideDefs2: sidedef %i has out-of-range sector num %u\n", i, sector_num); + sector_num = 0; + } + sd->sector = sec = §ors[sector_num]; + } + + // killough 4/4/98: allow sidedef texture names to be overloaded + // killough 4/11/98: refined to allow colormaps to work as wall + // textures if invalid as colormaps but valid as textures. + switch (sd->special) + { + case 242: // variable colormap via 242 linedef + sd->bottomtexture = + (sec->bottommap = R_ColormapNumForName(msd->bottomtexture)) < 0 ? + sec->bottommap = 0, R_TextureNumForName(msd->bottomtexture): 0 ; + sd->midtexture = + (sec->midmap = R_ColormapNumForName(msd->midtexture)) < 0 ? + sec->midmap = 0, R_TextureNumForName(msd->midtexture) : 0 ; + sd->toptexture = + (sec->topmap = R_ColormapNumForName(msd->toptexture)) < 0 ? + sec->topmap = 0, R_TextureNumForName(msd->toptexture) : 0 ; + break; + + case 260: // killough 4/11/98: apply translucency to 2s normal texture + sd->midtexture = strncasecmp("TRANMAP", msd->midtexture, 8) ? + (sd->special = W_CheckNumForName(msd->midtexture)) < 0 || + W_LumpLength(sd->special) != 65536 ? + sd->special=0, R_TextureNumForName(msd->midtexture) : + (sd->special++, 0) : (sd->special=0); + sd->toptexture = R_TextureNumForName(msd->toptexture); + sd->bottomtexture = R_TextureNumForName(msd->bottomtexture); + break; + + default: // normal cases + sd->midtexture = R_SafeTextureNumForName(msd->midtexture, i); + sd->toptexture = R_SafeTextureNumForName(msd->toptexture, i); + sd->bottomtexture = R_SafeTextureNumForName(msd->bottomtexture, i); + break; + } + } + + W_UnlockLumpNum(lump); // cph - release the lump +} + +// +// jff 10/6/98 +// New code added to speed up calculation of internal blockmap +// Algorithm is order of nlines*(ncols+nrows) not nlines*ncols*nrows +// + +#define blkshift 7 /* places to shift rel position for cell num */ +#define blkmask ((1<0 + // jff 10/12/98 0 ok with + 1 in rows,cols + +typedef struct linelist_t // type used to list lines in each block +{ + long num; + struct linelist_t *next; +} linelist_t; + +// +// Subroutine to add a line number to a block list +// It simply returns if the line is already in the block +// + +static void AddBlockLine +( + linelist_t **lists, + int *count, + int *done, + int blockno, + long lineno +) +{ + linelist_t *l; + + if (done[blockno]) + return; + + l = malloc(sizeof(linelist_t)); + l->num = lineno; + l->next = lists[blockno]; + lists[blockno] = l; + count[blockno]++; + done[blockno] = 1; +} + +// +// Actually construct the blockmap lump from the level data +// +// This finds the intersection of each linedef with the column and +// row lines at the left and bottom of each blockmap cell. It then +// adds the line to all block lists touching the intersection. +// + +static void P_CreateBlockMap(void) +{ + int xorg,yorg; // blockmap origin (lower left) + int nrows,ncols; // blockmap dimensions + linelist_t **blocklists=NULL; // array of pointers to lists of lines + int *blockcount=NULL; // array of counters of line lists + int *blockdone=NULL; // array keeping track of blocks/line + int NBlocks; // number of cells = nrows*ncols + long linetotal=0; // total length of all blocklists + int i,j; + int map_minx=INT_MAX; // init for map limits search + int map_miny=INT_MAX; + int map_maxx=INT_MIN; + int map_maxy=INT_MIN; + + // scan for map limits, which the blockmap must enclose + + for (i=0;i map_maxx) + map_maxx = t; + if ((t=vertexes[i].y) < map_miny) + map_miny = t; + else if (t > map_maxy) + map_maxy = t; + } + map_minx >>= FRACBITS; // work in map coords, not fixed_t + map_maxx >>= FRACBITS; + map_miny >>= FRACBITS; + map_maxy >>= FRACBITS; + + // set up blockmap area to enclose level plus margin + + xorg = map_minx-blkmargin; + yorg = map_miny-blkmargin; + ncols = (map_maxx+blkmargin-xorg+1+blkmask)>>blkshift; //jff 10/12/98 + nrows = (map_maxy+blkmargin-yorg+1+blkmask)>>blkshift; //+1 needed for + NBlocks = ncols*nrows; //map exactly 1 cell + + // create the array of pointers on NBlocks to blocklists + // also create an array of linelist counts on NBlocks + // finally make an array in which we can mark blocks done per line + + // CPhipps - calloc's + blocklists = calloc(NBlocks,sizeof(linelist_t *)); + blockcount = calloc(NBlocks,sizeof(int)); + blockdone = malloc(NBlocks*sizeof(int)); + + // initialize each blocklist, and enter the trailing -1 in all blocklists + // note the linked list of lines grows backwards + + for (i=0;inum = -1; + blocklists[i]->next = NULL; + blockcount[i]++; + } + + // For each linedef in the wad, determine all blockmap blocks it touches, + // and add the linedef number to the blocklists for those blocks + + for (i=0;ix>>FRACBITS; // lines[i] map coords + int y1 = lines[i].v1->y>>FRACBITS; + int x2 = lines[i].v2->x>>FRACBITS; + int y2 = lines[i].v2->y>>FRACBITS; + int dx = x2-x1; + int dy = y2-y1; + int vert = !dx; // lines[i] slopetype + int horiz = !dy; + int spos = (dx^dy) > 0; + int sneg = (dx^dy) < 0; + int bx,by; // block cell coords + int minx = x1>x2? x2 : x1; // extremal lines[i] coords + int maxx = x1>x2? x1 : x2; + int miny = y1>y2? y2 : y1; + int maxy = y1>y2? y1 : y2; + + // no blocks done for this linedef yet + + memset(blockdone,0,NBlocks*sizeof(int)); + + // The line always belongs to the blocks containing its endpoints + + bx = (x1-xorg)>>blkshift; + by = (y1-yorg)>>blkshift; + AddBlockLine(blocklists,blockcount,blockdone,by*ncols+bx,i); + bx = (x2-xorg)>>blkshift; + by = (y2-yorg)>>blkshift; + AddBlockLine(blocklists,blockcount,blockdone,by*ncols+bx,i); + + + // For each column, see where the line along its left edge, which + // it contains, intersects the Linedef i. Add i to each corresponding + // blocklist. + + if (!vert) // don't interesect vertical lines with columns + { + for (j=0;j>blkshift; // block row number + int yp = (y-yorg)&blkmask; // y position within block + + if (yb<0 || yb>nrows-1) // outside blockmap, continue + continue; + + if (xmaxx) // line doesn't touch column + continue; + + // The cell that contains the intersection point is always added + + AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j,i); + + // if the intersection is at a corner it depends on the slope + // (and whether the line extends past the intersection) which + // blocks are hit + + if (yp==0) // intersection at a corner + { + if (sneg) // \ - blocks x,y-, x-,y + { + if (yb>0 && miny0 && minx0 && j>0 && minx0 && minx0 && minx>blkshift; // block column number + int xp = (x-xorg)&blkmask; // x position within block + + if (xb<0 || xb>ncols-1) // outside blockmap, continue + continue; + + if (ymaxy) // line doesn't touch row + continue; + + // The cell that contains the intersection point is always added + + AddBlockLine(blocklists,blockcount,blockdone,ncols*j+xb,i); + + // if the intersection is at a corner it depends on the slope + // (and whether the line extends past the intersection) which + // blocks are hit + + if (xp==0) // intersection at a corner + { + if (sneg) // \ - blocks x,y-, x-,y + { + if (j>0 && miny0 && minx0 && miny0 && j>0 && miny0 && minynext; + blockmaplump[offs++] = bl->num; + free(bl); + bl = tmp; + } + } + + // free all temporary storage + + free (blocklists); + free (blockcount); + free (blockdone); +} + +// jff 10/6/98 +// End new code added to speed up calculation of internal blockmap + +// +// P_LoadBlockMap +// +// killough 3/1/98: substantially modified to work +// towards removing blockmap limit (a wad limitation) +// +// killough 3/30/98: Rewritten to remove blockmap limit, +// though current algorithm is brute-force and unoptimal. +// + +static void P_LoadBlockMap (int lump) +{ + long count; + + if (M_CheckParm("-blockmap") || W_LumpLength(lump)<8 || (count = W_LumpLength(lump)/2) >= 0x10000) //e6y + P_CreateBlockMap(); + else + { + long i; + // cph - const*, wad lump handling updated + const short *wadblockmaplump = W_CacheLumpNum(lump); + blockmaplump = Z_Malloc(sizeof(*blockmaplump) * count, PU_LEVEL, 0); + + // killough 3/1/98: Expand wad blockmap into larger internal one, + // by treating all offsets except -1 as unsigned and zero-extending + // them. This potentially doubles the size of blockmaps allowed, + // because Doom originally considered the offsets as always signed. + + blockmaplump[0] = SHORT(wadblockmaplump[0]); + blockmaplump[1] = SHORT(wadblockmaplump[1]); + blockmaplump[2] = (long)(SHORT(wadblockmaplump[2])) & 0xffff; + blockmaplump[3] = (long)(SHORT(wadblockmaplump[3])) & 0xffff; + + for (i=4 ; i= required) + return; // nothing to do + + // allocate a new block and copy the reject table into it; zero the rest + // PU_LEVEL => will be freed on level exit + newreject = Z_Malloc(required, PU_LEVEL, NULL); + rejectmatrix = (const byte *)memmove(newreject, rejectmatrix, length); + memset(newreject + length, 0, required - length); + // unlock the original lump, it is no longer needed + W_UnlockLumpNum(rejectlump); + rejectlump = -1; + + if (demo_compatibility) + { + // merged in RejectOverrunAddInt(), and the 4 calls to it, here + unsigned int rejectpad[4] = { + 0, // size, will be filled in using totallines + 0, // part of the header of a doom.exe z_zone block + 50, // DOOM_CONST_PU_LEVEL + 0x1d4a11 // DOOM_CONST_ZONEID + }; + unsigned int i, pad = 0, *src = rejectpad; + byte *dest = newreject + length; + + rejectpad[0] = ((totallines*4+3)&~3)+24; // doom.exe zone header size + + // copy at most 16 bytes from rejectpad + // emulating a 32-bit, little-endian architecture (can't memmove) + for (i = 0; i < required - length && i < 16; i++) { // 16 hard-coded + if (!(i&3)) // get the next 4 bytes to copy when i=0,4,8,12 + pad = *src++; + *dest++ = pad & 0xff; // store lowest-significant byte + pad >>= 8; // rotate the next byte down + } + } + lprintf(LO_WARN, "P_LoadReject: REJECT too short (%u<%u) - padded\n", + length, required); +} + +// +// P_GroupLines +// Builds sector line lists and subsector sector numbers. +// Finds block bounding boxes for sectors. +// +// killough 5/3/98: reformatted, cleaned up +// cph 18/8/99: rewritten to avoid O(numlines * numsectors) section +// It makes things more complicated, but saves seconds on big levels +// figgi 09/18/00 -- adapted for gl-nodes + +// cph - convenient sub-function +static void P_AddLineToSector(line_t* li, sector_t* sector) +{ + fixed_t *bbox = (void*)sector->blockbox; + + sector->lines[sector->linecount++] = li; + M_AddToBox (bbox, li->v1->x, li->v1->y); + M_AddToBox (bbox, li->v2->x, li->v2->y); +} + +// modified to return totallines (needed by P_LoadReject) +static int P_GroupLines (void) +{ + register line_t *li; + register sector_t *sector; + int i,j, total = numlines; + + // figgi + for (i=0 ; isidedef) + { + subsectors[i].sector = seg->sidedef->sector; + break; + } + seg++; + } + if(subsectors[i].sector == NULL) + I_Error("P_GroupLines: Subsector a part of no sector!\n"); + } + + // count number of lines in each sector + for (i=0,li=lines; ifrontsector->linecount++; + if (li->backsector && li->backsector != li->frontsector) + { + li->backsector->linecount++; + total++; + } + } + + { // allocate line tables for each sector + line_t **linebuffer = Z_Malloc(total*sizeof(line_t *), PU_LEVEL, 0); + + // e6y: REJECT overrun emulation code + // moved to P_LoadReject + + for (i=0, sector = sectors; ilines = linebuffer; + linebuffer += sector->linecount; + sector->linecount = 0; + M_ClearBox(sector->blockbox); + } + } + + // Enter those lines + for (i=0,li=lines; ifrontsector); + if (li->backsector && li->backsector != li->frontsector) + P_AddLineToSector(li, li->backsector); + } + + for (i=0, sector = sectors; iblockbox; // cph - For convenience, so + // I can sue the old code unchanged + int block; + + // set the degenmobj_t to the middle of the bounding box + if (comp[comp_sound]) + { + sector->soundorg.x = (bbox[BOXRIGHT]+bbox[BOXLEFT])/2; + sector->soundorg.y = (bbox[BOXTOP]+bbox[BOXBOTTOM])/2; + } + else + { + //e6y: fix sound origin for large levels + sector->soundorg.x = bbox[BOXRIGHT]/2+bbox[BOXLEFT]/2; + sector->soundorg.y = bbox[BOXTOP]/2+bbox[BOXBOTTOM]/2; + } + + // adjust bounding box to map blocks + block = (bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT; + block = block >= bmapheight ? bmapheight-1 : block; + sector->blockbox[BOXTOP]=block; + + block = (bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT; + block = block < 0 ? 0 : block; + sector->blockbox[BOXBOTTOM]=block; + + block = (bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT; + block = block >= bmapwidth ? bmapwidth-1 : block; + sector->blockbox[BOXRIGHT]=block; + + block = (bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT; + block = block < 0 ? 0 : block; + sector->blockbox[BOXLEFT]=block; + } + + return total; // this value is needed by the reject overrun emulation code +} + +// +// killough 10/98 +// +// Remove slime trails. +// +// Slime trails are inherent to Doom's coordinate system -- i.e. there is +// nothing that a node builder can do to prevent slime trails ALL of the time, +// because it's a product of the integer coodinate system, and just because +// two lines pass through exact integer coordinates, doesn't necessarily mean +// that they will intersect at integer coordinates. Thus we must allow for +// fractional coordinates if we are to be able to split segs with node lines, +// as a node builder must do when creating a BSP tree. +// +// A wad file does not allow fractional coordinates, so node builders are out +// of luck except that they can try to limit the number of splits (they might +// also be able to detect the degree of roundoff error and try to avoid splits +// with a high degree of roundoff error). But we can use fractional coordinates +// here, inside the engine. It's like the difference between square inches and +// square miles, in terms of granularity. +// +// For each vertex of every seg, check to see whether it's also a vertex of +// the linedef associated with the seg (i.e, it's an endpoint). If it's not +// an endpoint, and it wasn't already moved, move the vertex towards the +// linedef by projecting it using the law of cosines. Formula: +// +// 2 2 2 2 +// dx x0 + dy x1 + dx dy (y0 - y1) dy y0 + dx y1 + dx dy (x0 - x1) +// {---------------------------------, ---------------------------------} +// 2 2 2 2 +// dx + dy dx + dy +// +// (x0,y0) is the vertex being moved, and (x1,y1)-(x1+dx,y1+dy) is the +// reference linedef. +// +// Segs corresponding to orthogonal linedefs (exactly vertical or horizontal +// linedefs), which comprise at least half of all linedefs in most wads, don't +// need to be considered, because they almost never contribute to slime trails +// (because then any roundoff error is parallel to the linedef, which doesn't +// cause slime). Skipping simple orthogonal lines lets the code finish quicker. +// +// Please note: This section of code is not interchangable with TeamTNT's +// code which attempts to fix the same problem. +// +// Firelines (TM) is a Rezistered Trademark of MBF Productions +// + +static void P_RemoveSlimeTrails(void) // killough 10/98 +{ + byte *hit = calloc(1, numvertexes); // Hitlist for vertices + int i; + for (i=0; idx && l->dy) // We can ignore orthogonal lines + { + vertex_t *v = segs[i].v1; + do + if (!hit[v - vertexes]) // If we haven't processed vertex + { + hit[v - vertexes] = 1; // Mark this vertex as processed + if (v != l->v1 && v != l->v2) // Exclude endpoints of linedefs + { // Project the vertex back onto the parent linedef + int_64_t dx2 = (l->dx >> FRACBITS) * (l->dx >> FRACBITS); + int_64_t dy2 = (l->dy >> FRACBITS) * (l->dy >> FRACBITS); + int_64_t dxy = (l->dx >> FRACBITS) * (l->dy >> FRACBITS); + int_64_t s = dx2 + dy2; + int x0 = v->x, y0 = v->y, x1 = l->v1->x, y1 = l->v1->y; + v->x = (int)((dx2 * x0 + dy2 * x1 + dxy * (y0 - y1)) / s); + v->y = (int)((dy2 * y0 + dx2 * y1 + dxy * (x0 - x1)) / s); + } + } // Obsfucated C contest entry: :) + while ((v != segs[i].v2) && (v = segs[i].v2)); + } + } + free(hit); +} + +// +// P_SetupLevel +// +// killough 5/3/98: reformatted, cleaned up + +void P_SetupLevel(int episode, int map, int playermask, skill_t skill) +{ + int i; + char lumpname[9]; + int lumpnum; + + char gl_lumpname[9]; + int gl_lumpnum; + + R_StopAllInterpolations(); + + totallive = totalkills = totalitems = totalsecret = wminfo.maxfrags = 0; + wminfo.partime = 180; + + for (i=0; i 0) + P_LoadVertexes2 (lumpnum+ML_VERTEXES,gl_lumpnum+ML_GL_VERTS); + else + P_LoadVertexes (lumpnum+ML_VERTEXES); + P_LoadSectors (lumpnum+ML_SECTORS); + P_LoadSideDefs (lumpnum+ML_SIDEDEFS); + P_LoadLineDefs (lumpnum+ML_LINEDEFS); + P_LoadSideDefs2 (lumpnum+ML_SIDEDEFS); + P_LoadLineDefs2 (lumpnum+ML_LINEDEFS); + P_LoadBlockMap (lumpnum+ML_BLOCKMAP); + + if (nodesVersion > 0) + { + P_LoadSubsectors(gl_lumpnum + ML_GL_SSECT); + P_LoadNodes(gl_lumpnum + ML_GL_NODES); + P_LoadGLSegs(gl_lumpnum + ML_GL_SEGS); + } + else + { + P_LoadSubsectors(lumpnum + ML_SSECTORS); + P_LoadNodes(lumpnum + ML_NODES); + P_LoadSegs(lumpnum + ML_SEGS); + } + +#else + + P_LoadVertexes (lumpnum+ML_VERTEXES); + P_LoadSectors (lumpnum+ML_SECTORS); + P_LoadSideDefs (lumpnum+ML_SIDEDEFS); // killough 4/4/98 + P_LoadLineDefs (lumpnum+ML_LINEDEFS); // | + P_LoadSideDefs2 (lumpnum+ML_SIDEDEFS); // | + P_LoadLineDefs2 (lumpnum+ML_LINEDEFS); // killough 4/4/98 + P_LoadBlockMap (lumpnum+ML_BLOCKMAP); // killough 3/1/98 + P_LoadSubsectors(lumpnum+ML_SSECTORS); + P_LoadNodes (lumpnum+ML_NODES); + P_LoadSegs (lumpnum+ML_SEGS); + +#endif + + // reject loading and underflow padding separated out into new function + // P_GroupLines modified to return a number the underflow padding needs + P_LoadReject(lumpnum, P_GroupLines()); + + // e6y + // Correction of desync on dv04-423.lmp/dv.wad + // http://www.doomworld.com/vb/showthread.php?s=&postid=627257#post627257 + if (compatibility_level>=lxdoom_1_compatibility || M_CheckParm("-force_remove_slime_trails") > 0) + P_RemoveSlimeTrails(); // killough 10/98: remove slime trails from wad + + // Note: you don't need to clear player queue slots -- + // a much simpler fix is in g_game.c -- killough 10/98 + + bodyqueslot = 0; + + /* cph - reset all multiplayer starts */ + memset(playerstarts,0,sizeof(playerstarts)); + deathmatch_p = deathmatchstarts; + for (i = 0; i < MAXPLAYERS; i++) + players[i].mo = NULL; + + P_MapStart(); + + P_LoadThings(lumpnum+ML_THINGS); + + // if deathmatch, randomly spawn the active players + if (deathmatch) + { + for (i=0; idx ? x == node->x ? 2 : x <= node->x ? node->dy > 0 : node->dy < 0 : + !node->dy ? ( compatibility_level < prboom_4_compatibility ? x : y) == node->y ? 2 : y <= node->y ? node->dx < 0 : node->dx > 0 : + (right = ((y - node->y) >> FRACBITS) * (node->dx >> FRACBITS)) < + (left = ((x - node->x) >> FRACBITS) * (node->dy >> FRACBITS)) ? 0 : + right == left ? 2 : 1; +} + +// +// P_CrossSubsector +// Returns true +// if strace crosses the given subsector successfully. +// +// killough 4/19/98: made static and cleaned up + +static boolean P_CrossSubsector(int num) +{ + seg_t *seg = segs + subsectors[num].firstline; + int count; + fixed_t opentop = 0, openbottom = 0; + const sector_t *front = NULL, *back = NULL; + +#ifdef RANGECHECK + if (num >= numsubsectors) + I_Error("P_CrossSubsector: ss %i with numss = %i", num, numsubsectors); +#endif + + for (count = subsectors[num].numlines; --count >= 0; seg++) { // check lines + line_t *line = seg->linedef; + divline_t divl; + + if(!line) // figgi -- skip minisegs + continue; + + // allready checked other side? + if (line->validcount == validcount) + continue; + + line->validcount = validcount; + + /* OPTIMIZE: killough 4/20/98: Added quick bounding-box rejection test + * cph - this is causing demo desyncs on original Doom demos. + * Who knows why. Exclude test for those. + */ + if (!demo_compatibility) + if (line->bbox[BOXLEFT ] > los.bbox[BOXRIGHT ] || + line->bbox[BOXRIGHT ] < los.bbox[BOXLEFT ] || + line->bbox[BOXBOTTOM] > los.bbox[BOXTOP ] || + line->bbox[BOXTOP] < los.bbox[BOXBOTTOM]) + continue; + + // cph - do what we can before forced to check intersection + if (line->flags & ML_TWOSIDED) { + + // no wall to block sight with? + if ((front = seg->frontsector)->floorheight == + (back = seg->backsector)->floorheight && + front->ceilingheight == back->ceilingheight) + continue; + + // possible occluder + // because of ceiling height differences + opentop = front->ceilingheight < back->ceilingheight ? + front->ceilingheight : back->ceilingheight ; + + // because of floor height differences + openbottom = front->floorheight > back->floorheight ? + front->floorheight : back->floorheight ; + + // cph - reject if does not intrude in the z-space of the possible LOS + if ((opentop >= los.maxz) && (openbottom <= los.minz)) + continue; + } + + { // Forget this line if it doesn't cross the line of sight + const vertex_t *v1,*v2; + + v1 = line->v1; + v2 = line->v2; + + if (P_DivlineSide(v1->x, v1->y, &los.strace) == + P_DivlineSide(v2->x, v2->y, &los.strace)) + continue; + + divl.dx = v2->x - (divl.x = v1->x); + divl.dy = v2->y - (divl.y = v1->y); + + // line isn't crossed? + if (P_DivlineSide(los.strace.x, los.strace.y, &divl) == + P_DivlineSide(los.t2x, los.t2y, &divl)) + continue; + } + + // cph - if bottom >= top or top < minz or bottom > maxz then it must be + // solid wrt this LOS + if (!(line->flags & ML_TWOSIDED) || (openbottom >= opentop) || + (opentop < los.minz) || (openbottom > los.maxz)) + return false; + + { // crosses a two sided line + /* cph 2006/07/15 - oops, we missed this in 2.4.0 & .1; + * use P_InterceptVector2 for those compat levels only. */ + fixed_t frac = (compatibility_level == prboom_5_compatibility || compatibility_level == prboom_6_compatibility) ? + P_InterceptVector2(&los.strace, &divl) : + P_InterceptVector(&los.strace, &divl); + + if (front->floorheight != back->floorheight) { + fixed_t slope = FixedDiv(openbottom - los.sightzstart , frac); + if (slope > los.bottomslope) + los.bottomslope = slope; + } + + if (front->ceilingheight != back->ceilingheight) + { + fixed_t slope = FixedDiv(opentop - los.sightzstart , frac); + if (slope < los.topslope) + los.topslope = slope; + } + + if (los.topslope <= los.bottomslope) + return false; // stop + } + } + // passed the subsector ok + return true; +} + +// +// P_CrossBSPNode +// Returns true +// if strace crosses the given node successfully. +// +// killough 4/20/98: rewritten to remove tail recursion, clean up, and optimize +// cph - Made to use R_PointOnSide instead of P_DivlineSide, since the latter +// could return 2 which was ambigous, and the former is +// better optimised; also removes two casts :-) + +static boolean P_CrossBSPNode_LxDoom(int bspnum) +{ + while (!(bspnum & NF_SUBSECTOR)) + { + register const node_t *bsp = nodes + bspnum; + int side,side2; + side = R_PointOnSide(los.strace.x, los.strace.y, bsp); + side2 = R_PointOnSide(los.t2x, los.t2y, bsp); + if (side == side2) + bspnum = bsp->children[side]; // doesn't touch the other side + else // the partition plane is crossed here + if (!P_CrossBSPNode_LxDoom(bsp->children[side])) + return 0; // cross the starting side + else + bspnum = bsp->children[side^1]; // cross the ending side + } + return P_CrossSubsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); +} + +static boolean P_CrossBSPNode_PrBoom(int bspnum) +{ + while (!(bspnum & NF_SUBSECTOR)) + { + register const node_t *bsp = nodes + bspnum; + int side,side2; + side = P_DivlineSide(los.strace.x,los.strace.y,(const divline_t *)bsp)&1; + side2= P_DivlineSide(los.t2x, los.t2y, (const divline_t *) bsp); + if (side == side2) + bspnum = bsp->children[side]; // doesn't touch the other side + else // the partition plane is crossed here + if (!P_CrossBSPNode_PrBoom(bsp->children[side])) + return 0; // cross the starting side + else + bspnum = bsp->children[side^1]; // cross the ending side + } + return P_CrossSubsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); +} + +/* proff - Moved the compatibility check outside the functions + * this gives a slight speedup + */ +static boolean P_CrossBSPNode(int bspnum) +{ + /* cph - LxDoom used some R_* funcs here */ + if (compatibility_level == lxdoom_1_compatibility) + return P_CrossBSPNode_LxDoom(bspnum); + else + return P_CrossBSPNode_PrBoom(bspnum); +} + +// +// P_CheckSight +// Returns true +// if a straight line between t1 and t2 is unobstructed. +// Uses REJECT. +// +// killough 4/20/98: cleaned up, made to use new LOS struct + +boolean P_CheckSight(mobj_t *t1, mobj_t *t2) +{ + const sector_t *s1 = t1->subsector->sector; + const sector_t *s2 = t2->subsector->sector; + int pnum = (s1-sectors)*numsectors + (s2-sectors); + + // First check for trivial rejection. + // Determine subsector entries in REJECT table. + // + // Check in REJECT table. + + if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected + return false; + + // killough 4/19/98: make fake floors and ceilings block monster view + + if ((s1->heightsec != -1 && + ((t1->z + t1->height <= sectors[s1->heightsec].floorheight && + t2->z >= sectors[s1->heightsec].floorheight) || + (t1->z >= sectors[s1->heightsec].ceilingheight && + t2->z + t1->height <= sectors[s1->heightsec].ceilingheight))) + || + (s2->heightsec != -1 && + ((t2->z + t2->height <= sectors[s2->heightsec].floorheight && + t1->z >= sectors[s2->heightsec].floorheight) || + (t2->z >= sectors[s2->heightsec].ceilingheight && + t1->z + t2->height <= sectors[s2->heightsec].ceilingheight)))) + return false; + + /* killough 11/98: shortcut for melee situations + * same subsector? obviously visible + * cph - compatibility optioned for demo sync, cf HR06-UV.LMP */ + if ((t1->subsector == t2->subsector) && + (compatibility_level >= mbf_compatibility)) + return true; + + // An unobstructed LOS is possible. + // Now look from eyes of t1 to any part of t2. + + validcount++; + + los.topslope = (los.bottomslope = t2->z - (los.sightzstart = + t1->z + t1->height - + (t1->height>>2))) + t2->height; + los.strace.dx = (los.t2x = t2->x) - (los.strace.x = t1->x); + los.strace.dy = (los.t2y = t2->y) - (los.strace.y = t1->y); + + if (t1->x > t2->x) + los.bbox[BOXRIGHT] = t1->x, los.bbox[BOXLEFT] = t2->x; + else + los.bbox[BOXRIGHT] = t2->x, los.bbox[BOXLEFT] = t1->x; + + if (t1->y > t2->y) + los.bbox[BOXTOP] = t1->y, los.bbox[BOXBOTTOM] = t2->y; + else + los.bbox[BOXTOP] = t2->y, los.bbox[BOXBOTTOM] = t1->y; + + /* cph - calculate min and max z of the potential line of sight + * For old demos, we disable this optimisation by setting them to + * the extremes */ + switch (compatibility_level) { + case lxdoom_1_compatibility: + if (los.sightzstart < t2->z) { + los.maxz = t2->z + t2->height; los.minz = los.sightzstart; + } else if (los.sightzstart > t2->z + t2->height) { + los.maxz = los.sightzstart; los.minz = t2->z; + } else { + los.maxz = t2->z + t2->height; los.minz = t2->z; + } + break; + default: + los.maxz = INT_MAX; los.minz = INT_MIN; + } + + // the head node is the last node output + return P_CrossBSPNode(numnodes-1); +} diff --git a/src/p_spec.c b/src/p_spec.c new file mode 100644 index 0000000..738eec2 --- /dev/null +++ b/src/p_spec.c @@ -0,0 +1,3353 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * -Loads and initializes texture and flat animation sequences + * -Implements utility functions for all linedef/sector special handlers + * -Dispatches walkover and gun line triggers + * -Initializes and implements special sector types + * -Implements donut linedef triggers + * -Initializes and implements BOOM linedef triggers for + * Scrollers/Conveyors + * Friction + * Wind/Current + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "p_spec.h" +#include "p_tick.h" +#include "p_setup.h" +#include "m_random.h" +#include "d_englsh.h" +#include "m_argv.h" +#include "w_wad.h" +#include "r_main.h" +#include "p_maputl.h" +#include "p_map.h" +#include "g_game.h" +#include "p_inter.h" +#include "s_sound.h" +#include "sounds.h" +#include "m_bbox.h" // phares 3/20/98 +#include "d_deh.h" +#include "r_plane.h" +#include "lprintf.h" + +// +// Animating textures and planes +// There is another anim_t used in wi_stuff, unrelated. +// +typedef struct +{ + boolean istexture; + int picnum; + int basepic; + int numpics; + int speed; + +} anim_t; + +// +// source animation definition +// +// +#ifdef _MSC_VER // proff: This is the same as __attribute__ ((packed)) in GNUC +#pragma pack(push) +#pragma pack(1) +#endif //_MSC_VER + +#if defined(__MWERKS__) +#pragma options align=packed +#endif + +typedef struct +{ + signed char istexture; //jff 3/23/98 make char for comparison // cph - make signed + char endname[9]; // if false, it is a flat + char startname[9]; + int speed; +} PACKEDATTR animdef_t; //jff 3/23/98 pack to read from memory + +#if defined(__MWERKS__) +#pragma options align=reset +#endif + +#ifdef _MSC_VER +#pragma pack(pop) +#endif //_MSC_VER + +#define MAXANIMS 32 // no longer a strict limit -- killough + +static anim_t* lastanim; +static anim_t* anims; // new structure w/o limits -- killough +static size_t maxanims; + +// killough 3/7/98: Initialize generalized scrolling +static void P_SpawnScrollers(void); + +static void P_SpawnFriction(void); // phares 3/16/98 +static void P_SpawnPushers(void); // phares 3/20/98 + +// +// P_InitPicAnims +// +// Load the table of animation definitions, checking for existence of +// the start and end of each frame. If the start doesn't exist the sequence +// is skipped, if the last doesn't exist, BOOM exits. +// +// Wall/Flat animation sequences, defined by name of first and last frame, +// The full animation sequence is given using all lumps between the start +// and end entry, in the order found in the WAD file. +// +// This routine modified to read its data from a predefined lump or +// PWAD lump called ANIMATED rather than a static table in this module to +// allow wad designers to insert or modify animation sequences. +// +// Lump format is an array of byte packed animdef_t structures, terminated +// by a structure with istexture == -1. The lump can be generated from a +// text source file using SWANTBLS.EXE, distributed with the BOOM utils. +// The standard list of switches and animations is contained in the example +// source text file DEFSWANI.DAT also in the BOOM util distribution. +// +// +void P_InitPicAnims (void) +{ + int i; + const animdef_t *animdefs; //jff 3/23/98 pointer to animation lump + int lump = W_GetNumForName("ANIMATED"); // cph - new wad lump handling + // Init animation + + //jff 3/23/98 read from predefined or wad lump instead of table + animdefs = (const animdef_t *)W_CacheLumpNum(lump); + + lastanim = anims; + for (i=0 ; animdefs[i].istexture != -1 ; i++) + { + // 1/11/98 killough -- removed limit by array-doubling + if (lastanim >= anims + maxanims) + { + size_t newmax = maxanims ? maxanims*2 : MAXANIMS; + anims = realloc(anims, newmax*sizeof(*anims)); // killough + lastanim = anims + maxanims; + maxanims = newmax; + } + + if (animdefs[i].istexture) + { + // different episode ? + if (R_CheckTextureNumForName(animdefs[i].startname) == -1) + continue; + + lastanim->picnum = R_TextureNumForName (animdefs[i].endname); + lastanim->basepic = R_TextureNumForName (animdefs[i].startname); + } + else + { + if ((W_CheckNumForName)(animdefs[i].startname, ns_flats) == -1) // killough 4/17/98 + continue; + + lastanim->picnum = R_FlatNumForName (animdefs[i].endname); + lastanim->basepic = R_FlatNumForName (animdefs[i].startname); + } + + lastanim->istexture = animdefs[i].istexture; + lastanim->numpics = lastanim->picnum - lastanim->basepic + 1; + + if (lastanim->numpics < 2) + I_Error ("P_InitPicAnims: bad cycle from %s to %s", + animdefs[i].startname, + animdefs[i].endname); + + lastanim->speed = LONG(animdefs[i].speed); // killough 5/5/98: add LONG() + lastanim++; + } + W_UnlockLumpNum(lump); +} + +/////////////////////////////////////////////////////////////// +// +// Linedef and Sector Special Implementation Utility Functions +// +/////////////////////////////////////////////////////////////// + +// +// getSide() +// +// Will return a side_t* +// given the number of the current sector, +// the line number, and the side (0/1) that you want. +// +// Note: if side=1 is specified, it must exist or results undefined +// +side_t* getSide +( int currentSector, + int line, + int side ) +{ + return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ]; +} + + +// +// getSector() +// +// Will return a sector_t* +// given the number of the current sector, +// the line number and the side (0/1) that you want. +// +// Note: if side=1 is specified, it must exist or results undefined +// +sector_t* getSector +( int currentSector, + int line, + int side ) +{ + return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector; +} + + +// +// twoSided() +// +// Given the sector number and the line number, +// it will tell you whether the line is two-sided or not. +// +// modified to return actual two-sidedness rather than presence +// of 2S flag unless compatibility optioned +// +int twoSided +( int sector, + int line ) +{ + //jff 1/26/98 return what is actually needed, whether the line + //has two sidedefs, rather than whether the 2S flag is set + + return comp[comp_model] ? + (sectors[sector].lines[line])->flags & ML_TWOSIDED + : + (sectors[sector].lines[line])->sidenum[1] != NO_INDEX; +} + + +// +// getNextSector() +// +// Return sector_t * of sector next to current across line. +// +// Note: returns NULL if not two-sided line, or both sides refer to sector +// +sector_t* getNextSector +( line_t* line, + sector_t* sec ) +{ + //jff 1/26/98 check unneeded since line->backsector already + //returns NULL if the line is not two sided, and does so from + //the actual two-sidedness of the line, rather than its 2S flag + + if (comp[comp_model]) + { + if (!(line->flags & ML_TWOSIDED)) + return NULL; + } + + if (line->frontsector == sec) { + if (comp[comp_model] || line->backsector!=sec) + return line->backsector; //jff 5/3/98 don't retn sec unless compatibility + else // fixes an intra-sector line breaking functions + return NULL; // like floor->highest floor + } + return line->frontsector; +} + + +// +// P_FindLowestFloorSurrounding() +// +// Returns the fixed point value of the lowest floor height +// in the sector passed or its surrounding sectors. +// +fixed_t P_FindLowestFloorSurrounding(sector_t* sec) +{ + int i; + line_t* check; + sector_t* other; + fixed_t floor = sec->floorheight; + + for (i=0 ;i < sec->linecount ; i++) + { + check = sec->lines[i]; + other = getNextSector(check,sec); + + if (!other) + continue; + + if (other->floorheight < floor) + floor = other->floorheight; + } + return floor; +} + + +// +// P_FindHighestFloorSurrounding() +// +// Passed a sector, returns the fixed point value of the largest +// floor height in the surrounding sectors, not including that passed +// +// NOTE: if no surrounding sector exists -32000*FRACUINT is returned +// if compatibility then -500*FRACUNIT is the smallest return possible +// +fixed_t P_FindHighestFloorSurrounding(sector_t *sec) +{ + int i; + line_t* check; + sector_t* other; + fixed_t floor = -500*FRACUNIT; + + //jff 1/26/98 Fix initial value for floor to not act differently + //in sections of wad that are below -500 units + if (!comp[comp_model]) /* jff 3/12/98 avoid ovf */ + floor = -32000*FRACUNIT; // in height calculations + + for (i=0 ;i < sec->linecount ; i++) + { + check = sec->lines[i]; + other = getNextSector(check,sec); + + if (!other) + continue; + + if (other->floorheight > floor) + floor = other->floorheight; + } + return floor; +} + + +// +// P_FindNextHighestFloor() +// +// Passed a sector and a floor height, returns the fixed point value +// of the smallest floor height in a surrounding sector larger than +// the floor height passed. If no such height exists the floorheight +// passed is returned. +// +// Rewritten by Lee Killough to avoid fixed array and to be faster +// +fixed_t P_FindNextHighestFloor(sector_t *sec, int currentheight) +{ + sector_t *other; + int i; + + for (i=0 ;i < sec->linecount ; i++) + if ((other = getNextSector(sec->lines[i],sec)) && + other->floorheight > currentheight) + { + int height = other->floorheight; + while (++i < sec->linecount) + if ((other = getNextSector(sec->lines[i],sec)) && + other->floorheight < height && + other->floorheight > currentheight) + height = other->floorheight; + return height; + } + /* cph - my guess at doom v1.2 - 1.4beta compatibility here. + * If there are no higher neighbouring sectors, Heretic just returned + * heightlist[0] (local variable), i.e. noise off the stack. 0 is right for + * RETURN01 E1M2, so let's take that. */ + return (compatibility_level < doom_1666_compatibility ? 0 : currentheight); +} + + +// +// P_FindNextLowestFloor() +// +// Passed a sector and a floor height, returns the fixed point value +// of the largest floor height in a surrounding sector smaller than +// the floor height passed. If no such height exists the floorheight +// passed is returned. +// +// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this +// +fixed_t P_FindNextLowestFloor(sector_t *sec, int currentheight) +{ + sector_t *other; + int i; + + for (i=0 ;i < sec->linecount ; i++) + if ((other = getNextSector(sec->lines[i],sec)) && + other->floorheight < currentheight) + { + int height = other->floorheight; + while (++i < sec->linecount) + if ((other = getNextSector(sec->lines[i],sec)) && + other->floorheight > height && + other->floorheight < currentheight) + height = other->floorheight; + return height; + } + return currentheight; +} + + +// +// P_FindNextLowestCeiling() +// +// Passed a sector and a ceiling height, returns the fixed point value +// of the largest ceiling height in a surrounding sector smaller than +// the ceiling height passed. If no such height exists the ceiling height +// passed is returned. +// +// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this +// +fixed_t P_FindNextLowestCeiling(sector_t *sec, int currentheight) +{ + sector_t *other; + int i; + + for (i=0 ;i < sec->linecount ; i++) + if ((other = getNextSector(sec->lines[i],sec)) && + other->ceilingheight < currentheight) + { + int height = other->ceilingheight; + while (++i < sec->linecount) + if ((other = getNextSector(sec->lines[i],sec)) && + other->ceilingheight > height && + other->ceilingheight < currentheight) + height = other->ceilingheight; + return height; + } + return currentheight; +} + + +// +// P_FindNextHighestCeiling() +// +// Passed a sector and a ceiling height, returns the fixed point value +// of the smallest ceiling height in a surrounding sector larger than +// the ceiling height passed. If no such height exists the ceiling height +// passed is returned. +// +// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this +// +fixed_t P_FindNextHighestCeiling(sector_t *sec, int currentheight) +{ + sector_t *other; + int i; + + for (i=0 ;i < sec->linecount ; i++) + if ((other = getNextSector(sec->lines[i],sec)) && + other->ceilingheight > currentheight) + { + int height = other->ceilingheight; + while (++i < sec->linecount) + if ((other = getNextSector(sec->lines[i],sec)) && + other->ceilingheight < height && + other->ceilingheight > currentheight) + height = other->ceilingheight; + return height; + } + return currentheight; +} + + +// +// P_FindLowestCeilingSurrounding() +// +// Passed a sector, returns the fixed point value of the smallest +// ceiling height in the surrounding sectors, not including that passed +// +// NOTE: if no surrounding sector exists 32000*FRACUINT is returned +// but if compatibility then INT_MAX is the return +// +fixed_t P_FindLowestCeilingSurrounding(sector_t* sec) +{ + int i; + line_t* check; + sector_t* other; + fixed_t height = INT_MAX; + + /* jff 3/12/98 avoid ovf in height calculations */ + if (!comp[comp_model]) height = 32000*FRACUNIT; + + for (i=0 ;i < sec->linecount ; i++) + { + check = sec->lines[i]; + other = getNextSector(check,sec); + + if (!other) + continue; + + if (other->ceilingheight < height) + height = other->ceilingheight; + } + return height; +} + + +// +// P_FindHighestCeilingSurrounding() +// +// Passed a sector, returns the fixed point value of the largest +// ceiling height in the surrounding sectors, not including that passed +// +// NOTE: if no surrounding sector exists -32000*FRACUINT is returned +// but if compatibility then 0 is the smallest return possible +// +fixed_t P_FindHighestCeilingSurrounding(sector_t* sec) +{ + int i; + line_t* check; + sector_t* other; + fixed_t height = 0; + + /* jff 1/26/98 Fix initial value for floor to not act differently + * in sections of wad that are below 0 units + * jff 3/12/98 avoid ovf in height calculations */ + if (!comp[comp_model]) height = -32000*FRACUNIT; + + for (i=0 ;i < sec->linecount ; i++) + { + check = sec->lines[i]; + other = getNextSector(check,sec); + + if (!other) + continue; + + if (other->ceilingheight > height) + height = other->ceilingheight; + } + return height; +} + + +// +// P_FindShortestTextureAround() +// +// Passed a sector number, returns the shortest lower texture on a +// linedef bounding the sector. +// +// Note: If no lower texture exists 32000*FRACUNIT is returned. +// but if compatibility then INT_MAX is returned +// +// jff 02/03/98 Add routine to find shortest lower texture +// +fixed_t P_FindShortestTextureAround(int secnum) +{ + int minsize = INT_MAX; + side_t* side; + int i; + sector_t *sec = §ors[secnum]; + + if (!comp[comp_model]) + minsize = 32000<linecount; i++) + { + if (twoSided(secnum, i)) + { + side = getSide(secnum,i,0); + if (side->bottomtexture > 0) //jff 8/14/98 texture 0 is a placeholder + if (textureheight[side->bottomtexture] < minsize) + minsize = textureheight[side->bottomtexture]; + side = getSide(secnum,i,1); + if (side->bottomtexture > 0) //jff 8/14/98 texture 0 is a placeholder + if (textureheight[side->bottomtexture] < minsize) + minsize = textureheight[side->bottomtexture]; + } + } + return minsize; +} + + +// +// P_FindShortestUpperAround() +// +// Passed a sector number, returns the shortest upper texture on a +// linedef bounding the sector. +// +// Note: If no upper texture exists 32000*FRACUNIT is returned. +// but if compatibility then INT_MAX is returned +// +// jff 03/20/98 Add routine to find shortest upper texture +// +fixed_t P_FindShortestUpperAround(int secnum) +{ + int minsize = INT_MAX; + side_t* side; + int i; + sector_t *sec = §ors[secnum]; + + if (!comp[comp_model]) + minsize = 32000<linecount; i++) + { + if (twoSided(secnum, i)) + { + side = getSide(secnum,i,0); + if (side->toptexture > 0) //jff 8/14/98 texture 0 is a placeholder + if (textureheight[side->toptexture] < minsize) + minsize = textureheight[side->toptexture]; + side = getSide(secnum,i,1); + if (side->toptexture > 0) //jff 8/14/98 texture 0 is a placeholder + if (textureheight[side->toptexture] < minsize) + minsize = textureheight[side->toptexture]; + } + } + return minsize; +} + + +// +// P_FindModelFloorSector() +// +// Passed a floor height and a sector number, return a pointer to a +// a sector with that floor height across the lowest numbered two sided +// line surrounding the sector. +// +// Note: If no sector at that height bounds the sector passed, return NULL +// +// jff 02/03/98 Add routine to find numeric model floor +// around a sector specified by sector number +// jff 3/14/98 change first parameter to plain height to allow call +// from routine not using floormove_t +// +sector_t *P_FindModelFloorSector(fixed_t floordestheight,int secnum) +{ + int i; + sector_t *sec=NULL; + int linecount; + + sec = §ors[secnum]; //jff 3/2/98 woops! better do this + //jff 5/23/98 don't disturb sec->linecount while searching + // but allow early exit in old demos + linecount = sec->linecount; + for (i = 0; i < (demo_compatibility && sec->linecountlinecount : linecount); i++) + { + if ( twoSided(secnum, i) ) + { + if (getSide(secnum,i,0)->sector-sectors == secnum) + sec = getSector(secnum,i,1); + else + sec = getSector(secnum,i,0); + + if (sec->floorheight == floordestheight) + return sec; + } + } + return NULL; +} + + +// +// P_FindModelCeilingSector() +// +// Passed a ceiling height and a sector number, return a pointer to a +// a sector with that ceiling height across the lowest numbered two sided +// line surrounding the sector. +// +// Note: If no sector at that height bounds the sector passed, return NULL +// +// jff 02/03/98 Add routine to find numeric model ceiling +// around a sector specified by sector number +// used only from generalized ceiling types +// jff 3/14/98 change first parameter to plain height to allow call +// from routine not using ceiling_t +// +sector_t *P_FindModelCeilingSector(fixed_t ceildestheight,int secnum) +{ + int i; + sector_t *sec=NULL; + int linecount; + + sec = §ors[secnum]; //jff 3/2/98 woops! better do this + //jff 5/23/98 don't disturb sec->linecount while searching + // but allow early exit in old demos + linecount = sec->linecount; + for (i = 0; i < (demo_compatibility && sec->linecountlinecount : linecount); i++) + { + if ( twoSided(secnum, i) ) + { + if (getSide(secnum,i,0)->sector-sectors == secnum) + sec = getSector(secnum,i,1); + else + sec = getSector(secnum,i,0); + + if (sec->ceilingheight == ceildestheight) + return sec; + } + } + return NULL; +} + +// +// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO +// + +// Find the next sector with the same tag as a linedef. +// Rewritten by Lee Killough to use chained hashing to improve speed + +int P_FindSectorFromLineTag(const line_t *line, int start) +{ + start = start >= 0 ? sectors[start].nexttag : + sectors[(unsigned) line->tag % (unsigned) numsectors].firsttag; + while (start >= 0 && sectors[start].tag != line->tag) + start = sectors[start].nexttag; + return start; +} + +// killough 4/16/98: Same thing, only for linedefs + +int P_FindLineFromLineTag(const line_t *line, int start) +{ + start = start >= 0 ? lines[start].nexttag : + lines[(unsigned) line->tag % (unsigned) numlines].firsttag; + while (start >= 0 && lines[start].tag != line->tag) + start = lines[start].nexttag; + return start; +} + +// Hash the sector tags across the sectors and linedefs. +static void P_InitTagLists(void) +{ + register int i; + + for (i=numsectors; --i>=0; ) // Initially make all slots empty. + sectors[i].firsttag = -1; + for (i=numsectors; --i>=0; ) // Proceed from last to first sector + { // so that lower sectors appear first + int j = (unsigned) sectors[i].tag % (unsigned) numsectors; // Hash func + sectors[i].nexttag = sectors[j].firsttag; // Prepend sector to chain + sectors[j].firsttag = i; + } + + // killough 4/17/98: same thing, only for linedefs + + for (i=numlines; --i>=0; ) // Initially make all slots empty. + lines[i].firsttag = -1; + for (i=numlines; --i>=0; ) // Proceed from last to first linedef + { // so that lower linedefs appear first + int j = (unsigned) lines[i].tag % (unsigned) numlines; // Hash func + lines[i].nexttag = lines[j].firsttag; // Prepend linedef to chain + lines[j].firsttag = i; + } +} + +// +// P_FindMinSurroundingLight() +// +// Passed a sector and a light level, returns the smallest light level +// in a surrounding sector less than that passed. If no smaller light +// level exists, the light level passed is returned. +// +int P_FindMinSurroundingLight +( sector_t* sector, + int max ) +{ + int i; + int min; + line_t* line; + sector_t* check; + + min = max; + for (i=0 ; i < sector->linecount ; i++) + { + line = sector->lines[i]; + check = getNextSector(line,sector); + + if (!check) + continue; + + if (check->lightlevel < min) + min = check->lightlevel; + } + return min; +} + + +// +// P_CanUnlockGenDoor() +// +// Passed a generalized locked door linedef and a player, returns whether +// the player has the keys necessary to unlock that door. +// +// Note: The linedef passed MUST be a generalized locked door type +// or results are undefined. +// +// jff 02/05/98 routine added to test for unlockability of +// generalized locked doors +// +boolean P_CanUnlockGenDoor +( line_t* line, + player_t* player) +{ + // does this line special distinguish between skulls and keys? + int skulliscard = (line->special & LockedNKeys)>>LockedNKeysShift; + + // determine for each case of lock type if player's keys are adequate + switch((line->special & LockedKey)>>LockedKeyShift) + { + case AnyKey: + if + ( + !player->cards[it_redcard] && + !player->cards[it_redskull] && + !player->cards[it_bluecard] && + !player->cards[it_blueskull] && + !player->cards[it_yellowcard] && + !player->cards[it_yellowskull] + ) + { + player->message = s_PD_ANY; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case RCard: + if + ( + !player->cards[it_redcard] && + (!skulliscard || !player->cards[it_redskull]) + ) + { + player->message = skulliscard? s_PD_REDK : s_PD_REDC; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case BCard: + if + ( + !player->cards[it_bluecard] && + (!skulliscard || !player->cards[it_blueskull]) + ) + { + player->message = skulliscard? s_PD_BLUEK : s_PD_BLUEC; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case YCard: + if + ( + !player->cards[it_yellowcard] && + (!skulliscard || !player->cards[it_yellowskull]) + ) + { + player->message = skulliscard? s_PD_YELLOWK : s_PD_YELLOWC; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case RSkull: + if + ( + !player->cards[it_redskull] && + (!skulliscard || !player->cards[it_redcard]) + ) + { + player->message = skulliscard? s_PD_REDK : s_PD_REDS; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case BSkull: + if + ( + !player->cards[it_blueskull] && + (!skulliscard || !player->cards[it_bluecard]) + ) + { + player->message = skulliscard? s_PD_BLUEK : s_PD_BLUES; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case YSkull: + if + ( + !player->cards[it_yellowskull] && + (!skulliscard || !player->cards[it_yellowcard]) + ) + { + player->message = skulliscard? s_PD_YELLOWK : s_PD_YELLOWS; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + case AllKeys: + if + ( + !skulliscard && + ( + !player->cards[it_redcard] || + !player->cards[it_redskull] || + !player->cards[it_bluecard] || + !player->cards[it_blueskull] || + !player->cards[it_yellowcard] || + !player->cards[it_yellowskull] + ) + ) + { + player->message = s_PD_ALL6; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + if + ( + skulliscard && + ( + (!player->cards[it_redcard] && + !player->cards[it_redskull]) || + (!player->cards[it_bluecard] && + !player->cards[it_blueskull]) || + (!player->cards[it_yellowcard] && + !player->cards[it_yellowskull]) + ) + ) + { + player->message = s_PD_ALL3; // Ty 03/27/98 - externalized + S_StartSound(player->mo,sfx_oof); // killough 3/20/98 + return false; + } + break; + } + return true; +} + + +// +// P_SectorActive() +// +// Passed a linedef special class (floor, ceiling, lighting) and a sector +// returns whether the sector is already busy with a linedef special of the +// same class. If old demo compatibility true, all linedef special classes +// are the same. +// +// jff 2/23/98 added to prevent old demos from +// succeeding in starting multiple specials on one sector +// +boolean PUREFUNC P_SectorActive(special_e t, const sector_t *sec) +{ + if (demo_compatibility) // return whether any thinker is active + return sec->floordata != NULL || sec->ceilingdata != NULL || sec->lightingdata != NULL; + else + switch (t) // return whether thinker of same type is active + { + case floor_special: + return sec->floordata != NULL; + case ceiling_special: + return sec->ceilingdata != NULL; + case lighting_special: + return sec->lightingdata != NULL; + } + return true; // don't know which special, must be active, shouldn't be here +} + + +// +// P_CheckTag() +// +// Passed a line, returns true if the tag is non-zero or the line special +// allows no tag without harm. If compatibility, all linedef specials are +// allowed to have zero tag. +// +// Note: Only line specials activated by walkover, pushing, or shooting are +// checked by this routine. +// +// jff 2/27/98 Added to check for zero tag allowed for regular special types +// +int P_CheckTag(line_t *line) +{ + /* tag not zero, allowed, or + * killough 11/98: compatibility option */ + if (comp[comp_zerotags] || line->tag) + return 1; + + switch(line->special) + { + case 1: // Manual door specials + case 26: + case 27: + case 28: + case 31: + case 32: + case 33: + case 34: + case 117: + case 118: + + case 139: // Lighting specials + case 170: + case 79: + case 35: + case 138: + case 171: + case 81: + case 13: + case 192: + case 169: + case 80: + case 12: + case 194: + case 173: + case 157: + case 104: + case 193: + case 172: + case 156: + case 17: + + case 195: // Thing teleporters + case 174: + case 97: + case 39: + case 126: + case 125: + case 210: + case 209: + case 208: + case 207: + + case 11: // Exits + case 52: + case 197: + case 51: + case 124: + case 198: + + case 48: // Scrolling walls + case 85: + return 1; // zero tag allowed + + default: + break; + } + return 0; // zero tag not allowed +} + + +// +// P_IsSecret() +// +// Passed a sector, returns if the sector secret type is still active, i.e. +// secret type is set and the secret has not yet been obtained. +// +// jff 3/14/98 added to simplify checks for whether sector is secret +// in automap and other places +// +boolean PUREFUNC P_IsSecret(const sector_t *sec) +{ + return (sec->special==9 || (sec->special&SECRET_MASK)); +} + + +// +// P_WasSecret() +// +// Passed a sector, returns if the sector secret type is was active, i.e. +// secret type was set and the secret has been obtained already. +// +// jff 3/14/98 added to simplify checks for whether sector is secret +// in automap and other places +// +boolean PUREFUNC P_WasSecret(const sector_t *sec) +{ + return (sec->oldspecial==9 || (sec->oldspecial&SECRET_MASK)); +} + + +////////////////////////////////////////////////////////////////////////// +// +// Events +// +// Events are operations triggered by using, crossing, +// or shooting special lines, or by timed thinkers. +// +///////////////////////////////////////////////////////////////////////// + +// +// P_CrossSpecialLine - Walkover Trigger Dispatcher +// +// Called every time a thing origin is about +// to cross a line with a non 0 special, whether a walkover type or not. +// +// jff 02/12/98 all W1 lines were fixed to check the result from the EV_ +// function before clearing the special. This avoids losing the function +// of the line, should the sector already be active when the line is +// crossed. Change is qualified by demo_compatibility. +// +// CPhipps - take a line_t pointer instead of a line number, as in MBF +void P_CrossSpecialLine(line_t *line, int side, mobj_t *thing) +{ + int ok; + + // Things that should never trigger lines + if (!thing->player) + { + // Things that should NOT trigger specials... + switch(thing->type) + { + case MT_ROCKET: + case MT_PLASMA: + case MT_BFG: + case MT_TROOPSHOT: + case MT_HEADSHOT: + case MT_BRUISERSHOT: + return; + break; + + default: break; + } + } + + //jff 02/04/98 add check here for generalized lindef types + if (!demo_compatibility) // generalized types not recognized if old demo + { + // pointer to line function is NULL by default, set non-null if + // line special is walkover generalized linedef type + int (*linefunc)(line_t *line)=NULL; + + // check each range of generalized linedefs + if ((unsigned)line->special >= GenEnd) + { + // Out of range for GenFloors + } + else if ((unsigned)line->special >= GenFloorBase) + { + if (!thing->player) + if ((line->special & FloorChange) || !(line->special & FloorModel)) + return; // FloorModel is "Allow Monsters" if FloorChange is 0 + if (!line->tag) //jff 2/27/98 all walk generalized types require tag + return; + linefunc = EV_DoGenFloor; + } + else if ((unsigned)line->special >= GenCeilingBase) + { + if (!thing->player) + if ((line->special & CeilingChange) || !(line->special & CeilingModel)) + return; // CeilingModel is "Allow Monsters" if CeilingChange is 0 + if (!line->tag) //jff 2/27/98 all walk generalized types require tag + return; + linefunc = EV_DoGenCeiling; + } + else if ((unsigned)line->special >= GenDoorBase) + { + if (!thing->player) + { + if (!(line->special & DoorMonster)) + return; // monsters disallowed from this door + if (line->flags & ML_SECRET) // they can't open secret doors either + return; + } + if (!line->tag) //3/2/98 move outside the monster check + return; + linefunc = EV_DoGenDoor; + } + else if ((unsigned)line->special >= GenLockedBase) + { + if (!thing->player) + return; // monsters disallowed from unlocking doors + if (((line->special&TriggerType)==WalkOnce) || ((line->special&TriggerType)==WalkMany)) + { //jff 4/1/98 check for being a walk type before reporting door type + if (!P_CanUnlockGenDoor(line,thing->player)) + return; + } + else + return; + linefunc = EV_DoGenLockedDoor; + } + else if ((unsigned)line->special >= GenLiftBase) + { + if (!thing->player) + if (!(line->special & LiftMonster)) + return; // monsters disallowed + if (!line->tag) //jff 2/27/98 all walk generalized types require tag + return; + linefunc = EV_DoGenLift; + } + else if ((unsigned)line->special >= GenStairsBase) + { + if (!thing->player) + if (!(line->special & StairMonster)) + return; // monsters disallowed + if (!line->tag) //jff 2/27/98 all walk generalized types require tag + return; + linefunc = EV_DoGenStairs; + } + + if (linefunc) // if it was a valid generalized type + switch((line->special & TriggerType) >> TriggerTypeShift) + { + case WalkOnce: + if (linefunc(line)) + line->special = 0; // clear special if a walk once type + return; + case WalkMany: + linefunc(line); + return; + default: // if not a walk type, do nothing here + return; + } + } + + if (!thing->player) + { + ok = 0; + switch(line->special) + { + case 39: // teleport trigger + case 97: // teleport retrigger + case 125: // teleport monsteronly trigger + case 126: // teleport monsteronly retrigger + case 4: // raise door + case 10: // plat down-wait-up-stay trigger + case 88: // plat down-wait-up-stay retrigger + //jff 3/5/98 add ability of monsters etc. to use teleporters + case 208: //silent thing teleporters + case 207: + case 243: //silent line-line teleporter + case 244: //jff 3/6/98 make fit within DCK's 256 linedef types + case 262: //jff 4/14/98 add monster only + case 263: //jff 4/14/98 silent thing,line,line rev types + case 264: //jff 4/14/98 plus player/monster silent line + case 265: // reversed types + case 266: + case 267: + case 268: + case 269: + ok = 1; + break; + } + if (!ok) + return; + } + + if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types + return; + + // Dispatch on the line special value to the line's action routine + // If a once only function, and successful, clear the line special + + switch (line->special) + { + // Regular walk once triggers + + case 2: + // Open Door + if (EV_DoDoor(line,open) || demo_compatibility) + line->special = 0; + break; + + case 3: + // Close Door + if (EV_DoDoor(line,close) || demo_compatibility) + line->special = 0; + break; + + case 4: + // Raise Door + if (EV_DoDoor(line,normal) || demo_compatibility) + line->special = 0; + break; + + case 5: + // Raise Floor + if (EV_DoFloor(line,raiseFloor) || demo_compatibility) + line->special = 0; + break; + + case 6: + // Fast Ceiling Crush & Raise + if (EV_DoCeiling(line,fastCrushAndRaise) || demo_compatibility) + line->special = 0; + break; + + case 8: + // Build Stairs + if (EV_BuildStairs(line,build8) || demo_compatibility) + line->special = 0; + break; + + case 10: + // PlatDownWaitUp + if (EV_DoPlat(line,downWaitUpStay,0) || demo_compatibility) + line->special = 0; + break; + + case 12: + // Light Turn On - brightest near + if (EV_LightTurnOn(line,0) || demo_compatibility) + line->special = 0; + break; + + case 13: + // Light Turn On 255 + if (EV_LightTurnOn(line,255) || demo_compatibility) + line->special = 0; + break; + + case 16: + // Close Door 30 + if (EV_DoDoor(line,close30ThenOpen) || demo_compatibility) + line->special = 0; + break; + + case 17: + // Start Light Strobing + if (EV_StartLightStrobing(line) || demo_compatibility) + line->special = 0; + break; + + case 19: + // Lower Floor + if (EV_DoFloor(line,lowerFloor) || demo_compatibility) + line->special = 0; + break; + + case 22: + // Raise floor to nearest height and change texture + if (EV_DoPlat(line,raiseToNearestAndChange,0) || demo_compatibility) + line->special = 0; + break; + + case 25: + // Ceiling Crush and Raise + if (EV_DoCeiling(line,crushAndRaise) || demo_compatibility) + line->special = 0; + break; + + case 30: + // Raise floor to shortest texture height + // on either side of lines. + if (EV_DoFloor(line,raiseToTexture) || demo_compatibility) + line->special = 0; + break; + + case 35: + // Lights Very Dark + if (EV_LightTurnOn(line,35) || demo_compatibility) + line->special = 0; + break; + + case 36: + // Lower Floor (TURBO) + if (EV_DoFloor(line,turboLower) || demo_compatibility) + line->special = 0; + break; + + case 37: + // LowerAndChange + if (EV_DoFloor(line,lowerAndChange) || demo_compatibility) + line->special = 0; + break; + + case 38: + // Lower Floor To Lowest + if (EV_DoFloor(line, lowerFloorToLowest) || demo_compatibility) + line->special = 0; + break; + + case 39: + // TELEPORT! //jff 02/09/98 fix using up with wrong side crossing + if (EV_Teleport(line, side, thing) || demo_compatibility) + line->special = 0; + break; + + case 40: + // RaiseCeilingLowerFloor + if (demo_compatibility) + { + EV_DoCeiling( line, raiseToHighest ); + EV_DoFloor( line, lowerFloorToLowest ); //jff 02/12/98 doesn't work + line->special = 0; + } + else + if (EV_DoCeiling(line, raiseToHighest)) + line->special = 0; + break; + + case 44: + // Ceiling Crush + if (EV_DoCeiling(line, lowerAndCrush) || demo_compatibility) + line->special = 0; + break; + + case 52: + // EXIT! + // killough 10/98: prevent zombies from exiting levels + if (!(thing->player && thing->player->health <= 0 && !comp[comp_zombie])) + G_ExitLevel (); + break; + + case 53: + // Perpetual Platform Raise + if (EV_DoPlat(line,perpetualRaise,0) || demo_compatibility) + line->special = 0; + break; + + case 54: + // Platform Stop + if (EV_StopPlat(line) || demo_compatibility) + line->special = 0; + break; + + case 56: + // Raise Floor Crush + if (EV_DoFloor(line,raiseFloorCrush) || demo_compatibility) + line->special = 0; + break; + + case 57: + // Ceiling Crush Stop + if (EV_CeilingCrushStop(line) || demo_compatibility) + line->special = 0; + break; + + case 58: + // Raise Floor 24 + if (EV_DoFloor(line,raiseFloor24) || demo_compatibility) + line->special = 0; + break; + + case 59: + // Raise Floor 24 And Change + if (EV_DoFloor(line,raiseFloor24AndChange) || demo_compatibility) + line->special = 0; + break; + + case 100: + // Build Stairs Turbo 16 + if (EV_BuildStairs(line,turbo16) || demo_compatibility) + line->special = 0; + break; + + case 104: + // Turn lights off in sector(tag) + if (EV_TurnTagLightsOff(line) || demo_compatibility) + line->special = 0; + break; + + case 108: + // Blazing Door Raise (faster than TURBO!) + if (EV_DoDoor(line,blazeRaise) || demo_compatibility) + line->special = 0; + break; + + case 109: + // Blazing Door Open (faster than TURBO!) + if (EV_DoDoor (line,blazeOpen) || demo_compatibility) + line->special = 0; + break; + + case 110: + // Blazing Door Close (faster than TURBO!) + if (EV_DoDoor (line,blazeClose) || demo_compatibility) + line->special = 0; + break; + + case 119: + // Raise floor to nearest surr. floor + if (EV_DoFloor(line,raiseFloorToNearest) || demo_compatibility) + line->special = 0; + break; + + case 121: + // Blazing PlatDownWaitUpStay + if (EV_DoPlat(line,blazeDWUS,0) || demo_compatibility) + line->special = 0; + break; + + case 124: + // Secret EXIT + // killough 10/98: prevent zombies from exiting levels + // CPhipps - change for lxdoom's compatibility handling + if (!(thing->player && thing->player->health <= 0 && !comp[comp_zombie])) + G_SecretExitLevel (); + break; + + case 125: + // TELEPORT MonsterONLY + if (!thing->player && + (EV_Teleport(line, side, thing) || demo_compatibility)) + line->special = 0; + break; + + case 130: + // Raise Floor Turbo + if (EV_DoFloor(line,raiseFloorTurbo) || demo_compatibility) + line->special = 0; + break; + + case 141: + // Silent Ceiling Crush & Raise + if (EV_DoCeiling(line,silentCrushAndRaise) || demo_compatibility) + line->special = 0; + break; + + // Regular walk many retriggerable + + case 72: + // Ceiling Crush + EV_DoCeiling( line, lowerAndCrush ); + break; + + case 73: + // Ceiling Crush and Raise + EV_DoCeiling(line,crushAndRaise); + break; + + case 74: + // Ceiling Crush Stop + EV_CeilingCrushStop(line); + break; + + case 75: + // Close Door + EV_DoDoor(line,close); + break; + + case 76: + // Close Door 30 + EV_DoDoor(line,close30ThenOpen); + break; + + case 77: + // Fast Ceiling Crush & Raise + EV_DoCeiling(line,fastCrushAndRaise); + break; + + case 79: + // Lights Very Dark + EV_LightTurnOn(line,35); + break; + + case 80: + // Light Turn On - brightest near + EV_LightTurnOn(line,0); + break; + + case 81: + // Light Turn On 255 + EV_LightTurnOn(line,255); + break; + + case 82: + // Lower Floor To Lowest + EV_DoFloor( line, lowerFloorToLowest ); + break; + + case 83: + // Lower Floor + EV_DoFloor(line,lowerFloor); + break; + + case 84: + // LowerAndChange + EV_DoFloor(line,lowerAndChange); + break; + + case 86: + // Open Door + EV_DoDoor(line,open); + break; + + case 87: + // Perpetual Platform Raise + EV_DoPlat(line,perpetualRaise,0); + break; + + case 88: + // PlatDownWaitUp + EV_DoPlat(line,downWaitUpStay,0); + break; + + case 89: + // Platform Stop + EV_StopPlat(line); + break; + + case 90: + // Raise Door + EV_DoDoor(line,normal); + break; + + case 91: + // Raise Floor + EV_DoFloor(line,raiseFloor); + break; + + case 92: + // Raise Floor 24 + EV_DoFloor(line,raiseFloor24); + break; + + case 93: + // Raise Floor 24 And Change + EV_DoFloor(line,raiseFloor24AndChange); + break; + + case 94: + // Raise Floor Crush + EV_DoFloor(line,raiseFloorCrush); + break; + + case 95: + // Raise floor to nearest height + // and change texture. + EV_DoPlat(line,raiseToNearestAndChange,0); + break; + + case 96: + // Raise floor to shortest texture height + // on either side of lines. + EV_DoFloor(line,raiseToTexture); + break; + + case 97: + // TELEPORT! + EV_Teleport( line, side, thing ); + break; + + case 98: + // Lower Floor (TURBO) + EV_DoFloor(line,turboLower); + break; + + case 105: + // Blazing Door Raise (faster than TURBO!) + EV_DoDoor (line,blazeRaise); + break; + + case 106: + // Blazing Door Open (faster than TURBO!) + EV_DoDoor (line,blazeOpen); + break; + + case 107: + // Blazing Door Close (faster than TURBO!) + EV_DoDoor (line,blazeClose); + break; + + case 120: + // Blazing PlatDownWaitUpStay. + EV_DoPlat(line,blazeDWUS,0); + break; + + case 126: + // TELEPORT MonsterONLY. + if (!thing->player) + EV_Teleport( line, side, thing ); + break; + + case 128: + // Raise To Nearest Floor + EV_DoFloor(line,raiseFloorToNearest); + break; + + case 129: + // Raise Floor Turbo + EV_DoFloor(line,raiseFloorTurbo); + break; + + // Extended walk triggers + + // jff 1/29/98 added new linedef types to fill all functions out so that + // all have varieties SR, S1, WR, W1 + + // killough 1/31/98: "factor out" compatibility test, by + // adding inner switch qualified by compatibility flag. + // relax test to demo_compatibility + + // killough 2/16/98: Fix problems with W1 types being cleared too early + + default: + if (!demo_compatibility) + switch (line->special) + { + // Extended walk once triggers + + case 142: + // Raise Floor 512 + // 142 W1 EV_DoFloor(raiseFloor512) + if (EV_DoFloor(line,raiseFloor512)) + line->special = 0; + break; + + case 143: + // Raise Floor 24 and change + // 143 W1 EV_DoPlat(raiseAndChange,24) + if (EV_DoPlat(line,raiseAndChange,24)) + line->special = 0; + break; + + case 144: + // Raise Floor 32 and change + // 144 W1 EV_DoPlat(raiseAndChange,32) + if (EV_DoPlat(line,raiseAndChange,32)) + line->special = 0; + break; + + case 145: + // Lower Ceiling to Floor + // 145 W1 EV_DoCeiling(lowerToFloor) + if (EV_DoCeiling( line, lowerToFloor )) + line->special = 0; + break; + + case 146: + // Lower Pillar, Raise Donut + // 146 W1 EV_DoDonut() + if (EV_DoDonut(line)) + line->special = 0; + break; + + case 199: + // Lower ceiling to lowest surrounding ceiling + // 199 W1 EV_DoCeiling(lowerToLowest) + if (EV_DoCeiling(line,lowerToLowest)) + line->special = 0; + break; + + case 200: + // Lower ceiling to highest surrounding floor + // 200 W1 EV_DoCeiling(lowerToMaxFloor) + if (EV_DoCeiling(line,lowerToMaxFloor)) + line->special = 0; + break; + + case 207: + // killough 2/16/98: W1 silent teleporter (normal kind) + if (EV_SilentTeleport(line, side, thing)) + line->special = 0; + break; + + //jff 3/16/98 renumber 215->153 + case 153: //jff 3/15/98 create texture change no motion type + // Texture/Type Change Only (Trig) + // 153 W1 Change Texture/Type Only + if (EV_DoChange(line,trigChangeOnly)) + line->special = 0; + break; + + case 239: //jff 3/15/98 create texture change no motion type + // Texture/Type Change Only (Numeric) + // 239 W1 Change Texture/Type Only + if (EV_DoChange(line,numChangeOnly)) + line->special = 0; + break; + + case 219: + // Lower floor to next lower neighbor + // 219 W1 Lower Floor Next Lower Neighbor + if (EV_DoFloor(line,lowerFloorToNearest)) + line->special = 0; + break; + + case 227: + // Raise elevator next floor + // 227 W1 Raise Elevator next floor + if (EV_DoElevator(line,elevateUp)) + line->special = 0; + break; + + case 231: + // Lower elevator next floor + // 231 W1 Lower Elevator next floor + if (EV_DoElevator(line,elevateDown)) + line->special = 0; + break; + + case 235: + // Elevator to current floor + // 235 W1 Elevator to current floor + if (EV_DoElevator(line,elevateCurrent)) + line->special = 0; + break; + + case 243: //jff 3/6/98 make fit within DCK's 256 linedef types + // killough 2/16/98: W1 silent teleporter (linedef-linedef kind) + if (EV_SilentLineTeleport(line, side, thing, false)) + line->special = 0; + break; + + case 262: //jff 4/14/98 add silent line-line reversed + if (EV_SilentLineTeleport(line, side, thing, true)) + line->special = 0; + break; + + case 264: //jff 4/14/98 add monster-only silent line-line reversed + if (!thing->player && + EV_SilentLineTeleport(line, side, thing, true)) + line->special = 0; + break; + + case 266: //jff 4/14/98 add monster-only silent line-line + if (!thing->player && + EV_SilentLineTeleport(line, side, thing, false)) + line->special = 0; + break; + + case 268: //jff 4/14/98 add monster-only silent + if (!thing->player && EV_SilentTeleport(line, side, thing)) + line->special = 0; + break; + + //jff 1/29/98 end of added W1 linedef types + + // Extended walk many retriggerable + + //jff 1/29/98 added new linedef types to fill all functions + //out so that all have varieties SR, S1, WR, W1 + + case 147: + // Raise Floor 512 + // 147 WR EV_DoFloor(raiseFloor512) + EV_DoFloor(line,raiseFloor512); + break; + + case 148: + // Raise Floor 24 and Change + // 148 WR EV_DoPlat(raiseAndChange,24) + EV_DoPlat(line,raiseAndChange,24); + break; + + case 149: + // Raise Floor 32 and Change + // 149 WR EV_DoPlat(raiseAndChange,32) + EV_DoPlat(line,raiseAndChange,32); + break; + + case 150: + // Start slow silent crusher + // 150 WR EV_DoCeiling(silentCrushAndRaise) + EV_DoCeiling(line,silentCrushAndRaise); + break; + + case 151: + // RaiseCeilingLowerFloor + // 151 WR EV_DoCeiling(raiseToHighest), + // EV_DoFloor(lowerFloortoLowest) + EV_DoCeiling( line, raiseToHighest ); + EV_DoFloor( line, lowerFloorToLowest ); + break; + + case 152: + // Lower Ceiling to Floor + // 152 WR EV_DoCeiling(lowerToFloor) + EV_DoCeiling( line, lowerToFloor ); + break; + + //jff 3/16/98 renumber 153->256 + case 256: + // Build stairs, step 8 + // 256 WR EV_BuildStairs(build8) + EV_BuildStairs(line,build8); + break; + + //jff 3/16/98 renumber 154->257 + case 257: + // Build stairs, step 16 + // 257 WR EV_BuildStairs(turbo16) + EV_BuildStairs(line,turbo16); + break; + + case 155: + // Lower Pillar, Raise Donut + // 155 WR EV_DoDonut() + EV_DoDonut(line); + break; + + case 156: + // Start lights strobing + // 156 WR Lights EV_StartLightStrobing() + EV_StartLightStrobing(line); + break; + + case 157: + // Lights to dimmest near + // 157 WR Lights EV_TurnTagLightsOff() + EV_TurnTagLightsOff(line); + break; + + case 201: + // Lower ceiling to lowest surrounding ceiling + // 201 WR EV_DoCeiling(lowerToLowest) + EV_DoCeiling(line,lowerToLowest); + break; + + case 202: + // Lower ceiling to highest surrounding floor + // 202 WR EV_DoCeiling(lowerToMaxFloor) + EV_DoCeiling(line,lowerToMaxFloor); + break; + + case 208: + // killough 2/16/98: WR silent teleporter (normal kind) + EV_SilentTeleport(line, side, thing); + break; + + case 212: //jff 3/14/98 create instant toggle floor type + // Toggle floor between C and F instantly + // 212 WR Instant Toggle Floor + EV_DoPlat(line,toggleUpDn,0); + break; + + //jff 3/16/98 renumber 216->154 + case 154: //jff 3/15/98 create texture change no motion type + // Texture/Type Change Only (Trigger) + // 154 WR Change Texture/Type Only + EV_DoChange(line,trigChangeOnly); + break; + + case 240: //jff 3/15/98 create texture change no motion type + // Texture/Type Change Only (Numeric) + // 240 WR Change Texture/Type Only + EV_DoChange(line,numChangeOnly); + break; + + case 220: + // Lower floor to next lower neighbor + // 220 WR Lower Floor Next Lower Neighbor + EV_DoFloor(line,lowerFloorToNearest); + break; + + case 228: + // Raise elevator next floor + // 228 WR Raise Elevator next floor + EV_DoElevator(line,elevateUp); + break; + + case 232: + // Lower elevator next floor + // 232 WR Lower Elevator next floor + EV_DoElevator(line,elevateDown); + break; + + case 236: + // Elevator to current floor + // 236 WR Elevator to current floor + EV_DoElevator(line,elevateCurrent); + break; + + case 244: //jff 3/6/98 make fit within DCK's 256 linedef types + // killough 2/16/98: WR silent teleporter (linedef-linedef kind) + EV_SilentLineTeleport(line, side, thing, false); + break; + + case 263: //jff 4/14/98 add silent line-line reversed + EV_SilentLineTeleport(line, side, thing, true); + break; + + case 265: //jff 4/14/98 add monster-only silent line-line reversed + if (!thing->player) + EV_SilentLineTeleport(line, side, thing, true); + break; + + case 267: //jff 4/14/98 add monster-only silent line-line + if (!thing->player) + EV_SilentLineTeleport(line, side, thing, false); + break; + + case 269: //jff 4/14/98 add monster-only silent + if (!thing->player) + EV_SilentTeleport(line, side, thing); + break; + + //jff 1/29/98 end of added WR linedef types + } + break; + } +} + +// +// P_ShootSpecialLine - Gun trigger special dispatcher +// +// Called when a thing shoots a special line with bullet, shell, saw, or fist. +// +// jff 02/12/98 all G1 lines were fixed to check the result from the EV_ +// function before clearing the special. This avoids losing the function +// of the line, should the sector already be in motion when the line is +// impacted. Change is qualified by demo_compatibility. +// +void P_ShootSpecialLine +( mobj_t* thing, + line_t* line ) +{ + //jff 02/04/98 add check here for generalized linedef + if (!demo_compatibility) + { + // pointer to line function is NULL by default, set non-null if + // line special is gun triggered generalized linedef type + int (*linefunc)(line_t *line)=NULL; + + // check each range of generalized linedefs + if ((unsigned)line->special >= GenEnd) + { + // Out of range for GenFloors + } + else if ((unsigned)line->special >= GenFloorBase) + { + if (!thing->player) + if ((line->special & FloorChange) || !(line->special & FloorModel)) + return; // FloorModel is "Allow Monsters" if FloorChange is 0 + if (!line->tag) //jff 2/27/98 all gun generalized types require tag + return; + + linefunc = EV_DoGenFloor; + } + else if ((unsigned)line->special >= GenCeilingBase) + { + if (!thing->player) + if ((line->special & CeilingChange) || !(line->special & CeilingModel)) + return; // CeilingModel is "Allow Monsters" if CeilingChange is 0 + if (!line->tag) //jff 2/27/98 all gun generalized types require tag + return; + linefunc = EV_DoGenCeiling; + } + else if ((unsigned)line->special >= GenDoorBase) + { + if (!thing->player) + { + if (!(line->special & DoorMonster)) + return; // monsters disallowed from this door + if (line->flags & ML_SECRET) // they can't open secret doors either + return; + } + if (!line->tag) //jff 3/2/98 all gun generalized types require tag + return; + linefunc = EV_DoGenDoor; + } + else if ((unsigned)line->special >= GenLockedBase) + { + if (!thing->player) + return; // monsters disallowed from unlocking doors + if (((line->special&TriggerType)==GunOnce) || ((line->special&TriggerType)==GunMany)) + { //jff 4/1/98 check for being a gun type before reporting door type + if (!P_CanUnlockGenDoor(line,thing->player)) + return; + } + else + return; + if (!line->tag) //jff 2/27/98 all gun generalized types require tag + return; + + linefunc = EV_DoGenLockedDoor; + } + else if ((unsigned)line->special >= GenLiftBase) + { + if (!thing->player) + if (!(line->special & LiftMonster)) + return; // monsters disallowed + linefunc = EV_DoGenLift; + } + else if ((unsigned)line->special >= GenStairsBase) + { + if (!thing->player) + if (!(line->special & StairMonster)) + return; // monsters disallowed + if (!line->tag) //jff 2/27/98 all gun generalized types require tag + return; + linefunc = EV_DoGenStairs; + } + else if ((unsigned)line->special >= GenCrusherBase) + { + if (!thing->player) + if (!(line->special & StairMonster)) + return; // monsters disallowed + if (!line->tag) //jff 2/27/98 all gun generalized types require tag + return; + linefunc = EV_DoGenCrusher; + } + + if (linefunc) + switch((line->special & TriggerType) >> TriggerTypeShift) + { + case GunOnce: + if (linefunc(line)) + P_ChangeSwitchTexture(line,0); + return; + case GunMany: + if (linefunc(line)) + P_ChangeSwitchTexture(line,1); + return; + default: // if not a gun type, do nothing here + return; + } + } + + // Impacts that other things can activate. + if (!thing->player) + { + int ok = 0; + switch(line->special) + { + case 46: + // 46 GR Open door on impact weapon is monster activatable + ok = 1; + break; + } + if (!ok) + return; + } + + if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types + return; + + switch(line->special) + { + case 24: + // 24 G1 raise floor to highest adjacent + if (EV_DoFloor(line,raiseFloor) || demo_compatibility) + P_ChangeSwitchTexture(line,0); + break; + + case 46: + // 46 GR open door, stay open + EV_DoDoor(line,open); + P_ChangeSwitchTexture(line,1); + break; + + case 47: + // 47 G1 raise floor to nearest and change texture and type + if (EV_DoPlat(line,raiseToNearestAndChange,0) || demo_compatibility) + P_ChangeSwitchTexture(line,0); + break; + + //jff 1/30/98 added new gun linedefs here + // killough 1/31/98: added demo_compatibility check, added inner switch + + default: + if (!demo_compatibility) + switch (line->special) + { + case 197: + // Exit to next level + // killough 10/98: prevent zombies from exiting levels + if(thing->player && thing->player->health<=0 && !comp[comp_zombie]) + break; + P_ChangeSwitchTexture(line,0); + G_ExitLevel(); + break; + + case 198: + // Exit to secret level + // killough 10/98: prevent zombies from exiting levels + if(thing->player && thing->player->health<=0 && !comp[comp_zombie]) + break; + P_ChangeSwitchTexture(line,0); + G_SecretExitLevel(); + break; + //jff end addition of new gun linedefs + } + break; + } +} + + +// +// P_PlayerInSpecialSector() +// +// Called every tick frame +// that the player origin is in a special sector +// +// Changed to ignore sector types the engine does not recognize +// +void P_PlayerInSpecialSector (player_t* player) +{ + sector_t* sector; + + sector = player->mo->subsector->sector; + + // Falling, not all the way down yet? + // Sector specials don't apply in mid-air + if (player->mo->z != sector->floorheight) + return; + + // Has hit ground. + //jff add if to handle old vs generalized types + if (sector->special<32) // regular sector specials + { + switch (sector->special) + { + case 5: + // 5/10 unit damage per 31 ticks + if (!player->powers[pw_ironfeet]) + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 10); + break; + + case 7: + // 2/5 unit damage per 31 ticks + if (!player->powers[pw_ironfeet]) + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 5); + break; + + case 16: + // 10/20 unit damage per 31 ticks + case 4: + // 10/20 unit damage plus blinking light (light already spawned) + if (!player->powers[pw_ironfeet] + || (P_Random(pr_slimehurt)<5) ) // even with suit, take damage + { + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 20); + } + break; + + case 9: + // Tally player in secret sector, clear secret special + player->secretcount++; + sector->special = 0; + break; + + case 11: + // Exit on health < 11, take 10/20 damage per 31 ticks + if (comp[comp_god]) /* killough 2/21/98: add compatibility switch */ + player->cheats &= ~CF_GODMODE; // on godmode cheat clearing + // does not affect invulnerability + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 20); + + if (player->health <= 10) + G_ExitLevel(); + break; + + default: + //jff 1/24/98 Don't exit as DOOM2 did, just ignore + break; + }; + } + else //jff 3/14/98 handle extended sector types for secrets and damage + { + switch ((sector->special&DAMAGE_MASK)>>DAMAGE_SHIFT) + { + case 0: // no damage + break; + case 1: // 2/5 damage per 31 ticks + if (!player->powers[pw_ironfeet]) + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 5); + break; + case 2: // 5/10 damage per 31 ticks + if (!player->powers[pw_ironfeet]) + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 10); + break; + case 3: // 10/20 damage per 31 ticks + if (!player->powers[pw_ironfeet] + || (P_Random(pr_slimehurt)<5)) // take damage even with suit + { + if (!(leveltime&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 20); + } + break; + } + if (sector->special&SECRET_MASK) + { + player->secretcount++; + sector->special &= ~SECRET_MASK; + if (sector->special<32) // if all extended bits clear, + sector->special=0; // sector is not special anymore + } + + // phares 3/19/98: + // + // If FRICTION_MASK or PUSH_MASK is set, we don't care at this + // point, since the code to deal with those situations is + // handled by Thinkers. + + } +} + +// +// P_UpdateSpecials() +// +// Check level timer, frag counter, +// animate flats, scroll walls, +// change button textures +// +// Reads and modifies globals: +// levelTimer, levelTimeCount, +// levelFragLimit, levelFragLimitCount +// + +static boolean levelTimer; +static int levelTimeCount; +boolean levelFragLimit; // Ty 03/18/98 Added -frags support +int levelFragLimitCount; // Ty 03/18/98 Added -frags support + +void P_UpdateSpecials (void) +{ + anim_t* anim; + int pic; + int i; + + // Downcount level timer, exit level if elapsed + if (levelTimer == true) + { + levelTimeCount--; + if (!levelTimeCount) + G_ExitLevel(); + } + + // Check frag counters, if frag limit reached, exit level // Ty 03/18/98 + // Seems like the total frags should be kept in a simple + // array somewhere, but until they are... + if (levelFragLimit == true) // we used -frags so compare count + { + int k,m,fragcount,exitflag=false; + for (k=0;k= levelFragLimitCount) exitflag = true; + if (exitflag == true) break; // skip out of the loop--we're done + } + if (exitflag == true) + G_ExitLevel(); + } + + // Animate flats and textures globally + for (anim = anims ; anim < lastanim ; anim++) + { + for (i=anim->basepic ; ibasepic+anim->numpics ; i++) + { + pic = anim->basepic + ( (leveltime/anim->speed + i)%anim->numpics ); + if (anim->istexture) + texturetranslation[i] = pic; + else + flattranslation[i] = pic; + } + } + + // Check buttons (retriggerable switches) and change texture on timeout + for (i = 0; i < MAXBUTTONS; i++) + if (buttonlist[i].btimer) + { + buttonlist[i].btimer--; + if (!buttonlist[i].btimer) + { + switch(buttonlist[i].where) + { + case top: + sides[buttonlist[i].line->sidenum[0]].toptexture = + buttonlist[i].btexture; + break; + + case middle: + sides[buttonlist[i].line->sidenum[0]].midtexture = + buttonlist[i].btexture; + break; + + case bottom: + sides[buttonlist[i].line->sidenum[0]].bottomtexture = + buttonlist[i].btexture; + break; + } + { + /* don't take the address of the switch's sound origin, + * unless in a compatibility mode. */ + mobj_t *so = (mobj_t *)buttonlist[i].soundorg; + if (comp[comp_sound] || compatibility_level < prboom_6_compatibility) + /* since the buttonlist array is usually zeroed out, + * button popouts generally appear to come from (0,0) */ + so = (mobj_t *)&buttonlist[i].soundorg; + S_StartSound(so, sfx_swtchn); + } + memset(&buttonlist[i],0,sizeof(button_t)); + } + } +} + +////////////////////////////////////////////////////////////////////// +// +// Sector and Line special thinker spawning at level startup +// +////////////////////////////////////////////////////////////////////// + +// +// P_SpawnSpecials +// After the map has been loaded, +// scan for specials that spawn thinkers +// + +// Parses command line parameters. +void P_SpawnSpecials (void) +{ + sector_t* sector; + int i; + int episode; + + episode = 1; + if (W_CheckNumForName("texture2") >= 0) + episode = 2; + + // See if -timer needs to be used. + levelTimer = false; + + i = M_CheckParm("-avg"); // Austin Virtual Gaming 20 min timer on DM play + if (i && deathmatch) + { + levelTimer = true; + levelTimeCount = 20 * 60 * TICRATE; + } + + i = M_CheckParm("-timer"); // user defined timer on game play + if (i && deathmatch) + { + int time; + time = atoi(myargv[i+1]) * 60 * TICRATE; + levelTimer = true; + levelTimeCount = time; + } + + // See if -frags has been used + levelFragLimit = false; + i = M_CheckParm("-frags"); // Ty 03/18/98 Added -frags support + if (i && deathmatch) + { + int frags; + frags = atoi(myargv[i+1]); + if (frags <= 0) frags = 10; // default 10 if no count provided + levelFragLimit = true; + levelFragLimitCount = frags; + } + + + // Init special sectors. + sector = sectors; + for (i=0 ; ispecial) + continue; + + if (sector->special&SECRET_MASK) //jff 3/15/98 count extended + totalsecret++; // secret sectors too + + switch (sector->special&31) + { + case 1: + // random off + P_SpawnLightFlash (sector); + break; + + case 2: + // strobe fast + P_SpawnStrobeFlash(sector,FASTDARK,0); + break; + + case 3: + // strobe slow + P_SpawnStrobeFlash(sector,SLOWDARK,0); + break; + + case 4: + // strobe fast/death slime + P_SpawnStrobeFlash(sector,FASTDARK,0); + sector->special |= 3<special<32) //jff 3/14/98 bits don't count unless not + totalsecret++; // a generalized sector type + break; + + case 10: + // door close in 30 seconds + P_SpawnDoorCloseIn30 (sector); + break; + + case 12: + // sync strobe slow + P_SpawnStrobeFlash (sector, SLOWDARK, 1); + break; + + case 13: + // sync strobe fast + P_SpawnStrobeFlash (sector, FASTDARK, 1); + break; + + case 14: + // door raise in 5 minutes + P_SpawnDoorRaiseIn5Mins (sector, i); + break; + + case 17: + // fire flickering + P_SpawnFireFlicker(sector); + break; + } + } + + P_RemoveAllActiveCeilings(); // jff 2/22/98 use killough's scheme + + P_RemoveAllActivePlats(); // killough + + for (i = 0;i < MAXBUTTONS;i++) + memset(&buttonlist[i],0,sizeof(button_t)); + + // P_InitTagLists() must be called before P_FindSectorFromLineTag() + // or P_FindLineFromLineTag() can be called. + + P_InitTagLists(); // killough 1/30/98: Create xref tables for tags + + P_SpawnScrollers(); // killough 3/7/98: Add generalized scrollers + + P_SpawnFriction(); // phares 3/12/98: New friction model using linedefs + + P_SpawnPushers(); // phares 3/20/98: New pusher model using linedefs + + for (i=0; i= 0;) + sectors[s].heightsec = sec; + break; + + // killough 3/16/98: Add support for setting + // floor lighting independently (e.g. lava) + case 213: + sec = sides[*lines[i].sidenum].sector-sectors; + for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;) + sectors[s].floorlightsec = sec; + break; + + // killough 4/11/98: Add support for setting + // ceiling lighting independently + case 261: + sec = sides[*lines[i].sidenum].sector-sectors; + for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;) + sectors[s].ceilinglightsec = sec; + break; + + // killough 10/98: + // + // Support for sky textures being transferred from sidedefs. + // Allows scrolling and other effects (but if scrolling is + // used, then the same sector tag needs to be used for the + // sky sector, the sky-transfer linedef, and the scroll-effect + // linedef). Still requires user to use F_SKY1 for the floor + // or ceiling texture, to distinguish floor and ceiling sky. + + case 271: // Regular sky + case 272: // Same, only flipped + for (s = -1; (s = P_FindSectorFromLineTag(lines+i,s)) >= 0;) + sectors[s].sky = i | PL_SKYFLAT; + break; + } +} + +// killough 2/28/98: +// +// This function, with the help of r_plane.c and r_bsp.c, supports generalized +// scrolling floors and walls, with optional mobj-carrying properties, e.g. +// conveyor belts, rivers, etc. A linedef with a special type affects all +// tagged sectors the same way, by creating scrolling and/or object-carrying +// properties. Multiple linedefs may be used on the same sector and are +// cumulative, although the special case of scrolling a floor and carrying +// things on it, requires only one linedef. The linedef's direction determines +// the scrolling direction, and the linedef's length determines the scrolling +// speed. This was designed so that an edge around the sector could be used to +// control the direction of the sector's scrolling, which is usually what is +// desired. +// +// Process the active scrollers. +// +// This is the main scrolling code +// killough 3/7/98 + +void T_Scroll(scroll_t *s) +{ + fixed_t dx = s->dx, dy = s->dy; + + if (s->control != -1) + { // compute scroll amounts based on a sector's height changes + fixed_t height = sectors[s->control].floorheight + + sectors[s->control].ceilingheight; + fixed_t delta = height - s->last_height; + s->last_height = height; + dx = FixedMul(dx, delta); + dy = FixedMul(dy, delta); + } + + // killough 3/14/98: Add acceleration + if (s->accel) + { + s->vdx = dx += s->vdx; + s->vdy = dy += s->vdy; + } + + if (!(dx | dy)) // no-op if both (x,y) offsets 0 + return; + + switch (s->type) + { + side_t *side; + sector_t *sec; + fixed_t height, waterheight; // killough 4/4/98: add waterheight + msecnode_t *node; + mobj_t *thing; + + case sc_side: // killough 3/7/98: Scroll wall texture + side = sides + s->affectee; + side->textureoffset += dx; + side->rowoffset += dy; + break; + + case sc_floor: // killough 3/7/98: Scroll floor texture + sec = sectors + s->affectee; + sec->floor_xoffs += dx; + sec->floor_yoffs += dy; + break; + + case sc_ceiling: // killough 3/7/98: Scroll ceiling texture + sec = sectors + s->affectee; + sec->ceiling_xoffs += dx; + sec->ceiling_yoffs += dy; + break; + + case sc_carry: + + // killough 3/7/98: Carry things on floor + // killough 3/20/98: use new sector list which reflects true members + // killough 3/27/98: fix carrier bug + // killough 4/4/98: Underwater, carry things even w/o gravity + + sec = sectors + s->affectee; + height = sec->floorheight; + waterheight = sec->heightsec != -1 && + sectors[sec->heightsec].floorheight > height ? + sectors[sec->heightsec].floorheight : INT_MIN; + + for (node = sec->touching_thinglist; node; node = node->m_snext) + if (!((thing = node->m_thing)->flags & MF_NOCLIP) && + (!(thing->flags & MF_NOGRAVITY || thing->z > height) || + thing->z < waterheight)) + { + // Move objects only if on floor or underwater, + // non-floating, and clipped. + thing->momx += dx; + thing->momy += dy; + } + break; + + case sc_carry_ceiling: // to be added later + break; + } +} + +// +// Add_Scroller() +// +// Add a generalized scroller to the thinker list. +// +// type: the enumerated type of scrolling: floor, ceiling, floor carrier, +// wall, floor carrier & scroller +// +// (dx,dy): the direction and speed of the scrolling or its acceleration +// +// control: the sector whose heights control this scroller's effect +// remotely, or -1 if no control sector +// +// affectee: the index of the affected object (sector or sidedef) +// +// accel: non-zero if this is an accelerative effect +// + +static void Add_Scroller(int type, fixed_t dx, fixed_t dy, + int control, int affectee, int accel) +{ + scroll_t *s = Z_Malloc(sizeof *s, PU_LEVSPEC, 0); + s->thinker.function = T_Scroll; + s->type = type; + s->dx = dx; + s->dy = dy; + s->accel = accel; + s->vdx = s->vdy = 0; + if ((s->control = control) != -1) + s->last_height = + sectors[control].floorheight + sectors[control].ceilingheight; + s->affectee = affectee; + P_AddThinker(&s->thinker); +} + +// Adds wall scroller. Scroll amount is rotated with respect to wall's +// linedef first, so that scrolling towards the wall in a perpendicular +// direction is translated into vertical motion, while scrolling along +// the wall in a parallel direction is translated into horizontal motion. +// +// killough 5/25/98: cleaned up arithmetic to avoid drift due to roundoff +// +// killough 10/98: +// fix scrolling aliasing problems, caused by long linedefs causing overflowing + +static void Add_WallScroller(fixed_t dx, fixed_t dy, const line_t *l, + int control, int accel) +{ + fixed_t x = D_abs(l->dx), y = D_abs(l->dy), d; + if (y > x) + d = x, x = y, y = d; + d = FixedDiv(x, finesine[(tantoangle[FixedDiv(y,x) >> DBITS] + ANG90) + >> ANGLETOFINESHIFT]); + + // CPhipps - Import scroller calc overflow fix, compatibility optioned + if (compatibility_level >= lxdoom_1_compatibility) { + x = (fixed_t)(((int_64_t)dy * -(int_64_t)l->dy - (int_64_t)dx * (int_64_t)l->dx) / (int_64_t)d); // killough 10/98: + y = (fixed_t)(((int_64_t)dy * (int_64_t)l->dx - (int_64_t)dx * (int_64_t)l->dy) / (int_64_t)d); // Use long long arithmetic + } else { + x = -FixedDiv(FixedMul(dy, l->dy) + FixedMul(dx, l->dx), d); + y = -FixedDiv(FixedMul(dx, l->dy) - FixedMul(dy, l->dx), d); + } + Add_Scroller(sc_side, x, y, control, *l->sidenum, accel); +} + +// Amount (dx,dy) vector linedef is shifted right to get scroll amount +#define SCROLL_SHIFT 5 + +// Factor to scale scrolling effect into mobj-carrying properties = 3/32. +// (This is so scrolling floors and objects on them can move at same speed.) +#define CARRYFACTOR ((fixed_t)(FRACUNIT*.09375)) + +// Initialize the scrollers +static void P_SpawnScrollers(void) +{ + int i; + line_t *l = lines; + + for (i=0;idx >> SCROLL_SHIFT; // direction and speed of scrolling + fixed_t dy = l->dy >> SCROLL_SHIFT; + int control = -1, accel = 0; // no control sector or acceleration + int special = l->special; + + // killough 3/7/98: Types 245-249 are same as 250-254 except that the + // first side's sector's heights cause scrolling when they change, and + // this linedef controls the direction and speed of the scrolling. The + // most complicated linedef since donuts, but powerful :) + // + // killough 3/15/98: Add acceleration. Types 214-218 are the same but + // are accelerative. + + if (special >= 245 && special <= 249) // displacement scrollers + { + special += 250-245; + control = sides[*l->sidenum].sector - sectors; + } + else + if (special >= 214 && special <= 218) // accelerative scrollers + { + accel = 1; + special += 250-214; + control = sides[*l->sidenum].sector - sectors; + } + + switch (special) + { + register int s; + + case 250: // scroll effect ceiling + for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;) + Add_Scroller(sc_ceiling, -dx, dy, control, s, accel); + break; + + case 251: // scroll effect floor + case 253: // scroll and carry objects on floor + for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;) + Add_Scroller(sc_floor, -dx, dy, control, s, accel); + if (special != 253) + break; + + case 252: // carry objects on floor + dx = FixedMul(dx,CARRYFACTOR); + dy = FixedMul(dy,CARRYFACTOR); + for (s=-1; (s = P_FindSectorFromLineTag(l,s)) >= 0;) + Add_Scroller(sc_carry, dx, dy, control, s, accel); + break; + + // killough 3/1/98: scroll wall according to linedef + // (same direction and speed as scrolling floors) + case 254: + for (s=-1; (s = P_FindLineFromLineTag(l,s)) >= 0;) + if (s != i) + Add_WallScroller(dx, dy, lines+s, control, accel); + break; + + case 255: // killough 3/2/98: scroll according to sidedef offsets + s = lines[i].sidenum[0]; + Add_Scroller(sc_side, -sides[s].textureoffset, + sides[s].rowoffset, -1, s, accel); + break; + + case 48: // scroll first side + Add_Scroller(sc_side, FRACUNIT, 0, -1, lines[i].sidenum[0], accel); + break; + + case 85: // jff 1/30/98 2-way scroll + Add_Scroller(sc_side, -FRACUNIT, 0, -1, lines[i].sidenum[0], accel); + break; + } + } +} + +// e6y +// restored boom's friction code + +///////////////////////////// +// +// Add a friction thinker to the thinker list +// +// Add_Friction adds a new friction thinker to the list of active thinkers. +// + +static void Add_Friction(int friction, int movefactor, int affectee) + { + friction_t *f = Z_Malloc(sizeof *f, PU_LEVSPEC, 0); + + f->thinker.function/*.acp1*/ = /*(actionf_p1) */T_Friction; + f->friction = friction; + f->movefactor = movefactor; + f->affectee = affectee; + P_AddThinker(&f->thinker); + } + +///////////////////////////// +// +// This is where abnormal friction is applied to objects in the sectors. +// A friction thinker has been spawned for each sector where less or +// more friction should be applied. The amount applied is proportional to +// the length of the controlling linedef. + +void T_Friction(friction_t *f) + { + sector_t *sec; + mobj_t *thing; + msecnode_t* node; + + if (compatibility || !variable_friction) + return; + + sec = sectors + f->affectee; + + // Be sure the special sector type is still turned on. If so, proceed. + // Else, bail out; the sector type has been changed on us. + + if (!(sec->special & FRICTION_MASK)) + return; + + // Assign the friction value to players on the floor, non-floating, + // and clipped. Normally the object's friction value is kept at + // ORIG_FRICTION and this thinker changes it for icy or muddy floors. + + // In Phase II, you can apply friction to Things other than players. + + // When the object is straddling sectors with the same + // floorheight that have different frictions, use the lowest + // friction value (muddy has precedence over icy). + + node = sec->touching_thinglist; // things touching this sector + while (node) + { + thing = node->m_thing; + if (thing->player && + !(thing->flags & (MF_NOGRAVITY | MF_NOCLIP)) && + thing->z <= sec->floorheight) + { + if ((thing->friction == ORIG_FRICTION) || // normal friction? + (f->friction < thing->friction)) + { + thing->friction = f->friction; + thing->movefactor = f->movefactor; + } + } + node = node->m_snext; + } + } + + +// killough 3/7/98 -- end generalized scroll effects + +//////////////////////////////////////////////////////////////////////////// +// +// FRICTION EFFECTS +// +// phares 3/12/98: Start of friction effects +// +// As the player moves, friction is applied by decreasing the x and y +// momentum values on each tic. By varying the percentage of decrease, +// we can simulate muddy or icy conditions. In mud, the player slows +// down faster. In ice, the player slows down more slowly. +// +// The amount of friction change is controlled by the length of a linedef +// with type 223. A length < 100 gives you mud. A length > 100 gives you ice. +// +// Also, each sector where these effects are to take place is given a +// new special type _______. Changing the type value at runtime allows +// these effects to be turned on or off. +// +// Sector boundaries present problems. The player should experience these +// friction changes only when his feet are touching the sector floor. At +// sector boundaries where floor height changes, the player can find +// himself still 'in' one sector, but with his feet at the floor level +// of the next sector (steps up or down). To handle this, Thinkers are used +// in icy/muddy sectors. These thinkers examine each object that is touching +// their sectors, looking for players whose feet are at the same level as +// their floors. Players satisfying this condition are given new friction +// values that are applied by the player movement code later. +// +// killough 8/28/98: +// +// Completely redid code, which did not need thinkers, and which put a heavy +// drag on CPU. Friction is now a property of sectors, NOT objects inside +// them. All objects, not just players, are affected by it, if they touch +// the sector's floor. Code simpler and faster, only calling on friction +// calculations when an object needs friction considered, instead of doing +// friction calculations on every sector during every tic. +// +// Although this -might- ruin Boom demo sync involving friction, it's the only +// way, short of code explosion, to fix the original design bug. Fixing the +// design bug in Boom's original friction code, while maintaining demo sync +// under every conceivable circumstance, would double or triple code size, and +// would require maintenance of buggy legacy code which is only useful for old +// demos. Doom demos, which are more important IMO, are not affected by this +// change. +// +///////////////////////////// +// +// Initialize the sectors where friction is increased or decreased + +static void P_SpawnFriction(void) +{ + int i; + line_t *l = lines; + + // killough 8/28/98: initialize all sectors to normal friction first + for (i = 0; i < numsectors; i++) + { + sectors[i].friction = ORIG_FRICTION; + sectors[i].movefactor = ORIG_FRICTION_FACTOR; + } + + for (i = 0 ; i < numlines ; i++,l++) + if (l->special == 223) + { + int length = P_AproxDistance(l->dx,l->dy)>>FRACBITS; + int friction = (0x1EB8*length)/0x80 + 0xD000; + int movefactor, s; + + // The following check might seem odd. At the time of movement, + // the move distance is multiplied by 'friction/0x10000', so a + // higher friction value actually means 'less friction'. + + if (friction > ORIG_FRICTION) // ice + movefactor = ((0x10092 - friction)*(0x70))/0x158; + else + movefactor = ((friction - 0xDB34)*(0xA))/0x80; + + if (mbf_features) + { // killough 8/28/98: prevent odd situations + if (friction > FRACUNIT) + friction = FRACUNIT; + if (friction < 0) + friction = 0; + if (movefactor < 32) + movefactor = 32; + } + + for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; ) + { + // killough 8/28/98: + // + // Instead of spawning thinkers, which are slow and expensive, + // modify the sector's own friction values. Friction should be + // a property of sectors, not objects which reside inside them. + // Original code scanned every object in every friction sector + // on every tic, adjusting its friction, putting unnecessary + // drag on CPU. New code adjusts friction of sector only once + // at level startup, and then uses this friction value. + + //e6y: boom's friction code for boom compatibility + if (!demo_compatibility && !mbf_features) + Add_Friction(friction,movefactor,s); + + sectors[s].friction = friction; + sectors[s].movefactor = movefactor; + } + } +} + +// +// phares 3/12/98: End of friction effects +// +//////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////// +// +// PUSH/PULL EFFECT +// +// phares 3/20/98: Start of push/pull effects +// +// This is where push/pull effects are applied to objects in the sectors. +// +// There are four kinds of push effects +// +// 1) Pushing Away +// +// Pushes you away from a point source defined by the location of an +// MT_PUSH Thing. The force decreases linearly with distance from the +// source. This force crosses sector boundaries and is felt w/in a circle +// whose center is at the MT_PUSH. The force is felt only if the point +// MT_PUSH can see the target object. +// +// 2) Pulling toward +// +// Same as Pushing Away except you're pulled toward an MT_PULL point +// source. This force crosses sector boundaries and is felt w/in a circle +// whose center is at the MT_PULL. The force is felt only if the point +// MT_PULL can see the target object. +// +// 3) Wind +// +// Pushes you in a constant direction. Full force above ground, half +// force on the ground, nothing if you're below it (water). +// +// 4) Current +// +// Pushes you in a constant direction. No force above ground, full +// force if on the ground or below it (water). +// +// The magnitude of the force is controlled by the length of a controlling +// linedef. The force vector for types 3 & 4 is determined by the angle +// of the linedef, and is constant. +// +// For each sector where these effects occur, the sector special type has +// to have the PUSH_MASK bit set. If this bit is turned off by a switch +// at run-time, the effect will not occur. The controlling sector for +// types 1 & 2 is the sector containing the MT_PUSH/MT_PULL Thing. + + +#define PUSH_FACTOR 7 + +///////////////////////////// +// +// Add a push thinker to the thinker list + +static void Add_Pusher(int type, int x_mag, int y_mag, mobj_t* source, int affectee) + { + pusher_t *p = Z_Malloc(sizeof *p, PU_LEVSPEC, 0); + + p->thinker.function = T_Pusher; + p->source = source; + p->type = type; + p->x_mag = x_mag>>FRACBITS; + p->y_mag = y_mag>>FRACBITS; + p->magnitude = P_AproxDistance(p->x_mag,p->y_mag); + if (source) // point source exist? + { + p->radius = (p->magnitude)<<(FRACBITS+1); // where force goes to zero + p->x = p->source->x; + p->y = p->source->y; + } + p->affectee = affectee; + P_AddThinker(&p->thinker); + } + +///////////////////////////// +// +// PIT_PushThing determines the angle and magnitude of the effect. +// The object's x and y momentum values are changed. +// +// tmpusher belongs to the point source (MT_PUSH/MT_PULL). +// +// killough 10/98: allow to affect things besides players + +pusher_t* tmpusher; // pusher structure for blockmap searches + +static boolean PIT_PushThing(mobj_t* thing) +{ + /* killough 10/98: made more general */ + if (!mbf_features ? + thing->player && !(thing->flags & (MF_NOCLIP | MF_NOGRAVITY)) : + (sentient(thing) || thing->flags & MF_SHOOTABLE) && + !(thing->flags & MF_NOCLIP)) + { + angle_t pushangle; + fixed_t speed; + fixed_t sx = tmpusher->x; + fixed_t sy = tmpusher->y; + + speed = (tmpusher->magnitude - + ((P_AproxDistance(thing->x - sx,thing->y - sy) + >>FRACBITS)>>1))<<(FRACBITS-PUSH_FACTOR-1); + + // killough 10/98: make magnitude decrease with square + // of distance, making it more in line with real nature, + // so long as it's still in range with original formula. + // + // Removes angular distortion, and makes effort required + // to stay close to source, grow increasingly hard as you + // get closer, as expected. Still, it doesn't consider z :( + + if (speed > 0 && mbf_features) + { + int x = (thing->x-sx) >> FRACBITS; + int y = (thing->y-sy) >> FRACBITS; + speed = (int)(((uint_64_t) tmpusher->magnitude << 23) / (x*x+y*y+1)); + } + + // If speed <= 0, you're outside the effective radius. You also have + // to be able to see the push/pull source point. + + if (speed > 0 && P_CheckSight(thing,tmpusher->source)) + { + pushangle = R_PointToAngle2(thing->x,thing->y,sx,sy); + if (tmpusher->source->type == MT_PUSH) + pushangle += ANG180; // away + pushangle >>= ANGLETOFINESHIFT; + thing->momx += FixedMul(speed,finecosine[pushangle]); + thing->momy += FixedMul(speed,finesine[pushangle]); + } + } + return true; +} + +///////////////////////////// +// +// T_Pusher looks for all objects that are inside the radius of +// the effect. +// + +void T_Pusher(pusher_t *p) + { + sector_t *sec; + mobj_t *thing; + msecnode_t* node; + int xspeed,yspeed; + int xl,xh,yl,yh,bx,by; + int radius; + int ht = 0; + + if (!allow_pushers) + return; + + sec = sectors + p->affectee; + + // Be sure the special sector type is still turned on. If so, proceed. + // Else, bail out; the sector type has been changed on us. + + if (!(sec->special & PUSH_MASK)) + return; + + // For constant pushers (wind/current) there are 3 situations: + // + // 1) Affected Thing is above the floor. + // + // Apply the full force if wind, no force if current. + // + // 2) Affected Thing is on the ground. + // + // Apply half force if wind, full force if current. + // + // 3) Affected Thing is below the ground (underwater effect). + // + // Apply no force if wind, full force if current. + + if (p->type == p_push) + { + + // Seek out all pushable things within the force radius of this + // point pusher. Crosses sectors, so use blockmap. + + tmpusher = p; // MT_PUSH/MT_PULL point source + radius = p->radius; // where force goes to zero + tmbbox[BOXTOP] = p->y + radius; + tmbbox[BOXBOTTOM] = p->y - radius; + tmbbox[BOXRIGHT] = p->x + radius; + tmbbox[BOXLEFT] = p->x - radius; + + xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; + xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; + yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; + yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; + for (bx=xl ; bx<=xh ; bx++) + for (by=yl ; by<=yh ; by++) + P_BlockThingsIterator(bx,by,PIT_PushThing); + return; + } + + // constant pushers p_wind and p_current + + if (sec->heightsec != -1) // special water sector? + ht = sectors[sec->heightsec].floorheight; + node = sec->touching_thinglist; // things touching this sector + for ( ; node ; node = node->m_snext) + { + thing = node->m_thing; + if (!thing->player || (thing->flags & (MF_NOGRAVITY | MF_NOCLIP))) + continue; + if (p->type == p_wind) + { + if (sec->heightsec == -1) // NOT special water sector + if (thing->z > thing->floorz) // above ground + { + xspeed = p->x_mag; // full force + yspeed = p->y_mag; + } + else // on ground + { + xspeed = (p->x_mag)>>1; // half force + yspeed = (p->y_mag)>>1; + } + else // special water sector + { + if (thing->z > ht) // above ground + { + xspeed = p->x_mag; // full force + yspeed = p->y_mag; + } + else if (thing->player->viewz < ht) // underwater + xspeed = yspeed = 0; // no force + else // wading in water + { + xspeed = (p->x_mag)>>1; // half force + yspeed = (p->y_mag)>>1; + } + } + } + else // p_current + { + if (sec->heightsec == -1) // NOT special water sector + if (thing->z > sec->floorheight) // above ground + xspeed = yspeed = 0; // no force + else // on ground + { + xspeed = p->x_mag; // full force + yspeed = p->y_mag; + } + else // special water sector + if (thing->z > ht) // above ground + xspeed = yspeed = 0; // no force + else // underwater + { + xspeed = p->x_mag; // full force + yspeed = p->y_mag; + } + } + thing->momx += xspeed<<(FRACBITS-PUSH_FACTOR); + thing->momy += yspeed<<(FRACBITS-PUSH_FACTOR); + } + } + +///////////////////////////// +// +// P_GetPushThing() returns a pointer to an MT_PUSH or MT_PULL thing, +// NULL otherwise. + +mobj_t* P_GetPushThing(int s) + { + mobj_t* thing; + sector_t* sec; + + sec = sectors + s; + thing = sec->thinglist; + while (thing) + { + switch(thing->type) + { + case MT_PUSH: + case MT_PULL: + return thing; + default: + break; + } + thing = thing->snext; + } + return NULL; + } + +///////////////////////////// +// +// Initialize the sectors where pushers are present +// + +static void P_SpawnPushers(void) + { + int i; + line_t *l = lines; + register int s; + mobj_t* thing; + + for (i = 0 ; i < numlines ; i++,l++) + switch(l->special) + { + case 224: // wind + for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; ) + Add_Pusher(p_wind,l->dx,l->dy,NULL,s); + break; + case 225: // current + for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; ) + Add_Pusher(p_current,l->dx,l->dy,NULL,s); + break; + case 226: // push/pull + for (s = -1; (s = P_FindSectorFromLineTag(l,s)) >= 0 ; ) + { + thing = P_GetPushThing(s); + if (thing) // No MT_P* means no effect + Add_Pusher(p_push,l->dx,l->dy,thing,s); + } + break; + } + } + +// +// phares 3/20/98: End of Pusher effects +// +//////////////////////////////////////////////////////////////////////////// diff --git a/src/p_spec.h b/src/p_spec.h new file mode 100644 index 0000000..1d5aa2b --- /dev/null +++ b/src/p_spec.h @@ -0,0 +1,1141 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: definitions, declarations and prototypes for specials + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_SPEC__ +#define __P_SPEC__ + +#include "r_defs.h" +#include "d_player.h" + +// Define values for map objects +#define MO_TELEPORTMAN 14 + +// p_floor + +#define ELEVATORSPEED (FRACUNIT*4) +#define FLOORSPEED FRACUNIT + +// p_ceilng + +#define CEILSPEED FRACUNIT +#define CEILWAIT 150 + +// p_doors + +#define VDOORSPEED (FRACUNIT*2) +#define VDOORWAIT 150 + +// p_plats + +#define PLATWAIT 3 +#define PLATSPEED FRACUNIT + +// p_switch + +// 4 players, 4 buttons each at once, max. +// killough 2/14/98: redefine in terms of MAXPLAYERS +#define MAXBUTTONS (MAXPLAYERS*4) + +// 1 second, in ticks. +#define BUTTONTIME TICRATE + +// p_lights + +#define GLOWSPEED 8 +#define STROBEBRIGHT 5 +#define FASTDARK 15 +#define SLOWDARK 35 + +//jff 3/14/98 add bits and shifts for generalized sector types + +#define DAMAGE_MASK 0x60 +#define DAMAGE_SHIFT 5 +#define SECRET_MASK 0x80 +#define SECRET_SHIFT 7 +#define FRICTION_MASK 0x100 +#define FRICTION_SHIFT 8 +#define PUSH_MASK 0x200 +#define PUSH_SHIFT 9 + +//jff 02/04/98 Define masks, shifts, for fields in +// generalized linedef types + +#define GenEnd 0x8000 +#define GenFloorBase 0x6000 +#define GenCeilingBase 0x4000 +#define GenDoorBase 0x3c00 +#define GenLockedBase 0x3800 +#define GenLiftBase 0x3400 +#define GenStairsBase 0x3000 +#define GenCrusherBase 0x2F80 + +#define TriggerType 0x0007 +#define TriggerTypeShift 0 + +// define masks and shifts for the floor type fields + +#define FloorCrush 0x1000 +#define FloorChange 0x0c00 +#define FloorTarget 0x0380 +#define FloorDirection 0x0040 +#define FloorModel 0x0020 +#define FloorSpeed 0x0018 + +#define FloorCrushShift 12 +#define FloorChangeShift 10 +#define FloorTargetShift 7 +#define FloorDirectionShift 6 +#define FloorModelShift 5 +#define FloorSpeedShift 3 + +// define masks and shifts for the ceiling type fields + +#define CeilingCrush 0x1000 +#define CeilingChange 0x0c00 +#define CeilingTarget 0x0380 +#define CeilingDirection 0x0040 +#define CeilingModel 0x0020 +#define CeilingSpeed 0x0018 + +#define CeilingCrushShift 12 +#define CeilingChangeShift 10 +#define CeilingTargetShift 7 +#define CeilingDirectionShift 6 +#define CeilingModelShift 5 +#define CeilingSpeedShift 3 + +// define masks and shifts for the lift type fields + +#define LiftTarget 0x0300 +#define LiftDelay 0x00c0 +#define LiftMonster 0x0020 +#define LiftSpeed 0x0018 + +#define LiftTargetShift 8 +#define LiftDelayShift 6 +#define LiftMonsterShift 5 +#define LiftSpeedShift 3 + +// define masks and shifts for the stairs type fields + +#define StairIgnore 0x0200 +#define StairDirection 0x0100 +#define StairStep 0x00c0 +#define StairMonster 0x0020 +#define StairSpeed 0x0018 + +#define StairIgnoreShift 9 +#define StairDirectionShift 8 +#define StairStepShift 6 +#define StairMonsterShift 5 +#define StairSpeedShift 3 + +// define masks and shifts for the crusher type fields + +#define CrusherSilent 0x0040 +#define CrusherMonster 0x0020 +#define CrusherSpeed 0x0018 + +#define CrusherSilentShift 6 +#define CrusherMonsterShift 5 +#define CrusherSpeedShift 3 + +// define masks and shifts for the door type fields + +#define DoorDelay 0x0300 +#define DoorMonster 0x0080 +#define DoorKind 0x0060 +#define DoorSpeed 0x0018 + +#define DoorDelayShift 8 +#define DoorMonsterShift 7 +#define DoorKindShift 5 +#define DoorSpeedShift 3 + +// define masks and shifts for the locked door type fields + +#define LockedNKeys 0x0200 +#define LockedKey 0x01c0 +#define LockedKind 0x0020 +#define LockedSpeed 0x0018 + +#define LockedNKeysShift 9 +#define LockedKeyShift 6 +#define LockedKindShift 5 +#define LockedSpeedShift 3 + +// define names for the TriggerType field of the general linedefs + +typedef enum +{ + WalkOnce, + WalkMany, + SwitchOnce, + SwitchMany, + GunOnce, + GunMany, + PushOnce, + PushMany, +} triggertype_e; + +// define names for the Speed field of the general linedefs + +typedef enum +{ + SpeedSlow, + SpeedNormal, + SpeedFast, + SpeedTurbo, +} motionspeed_e; + +// define names for the Target field of the general floor + +typedef enum +{ + FtoHnF, + FtoLnF, + FtoNnF, + FtoLnC, + FtoC, + FbyST, + Fby24, + Fby32, +} floortarget_e; + +// define names for the Changer Type field of the general floor + +typedef enum +{ + FNoChg, + FChgZero, + FChgTxt, + FChgTyp, +} floorchange_e; + +// define names for the Change Model field of the general floor + +typedef enum +{ + FTriggerModel, + FNumericModel, +} floormodel_t; + +// define names for the Target field of the general ceiling + +typedef enum +{ + CtoHnC, + CtoLnC, + CtoNnC, + CtoHnF, + CtoF, + CbyST, + Cby24, + Cby32, +} ceilingtarget_e; + +// define names for the Changer Type field of the general ceiling + +typedef enum +{ + CNoChg, + CChgZero, + CChgTxt, + CChgTyp, +} ceilingchange_e; + +// define names for the Change Model field of the general ceiling + +typedef enum +{ + CTriggerModel, + CNumericModel, +} ceilingmodel_t; + +// define names for the Target field of the general lift + +typedef enum +{ + F2LnF, + F2NnF, + F2LnC, + LnF2HnF, +} lifttarget_e; + +// define names for the door Kind field of the general ceiling + +typedef enum +{ + OdCDoor, + ODoor, + CdODoor, + CDoor, +} doorkind_e; + +// define names for the locked door Kind field of the general ceiling + +typedef enum +{ + AnyKey, + RCard, + BCard, + YCard, + RSkull, + BSkull, + YSkull, + AllKeys, +} keykind_e; + +////////////////////////////////////////////////////////////////// +// +// enums for classes of linedef triggers +// +////////////////////////////////////////////////////////////////// + +//jff 2/23/98 identify the special classes that can share sectors + +typedef enum +{ + floor_special, + ceiling_special, + lighting_special, +} special_e; + +//jff 3/15/98 pure texture/type change for better generalized support +typedef enum +{ + trigChangeOnly, + numChangeOnly, +} change_e; + +// p_plats + +typedef enum +{ + up, + down, + waiting, + in_stasis +} plat_e; + +typedef enum +{ + perpetualRaise, + downWaitUpStay, + raiseAndChange, + raiseToNearestAndChange, + blazeDWUS, + genLift, //jff added to support generalized Plat types + genPerpetual, + toggleUpDn, //jff 3/14/98 added to support instant toggle type + +} plattype_e; + +// p_doors + +typedef enum +{ + normal, + close30ThenOpen, + close, + open, + raiseIn5Mins, + blazeRaise, + blazeOpen, + blazeClose, + + //jff 02/05/98 add generalize door types + genRaise, + genBlazeRaise, + genOpen, + genBlazeOpen, + genClose, + genBlazeClose, + genCdO, + genBlazeCdO, +} vldoor_e; + +// p_ceilng + +typedef enum +{ + lowerToFloor, + raiseToHighest, + lowerToLowest, + lowerToMaxFloor, + lowerAndCrush, + crushAndRaise, + fastCrushAndRaise, + silentCrushAndRaise, + + //jff 02/04/98 add types for generalized ceiling mover + genCeiling, + genCeilingChg, + genCeilingChg0, + genCeilingChgT, + + //jff 02/05/98 add types for generalized ceiling mover + genCrusher, + genSilentCrusher, + +} ceiling_e; + +// p_floor + +typedef enum +{ + // lower floor to highest surrounding floor + lowerFloor, + + // lower floor to lowest surrounding floor + lowerFloorToLowest, + + // lower floor to highest surrounding floor VERY FAST + turboLower, + + // raise floor to lowest surrounding CEILING + raiseFloor, + + // raise floor to next highest surrounding floor + raiseFloorToNearest, + + //jff 02/03/98 lower floor to next lowest neighbor + lowerFloorToNearest, + + //jff 02/03/98 lower floor 24 absolute + lowerFloor24, + + //jff 02/03/98 lower floor 32 absolute + lowerFloor32Turbo, + + // raise floor to shortest height texture around it + raiseToTexture, + + // lower floor to lowest surrounding floor + // and change floorpic + lowerAndChange, + + raiseFloor24, + + //jff 02/03/98 raise floor 32 absolute + raiseFloor32Turbo, + + raiseFloor24AndChange, + raiseFloorCrush, + + // raise to next highest floor, turbo-speed + raiseFloorTurbo, + donutRaise, + raiseFloor512, + + //jff 02/04/98 add types for generalized floor mover + genFloor, + genFloorChg, + genFloorChg0, + genFloorChgT, + + //new types for stair builders + buildStair, + genBuildStair, +} floor_e; + +typedef enum +{ + build8, // slowly build by 8 + turbo16 // quickly build by 16 + +} stair_e; + +typedef enum +{ + elevateUp, + elevateDown, + elevateCurrent, +} elevator_e; + +////////////////////////////////////////////////////////////////// +// +// general enums +// +////////////////////////////////////////////////////////////////// + +// texture type enum +typedef enum +{ + top, + middle, + bottom + +} bwhere_e; + +// crush check returns +typedef enum +{ + ok, + crushed, + pastdest +} result_e; + +////////////////////////////////////////////////////////////////// +// +// linedef and sector special data types +// +////////////////////////////////////////////////////////////////// + +// p_switch + +// switch animation structure type + +#if defined(__MWERKS__) +#pragma options align=packed +#endif + +typedef struct +{ + char name1[9]; + char name2[9]; + short episode; +} PACKEDATTR switchlist_t; //jff 3/23/98 pack to read from memory + +#if defined(__MWERKS__) +#pragma options align=reset +#endif + +typedef struct +{ + line_t* line; + bwhere_e where; + int btexture; + int btimer; + mobj_t* soundorg; + +} button_t; + +// p_lights + +typedef struct +{ + thinker_t thinker; + sector_t* sector; + int count; + int maxlight; + int minlight; + +} fireflicker_t; + +typedef struct +{ + thinker_t thinker; + sector_t* sector; + int count; + int maxlight; + int minlight; + int maxtime; + int mintime; + +} lightflash_t; + +typedef struct +{ + thinker_t thinker; + sector_t* sector; + int count; + int minlight; + int maxlight; + int darktime; + int brighttime; + +} strobe_t; + +typedef struct +{ + thinker_t thinker; + sector_t* sector; + int minlight; + int maxlight; + int direction; + +} glow_t; + +// p_plats + +typedef struct +{ + thinker_t thinker; + sector_t* sector; + fixed_t speed; + fixed_t low; + fixed_t high; + int wait; + int count; + plat_e status; + plat_e oldstatus; + boolean crush; + int tag; + plattype_e type; + + struct platlist *list; // killough +} plat_t; + +// New limit-free plat structure -- killough + +typedef struct platlist { + plat_t *plat; + struct platlist *next,**prev; +} platlist_t; + +// p_ceilng + +typedef struct +{ + thinker_t thinker; + vldoor_e type; + sector_t* sector; + fixed_t topheight; + fixed_t speed; + + // 1 = up, 0 = waiting at top, -1 = down + int direction; + + // tics to wait at the top + int topwait; + // (keep in case a door going down is reset) + // when it reaches 0, start going down + int topcountdown; + + //jff 1/31/98 keep track of line door is triggered by + line_t *line; + + /* killough 10/98: sector tag for gradual lighting effects */ + int lighttag; +} vldoor_t; + +// p_doors + +typedef struct +{ + thinker_t thinker; + ceiling_e type; + sector_t* sector; + fixed_t bottomheight; + fixed_t topheight; + fixed_t speed; + fixed_t oldspeed; + boolean crush; + + //jff 02/04/98 add these to support ceiling changers + int newspecial; + int oldspecial; //jff 3/14/98 add to fix bug in change transfers + short texture; + + // 1 = up, 0 = waiting, -1 = down + int direction; + + // ID + int tag; + int olddirection; + struct ceilinglist *list; // jff 2/22/98 copied from killough's plats +} ceiling_t; + +typedef struct ceilinglist { + ceiling_t *ceiling; + struct ceilinglist *next,**prev; +} ceilinglist_t; + +// p_floor + +typedef struct +{ + thinker_t thinker; + floor_e type; + boolean crush; + sector_t* sector; + int direction; + int newspecial; + int oldspecial; //jff 3/14/98 add to fix bug in change transfers + short texture; + fixed_t floordestheight; + fixed_t speed; + +} floormove_t; + +typedef struct +{ + thinker_t thinker; + elevator_e type; + sector_t* sector; + int direction; + fixed_t floordestheight; + fixed_t ceilingdestheight; + fixed_t speed; +} elevator_t; + +// p_spec + +// killough 3/7/98: Add generalized scroll effects + +typedef struct { + thinker_t thinker; // Thinker structure for scrolling + fixed_t dx, dy; // (dx,dy) scroll speeds + int affectee; // Number of affected sidedef, sector, tag, or whatever + int control; // Control sector (-1 if none) used to control scrolling + fixed_t last_height; // Last known height of control sector + fixed_t vdx, vdy; // Accumulated velocity if accelerative + int accel; // Whether it's accelerative + enum + { + sc_side, + sc_floor, + sc_ceiling, + sc_carry, + sc_carry_ceiling, // killough 4/11/98: carry objects hanging on ceilings + } type; // Type of scroll effect +} scroll_t; + +// phares 3/12/98: added new model of friction for ice/sludge effects + +typedef struct { + thinker_t thinker; // Thinker structure for friction + int friction; // friction value (E800 = normal) + int movefactor; // inertia factor when adding to momentum + int affectee; // Number of affected sector +} friction_t; + +// phares 3/20/98: added new model of Pushers for push/pull effects + +typedef struct { + thinker_t thinker; // Thinker structure for Pusher + enum + { + p_push, + p_pull, + p_wind, + p_current, + } type; + mobj_t* source; // Point source if point pusher + int x_mag; // X Strength + int y_mag; // Y Strength + int magnitude; // Vector strength for point pusher + int radius; // Effective radius for point pusher + int x; // X of point source if point pusher + int y; // Y of point source if point pusher + int affectee; // Number of affected sector +} pusher_t; + +////////////////////////////////////////////////////////////////// +// +// external data declarations +// +////////////////////////////////////////////////////////////////// + +// list of retriggerable buttons active +extern button_t buttonlist[MAXBUTTONS]; + +extern platlist_t *activeplats; // killough 2/14/98 + +extern ceilinglist_t *activeceilings; // jff 2/22/98 + +//////////////////////////////////////////////////////////////// +// +// Linedef and sector special utility function prototypes +// +//////////////////////////////////////////////////////////////// + +int twoSided +( int sector, + int line ); + +sector_t* getSector +( int currentSector, + int line, + int side ); + +side_t* getSide +( int currentSector, + int line, + int side ); + +fixed_t P_FindLowestFloorSurrounding +( sector_t* sec ); + +fixed_t P_FindHighestFloorSurrounding +( sector_t* sec ); + +fixed_t P_FindNextHighestFloor +( sector_t* sec, + int currentheight ); + +fixed_t P_FindNextLowestFloor +( sector_t* sec, + int currentheight ); + +fixed_t P_FindLowestCeilingSurrounding +( sector_t* sec ); // jff 2/04/98 + +fixed_t P_FindHighestCeilingSurrounding +( sector_t* sec ); // jff 2/04/98 + +fixed_t P_FindNextLowestCeiling +( sector_t *sec, + int currentheight ); // jff 2/04/98 + +fixed_t P_FindNextHighestCeiling +( sector_t *sec, + int currentheight ); // jff 2/04/98 + +fixed_t P_FindShortestTextureAround +( int secnum ); // jff 2/04/98 + +fixed_t P_FindShortestUpperAround +( int secnum ); // jff 2/04/98 + +sector_t* P_FindModelFloorSector +( fixed_t floordestheight, + int secnum ); //jff 02/04/98 + +sector_t* P_FindModelCeilingSector +( fixed_t ceildestheight, + int secnum ); //jff 02/04/98 + +int P_FindSectorFromLineTag +( const line_t *line, + int start ); // killough 4/17/98 + +int P_FindLineFromLineTag +( const line_t *line, + int start ); // killough 4/17/98 + +int P_FindMinSurroundingLight +( sector_t* sector, + int max ); + +sector_t* getNextSector +( line_t* line, + sector_t* sec ); + +int P_CheckTag +(line_t *line); // jff 2/27/98 + +boolean P_CanUnlockGenDoor +( line_t* line, + player_t* player); + +boolean PUREFUNC P_SectorActive +( special_e t, + const sector_t* s ); + +boolean PUREFUNC P_IsSecret +( const sector_t *sec ); + +boolean PUREFUNC P_WasSecret +( const sector_t *sec ); + +void P_ChangeSwitchTexture +( line_t* line, + int useAgain ); + +//////////////////////////////////////////////////////////////// +// +// Linedef and sector special action function prototypes +// +//////////////////////////////////////////////////////////////// + +// p_lights + +void T_LightFlash +( lightflash_t* flash ); + +void T_StrobeFlash +( strobe_t* flash ); + +// jff 8/8/98 add missing thinker for flicker +void T_FireFlicker +( fireflicker_t* flick ); + +void T_Glow +( glow_t* g ); + +// p_plats + +void T_PlatRaise +( plat_t* plat ); + +// p_doors + +void T_VerticalDoor +( vldoor_t* door ); + +// p_ceilng + +void T_MoveCeiling +( ceiling_t* ceiling ); + +// p_floor + +result_e T_MovePlane +( sector_t* sector, + fixed_t speed, + fixed_t dest, + boolean crush, + int floorOrCeiling, + int direction ); + +void T_MoveFloor +( floormove_t* floor ); + +void T_MoveElevator +( elevator_t* elevator ); + +// p_spec + +void T_Scroll +( scroll_t * ); // killough 3/7/98: scroll effect thinker + +void T_Friction +( friction_t * ); // phares 3/12/98: friction thinker + +void T_Pusher +( pusher_t * ); // phares 3/20/98: Push thinker + +//////////////////////////////////////////////////////////////// +// +// Linedef and sector special handler prototypes +// +//////////////////////////////////////////////////////////////// + +// p_telept + +int EV_Teleport +( line_t* line, + int side, + mobj_t* thing ); + +// killough 2/14/98: Add silent teleporter +int EV_SilentTeleport +( line_t* line, + int side, + mobj_t* thing ); + +// killough 1/31/98: Add silent line teleporter +int EV_SilentLineTeleport +( line_t* line, + int side, + mobj_t* thing, + boolean reverse); + +// p_floor + +int +EV_DoElevator +( line_t* line, + elevator_e type ); + +int EV_BuildStairs +( line_t* line, + stair_e type ); + +int EV_DoFloor +( line_t* line, + floor_e floortype ); + +// p_ceilng + +int EV_DoCeiling +( line_t* line, + ceiling_e type ); + +int EV_CeilingCrushStop +( line_t* line ); + +// p_doors + +int EV_VerticalDoor +( line_t* line, + mobj_t* thing ); + +int EV_DoDoor +( line_t* line, + vldoor_e type ); + +int EV_DoLockedDoor +( line_t* line, + vldoor_e type, + mobj_t* thing ); + +// p_lights + +int EV_StartLightStrobing +( line_t* line ); + +int EV_TurnTagLightsOff +( line_t* line ); + +int EV_LightTurnOn +( line_t* line, + int bright ); + +int EV_LightTurnOnPartway(line_t* line, fixed_t level); // killough 10/10/98 + +// p_floor + +int EV_DoChange +( line_t* line, + change_e changetype ); + +int EV_DoDonut +( line_t* line ); + +// p_plats + +int EV_DoPlat +( line_t* line, + plattype_e type, + int amount ); + +int EV_StopPlat +( line_t* line ); + +// p_genlin + +int EV_DoGenFloor +( line_t* line ); + +int EV_DoGenCeiling +( line_t* line ); + +int EV_DoGenLift +( line_t* line ); + +int EV_DoGenStairs +( line_t* line ); + +int EV_DoGenCrusher +( line_t* line ); + +int EV_DoGenDoor +( line_t* line ); + +int EV_DoGenLockedDoor +( line_t* line ); + +//////////////////////////////////////////////////////////////// +// +// Linedef and sector special thinker spawning +// +//////////////////////////////////////////////////////////////// + +// at game start +void P_InitPicAnims +( void ); + +void P_InitSwitchList +( void ); + +// at map load +void P_SpawnSpecials +( void ); + +// every tic +void P_UpdateSpecials +( void ); + +// when needed +boolean P_UseSpecialLine +( mobj_t* thing, + line_t* line, + int side ); + +void P_ShootSpecialLine +( mobj_t* thing, + line_t* line ); + +void P_CrossSpecialLine(line_t *line, int side, mobj_t *thing); + +void P_PlayerInSpecialSector +( player_t* player ); + +// p_lights + +void P_SpawnFireFlicker +( sector_t* sector ); + +void P_SpawnLightFlash +( sector_t* sector ); + +void P_SpawnStrobeFlash +( sector_t* sector, + int fastOrSlow, + int inSync ); + +void P_SpawnGlowingLight +( sector_t* sector ); + +// p_plats + +void P_AddActivePlat +( plat_t* plat ); + +void P_RemoveActivePlat +( plat_t* plat ); + +void P_RemoveAllActivePlats +( void ); // killough + +void P_ActivateInStasis +( int tag ); + +// p_doors + +void P_SpawnDoorCloseIn30 +( sector_t* sec ); + +void P_SpawnDoorRaiseIn5Mins +( sector_t* sec, + int secnum ); + +// p_ceilng + +void P_RemoveActiveCeiling +( ceiling_t* ceiling ); //jff 2/22/98 + +void P_RemoveAllActiveCeilings +( void ); //jff 2/22/98 + +void P_AddActiveCeiling +( ceiling_t* c ); + +int P_ActivateInStasisCeiling +( line_t* line ); + +mobj_t* P_GetPushThing(int); // phares 3/23/98 + +#endif diff --git a/src/p_switch.c b/src/p_switch.c new file mode 100644 index 0000000..7dfb2f9 --- /dev/null +++ b/src/p_switch.c @@ -0,0 +1,1150 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Switches, buttons. Two-state animation. Exits. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "w_wad.h" +#include "r_main.h" +#include "p_spec.h" +#include "g_game.h" +#include "s_sound.h" +#include "sounds.h" +#include "lprintf.h" + +// killough 2/8/98: Remove switch limit + +static int *switchlist; // killough +static int max_numswitches; // killough +static int numswitches; // killough + +button_t buttonlist[MAXBUTTONS]; + +// +// P_InitSwitchList() +// +// Only called at game initialization in order to list the set of switches +// and buttons known to the engine. This enables their texture to change +// when activated, and in the case of buttons, change back after a timeout. +// +// This routine modified to read its data from a predefined lump or +// PWAD lump called SWITCHES rather than a static table in this module to +// allow wad designers to insert or modify switches. +// +// Lump format is an array of byte packed switchlist_t structures, terminated +// by a structure with episode == -0. The lump can be generated from a +// text source file using SWANTBLS.EXE, distributed with the BOOM utils. +// The standard list of switches and animations is contained in the example +// source text file DEFSWANI.DAT also in the BOOM util distribution. +// +// Rewritten by Lee Killough to remove limit 2/8/98 +// +void P_InitSwitchList(void) +{ + int i, index = 0; + int episode = (gamemode == registered || gamemode==retail) ? + 2 : gamemode == commercial ? 3 : 1; + const switchlist_t *alphSwitchList; //jff 3/23/98 pointer to switch table + int lump = W_GetNumForName("SWITCHES"); // cph - new wad lump handling + + //jff 3/23/98 read the switch table from a predefined lump + alphSwitchList = (const switchlist_t *)W_CacheLumpNum(lump); + + for (i=0;;i++) + { + if (index+1 >= max_numswitches) + switchlist = realloc(switchlist, sizeof *switchlist * + (max_numswitches = max_numswitches ? max_numswitches*2 : 8)); + if (SHORT(alphSwitchList[i].episode) <= episode) //jff 5/11/98 endianess + { + int texture1, texture2; + + if (!SHORT(alphSwitchList[i].episode)) + break; + + // Ignore switches referencing unknown texture names, instead of exiting. + // Warn if either one is missing, but only add if both are valid. + texture1 = R_CheckTextureNumForName(alphSwitchList[i].name1); + if (texture1 == -1) + lprintf(LO_WARN, "P_InitSwitchList: unknown texture %s\n", + alphSwitchList[i].name1); + texture2 = R_CheckTextureNumForName(alphSwitchList[i].name2); + if (texture2 == -1) + lprintf(LO_WARN, "P_InitSwitchList: unknown texture %s\n", + alphSwitchList[i].name2); + if (texture1 != -1 && texture2 != -1) { + switchlist[index++] = texture1; + switchlist[index++] = texture2; + } + } + } + + numswitches = index/2; + switchlist[index] = -1; + W_UnlockLumpNum(lump); +} + +// +// P_StartButton() +// +// Start a button (retriggerable switch) counting down till it turns off. +// +// Passed the linedef the button is on, which texture on the sidedef contains +// the button, the texture number of the button, and the time the button is +// to remain active in gametics. +// No return. +// +static void P_StartButton +( line_t* line, + bwhere_e w, + int texture, + int time ) +{ + int i; + + // See if button is already pressed + for (i = 0;i < MAXBUTTONS;i++) + if (buttonlist[i].btimer && buttonlist[i].line == line) + return; + + for (i = 0;i < MAXBUTTONS;i++) + if (!buttonlist[i].btimer) // use first unused element of list + { + buttonlist[i].line = line; + buttonlist[i].where = w; + buttonlist[i].btexture = texture; + buttonlist[i].btimer = time; + /* use sound origin of line itself - no need to compatibility-wrap + * as the popout code gets it wrong whatever its value */ + buttonlist[i].soundorg = (mobj_t *)&line->soundorg; + return; + } + + I_Error("P_StartButton: no button slots left!"); +} + +// +// P_ChangeSwitchTexture() +// +// Function that changes switch wall texture on activation. +// +// Passed the line which the switch is on, and whether its retriggerable. +// If not retriggerable, this function clears the line special to insure that +// +// No return +// +void P_ChangeSwitchTexture +( line_t* line, + int useAgain ) +{ + /* Rearranged a bit to avoid too much code duplication */ + mobj_t *soundorg; + int i, sound; + short *texture, *ttop, *tmid, *tbot; + bwhere_e position; + + ttop = &sides[line->sidenum[0]].toptexture; + tmid = &sides[line->sidenum[0]].midtexture; + tbot = &sides[line->sidenum[0]].bottomtexture; + + sound = sfx_swtchn; + /* use the sound origin of the linedef (its midpoint) + * unless in a compatibility mode */ + soundorg = (mobj_t *)&line->soundorg; + if (comp[comp_sound] || compatibility_level < prboom_6_compatibility) { + /* usually NULL, unless there is another button already pressed in, + * in which case it's the sound origin of that button press... */ + soundorg = buttonlist->soundorg; + } else { + // EXIT SWITCH? + /* don't do this unless you're in a compatibility mode */ + // proff - this works as advertised, but I don't like the sound + // if (line->special == 11 || line->special == 51) // exit or secret exit + // sound = sfx_swtchx; + } + + /* don't zero line->special until after exit switch test */ + if (!useAgain) + line->special = 0; + + /* search for a texture to change */ + texture = NULL; position = 0; + for (i = 0;i < numswitches*2;i++) { /* this could be more efficient... */ + if (switchlist[i] == *ttop) { + texture = ttop; position = top; break; + } else if (switchlist[i] == *tmid) { + texture = tmid; position = middle; break; + } else if (switchlist[i] == *tbot) { + texture = tbot; position = bottom; break; + } + } + if (texture == NULL) + return; /* no switch texture was found to change */ + *texture = switchlist[i^1]; + + S_StartSound(soundorg, sound); + + if (useAgain) + P_StartButton(line, position, switchlist[i], BUTTONTIME); +} + + +// +// P_UseSpecialLine +// +// +// Called when a thing uses (pushes) a special line. +// Only the front sides of lines are usable. +// Dispatches to the appropriate linedef function handler. +// +// Passed the thing using the line, the line being used, and the side used +// Returns true if a thinker was created +// +boolean +P_UseSpecialLine +( mobj_t* thing, + line_t* line, + int side ) +{ + + // e6y + // b.m. side test was broken in boom201 + if ((demoplayback ? (demover != 201) : (compatibility_level != boom_201_compatibility))) + if (side) //jff 6/1/98 fix inadvertent deletion of side test + return false; + + //jff 02/04/98 add check here for generalized floor/ceil mover + if (!demo_compatibility) + { + // pointer to line function is NULL by default, set non-null if + // line special is push or switch generalized linedef type + int (*linefunc)(line_t *line)=NULL; + + // check each range of generalized linedefs + if ((unsigned)line->special >= GenEnd) + { + // Out of range for GenFloors + } + else if ((unsigned)line->special >= GenFloorBase) + { + if (!thing->player) + if ((line->special & FloorChange) || !(line->special & FloorModel)) + return false; // FloorModel is "Allow Monsters" if FloorChange is 0 + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenFloor; + } + else if ((unsigned)line->special >= GenCeilingBase) + { + if (!thing->player) + if ((line->special & CeilingChange) || !(line->special & CeilingModel)) + return false; // CeilingModel is "Allow Monsters" if CeilingChange is 0 + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenCeiling; + } + else if ((unsigned)line->special >= GenDoorBase) + { + if (!thing->player) + { + if (!(line->special & DoorMonster)) + return false; // monsters disallowed from this door + if (line->flags & ML_SECRET) // they can't open secret doors either + return false; + } + if (!line->tag && ((line->special&6)!=6)) //jff 3/2/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenDoor; + } + else if ((unsigned)line->special >= GenLockedBase) + { + if (!thing->player) + return false; // monsters disallowed from unlocking doors + if (!P_CanUnlockGenDoor(line,thing->player)) + return false; + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + + linefunc = EV_DoGenLockedDoor; + } + else if ((unsigned)line->special >= GenLiftBase) + { + if (!thing->player) + if (!(line->special & LiftMonster)) + return false; // monsters disallowed + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenLift; + } + else if ((unsigned)line->special >= GenStairsBase) + { + if (!thing->player) + if (!(line->special & StairMonster)) + return false; // monsters disallowed + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenStairs; + } + else if ((unsigned)line->special >= GenCrusherBase) + { + if (!thing->player) + if (!(line->special & CrusherMonster)) + return false; // monsters disallowed + if (!line->tag && ((line->special&6)!=6)) //jff 2/27/98 all non-manual + return false; // generalized types require tag + linefunc = EV_DoGenCrusher; + } + + if (linefunc) + switch((line->special & TriggerType) >> TriggerTypeShift) + { + case PushOnce: + if (!side) + if (linefunc(line)) + line->special = 0; + return true; + case PushMany: + if (!side) + linefunc(line); + return true; + case SwitchOnce: + if (linefunc(line)) + P_ChangeSwitchTexture(line,0); + return true; + case SwitchMany: + if (linefunc(line)) + P_ChangeSwitchTexture(line,1); + return true; + default: // if not a switch/push type, do nothing here + return false; + } + } + + // Switches that other things can activate. + if (!thing->player) + { + // never open secret doors + if (line->flags & ML_SECRET) + return false; + + switch(line->special) + { + case 1: // MANUAL DOOR RAISE + case 32: // MANUAL BLUE + case 33: // MANUAL RED + case 34: // MANUAL YELLOW + //jff 3/5/98 add ability to use teleporters for monsters + case 195: // switch teleporters + case 174: + case 210: // silent switch teleporters + case 209: + break; + + default: + return false; + break; + } + } + + if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types + return false; + + // Dispatch to handler according to linedef type + switch (line->special) + { + // Manual doors, push type with no tag + case 1: // Vertical Door + case 26: // Blue Door/Locked + case 27: // Yellow Door /Locked + case 28: // Red Door /Locked + + case 31: // Manual door open + case 32: // Blue locked door open + case 33: // Red locked door open + case 34: // Yellow locked door open + + case 117: // Blazing door raise + case 118: // Blazing door open + EV_VerticalDoor (line, thing); + break; + + // Switches (non-retriggerable) + case 7: + // Build Stairs + if (EV_BuildStairs(line,build8)) + P_ChangeSwitchTexture(line,0); + break; + + case 9: + // Change Donut + if (EV_DoDonut(line)) + P_ChangeSwitchTexture(line,0); + break; + + case 11: + /* Exit level + * killough 10/98: prevent zombies from exiting levels + */ + if (thing->player && thing->player->health <= 0 && !comp[comp_zombie]) + { + S_StartSound(thing, sfx_noway); + return false; + } + + P_ChangeSwitchTexture(line,0); + G_ExitLevel (); + break; + + case 14: + // Raise Floor 32 and change texture + if (EV_DoPlat(line,raiseAndChange,32)) + P_ChangeSwitchTexture(line,0); + break; + + case 15: + // Raise Floor 24 and change texture + if (EV_DoPlat(line,raiseAndChange,24)) + P_ChangeSwitchTexture(line,0); + break; + + case 18: + // Raise Floor to next highest floor + if (EV_DoFloor(line, raiseFloorToNearest)) + P_ChangeSwitchTexture(line,0); + break; + + case 20: + // Raise Plat next highest floor and change texture + if (EV_DoPlat(line,raiseToNearestAndChange,0)) + P_ChangeSwitchTexture(line,0); + break; + + case 21: + // PlatDownWaitUpStay + if (EV_DoPlat(line,downWaitUpStay,0)) + P_ChangeSwitchTexture(line,0); + break; + + case 23: + // Lower Floor to Lowest + if (EV_DoFloor(line,lowerFloorToLowest)) + P_ChangeSwitchTexture(line,0); + break; + + case 29: + // Raise Door + if (EV_DoDoor(line,normal)) + P_ChangeSwitchTexture(line,0); + break; + + case 41: + // Lower Ceiling to Floor + if (EV_DoCeiling(line,lowerToFloor)) + P_ChangeSwitchTexture(line,0); + break; + + case 71: + // Turbo Lower Floor + if (EV_DoFloor(line,turboLower)) + P_ChangeSwitchTexture(line,0); + break; + + case 49: + // Ceiling Crush And Raise + if (EV_DoCeiling(line,crushAndRaise)) + P_ChangeSwitchTexture(line,0); + break; + + case 50: + // Close Door + if (EV_DoDoor(line,close)) + P_ChangeSwitchTexture(line,0); + break; + + case 51: + /* Secret EXIT + * killough 10/98: prevent zombies from exiting levels + */ + if (thing->player && thing->player->health <= 0 && !comp[comp_zombie]) + { + S_StartSound(thing, sfx_noway); + return false; + } + + P_ChangeSwitchTexture(line,0); + G_SecretExitLevel (); + break; + + case 55: + // Raise Floor Crush + if (EV_DoFloor(line,raiseFloorCrush)) + P_ChangeSwitchTexture(line,0); + break; + + case 101: + // Raise Floor + if (EV_DoFloor(line,raiseFloor)) + P_ChangeSwitchTexture(line,0); + break; + + case 102: + // Lower Floor to Surrounding floor height + if (EV_DoFloor(line,lowerFloor)) + P_ChangeSwitchTexture(line,0); + break; + + case 103: + // Open Door + if (EV_DoDoor(line,open)) + P_ChangeSwitchTexture(line,0); + break; + + case 111: + // Blazing Door Raise (faster than TURBO!) + if (EV_DoDoor (line,blazeRaise)) + P_ChangeSwitchTexture(line,0); + break; + + case 112: + // Blazing Door Open (faster than TURBO!) + if (EV_DoDoor (line,blazeOpen)) + P_ChangeSwitchTexture(line,0); + break; + + case 113: + // Blazing Door Close (faster than TURBO!) + if (EV_DoDoor (line,blazeClose)) + P_ChangeSwitchTexture(line,0); + break; + + case 122: + // Blazing PlatDownWaitUpStay + if (EV_DoPlat(line,blazeDWUS,0)) + P_ChangeSwitchTexture(line,0); + break; + + case 127: + // Build Stairs Turbo 16 + if (EV_BuildStairs(line,turbo16)) + P_ChangeSwitchTexture(line,0); + break; + + case 131: + // Raise Floor Turbo + if (EV_DoFloor(line,raiseFloorTurbo)) + P_ChangeSwitchTexture(line,0); + break; + + case 133: + // BlzOpenDoor BLUE + case 135: + // BlzOpenDoor RED + case 137: + // BlzOpenDoor YELLOW + if (EV_DoLockedDoor (line,blazeOpen,thing)) + P_ChangeSwitchTexture(line,0); + break; + + case 140: + // Raise Floor 512 + if (EV_DoFloor(line,raiseFloor512)) + P_ChangeSwitchTexture(line,0); + break; + + // killough 1/31/98: factored out compatibility check; + // added inner switch, relaxed check to demo_compatibility + + default: + if (!demo_compatibility) + switch (line->special) + { + //jff 1/29/98 added linedef types to fill all functions out so that + // all possess SR, S1, WR, W1 types + + case 158: + // Raise Floor to shortest lower texture + // 158 S1 EV_DoFloor(raiseToTexture), CSW(0) + if (EV_DoFloor(line,raiseToTexture)) + P_ChangeSwitchTexture(line,0); + break; + + case 159: + // Raise Floor to shortest lower texture + // 159 S1 EV_DoFloor(lowerAndChange) + if (EV_DoFloor(line,lowerAndChange)) + P_ChangeSwitchTexture(line,0); + break; + + case 160: + // Raise Floor 24 and change + // 160 S1 EV_DoFloor(raiseFloor24AndChange) + if (EV_DoFloor(line,raiseFloor24AndChange)) + P_ChangeSwitchTexture(line,0); + break; + + case 161: + // Raise Floor 24 + // 161 S1 EV_DoFloor(raiseFloor24) + if (EV_DoFloor(line,raiseFloor24)) + P_ChangeSwitchTexture(line,0); + break; + + case 162: + // Moving floor min n to max n + // 162 S1 EV_DoPlat(perpetualRaise,0) + if (EV_DoPlat(line,perpetualRaise,0)) + P_ChangeSwitchTexture(line,0); + break; + + case 163: + // Stop Moving floor + // 163 S1 EV_DoPlat(perpetualRaise,0) + EV_StopPlat(line); + P_ChangeSwitchTexture(line,0); + break; + + case 164: + // Start fast crusher + // 164 S1 EV_DoCeiling(fastCrushAndRaise) + if (EV_DoCeiling(line,fastCrushAndRaise)) + P_ChangeSwitchTexture(line,0); + break; + + case 165: + // Start slow silent crusher + // 165 S1 EV_DoCeiling(silentCrushAndRaise) + if (EV_DoCeiling(line,silentCrushAndRaise)) + P_ChangeSwitchTexture(line,0); + break; + + case 166: + // Raise ceiling, Lower floor + // 166 S1 EV_DoCeiling(raiseToHighest), EV_DoFloor(lowerFloortoLowest) + if (EV_DoCeiling(line, raiseToHighest) || + EV_DoFloor(line, lowerFloorToLowest)) + P_ChangeSwitchTexture(line,0); + break; + + case 167: + // Lower floor and Crush + // 167 S1 EV_DoCeiling(lowerAndCrush) + if (EV_DoCeiling(line, lowerAndCrush)) + P_ChangeSwitchTexture(line,0); + break; + + case 168: + // Stop crusher + // 168 S1 EV_CeilingCrushStop() + if (EV_CeilingCrushStop(line)) + P_ChangeSwitchTexture(line,0); + break; + + case 169: + // Lights to brightest neighbor sector + // 169 S1 EV_LightTurnOn(0) + EV_LightTurnOn(line,0); + P_ChangeSwitchTexture(line,0); + break; + + case 170: + // Lights to near dark + // 170 S1 EV_LightTurnOn(35) + EV_LightTurnOn(line,35); + P_ChangeSwitchTexture(line,0); + break; + + case 171: + // Lights on full + // 171 S1 EV_LightTurnOn(255) + EV_LightTurnOn(line,255); + P_ChangeSwitchTexture(line,0); + break; + + case 172: + // Start Lights Strobing + // 172 S1 EV_StartLightStrobing() + EV_StartLightStrobing(line); + P_ChangeSwitchTexture(line,0); + break; + + case 173: + // Lights to Dimmest Near + // 173 S1 EV_TurnTagLightsOff() + EV_TurnTagLightsOff(line); + P_ChangeSwitchTexture(line,0); + break; + + case 174: + // Teleport + // 174 S1 EV_Teleport(side,thing) + if (EV_Teleport(line,side,thing)) + P_ChangeSwitchTexture(line,0); + break; + + case 175: + // Close Door, Open in 30 secs + // 175 S1 EV_DoDoor(close30ThenOpen) + if (EV_DoDoor(line,close30ThenOpen)) + P_ChangeSwitchTexture(line,0); + break; + + case 189: //jff 3/15/98 create texture change no motion type + // Texture Change Only (Trigger) + // 189 S1 Change Texture/Type Only + if (EV_DoChange(line,trigChangeOnly)) + P_ChangeSwitchTexture(line,0); + break; + + case 203: + // Lower ceiling to lowest surrounding ceiling + // 203 S1 EV_DoCeiling(lowerToLowest) + if (EV_DoCeiling(line,lowerToLowest)) + P_ChangeSwitchTexture(line,0); + break; + + case 204: + // Lower ceiling to highest surrounding floor + // 204 S1 EV_DoCeiling(lowerToMaxFloor) + if (EV_DoCeiling(line,lowerToMaxFloor)) + P_ChangeSwitchTexture(line,0); + break; + + case 209: + // killough 1/31/98: silent teleporter + //jff 209 S1 SilentTeleport + if (EV_SilentTeleport(line, side, thing)) + P_ChangeSwitchTexture(line,0); + break; + + case 241: //jff 3/15/98 create texture change no motion type + // Texture Change Only (Numeric) + // 241 S1 Change Texture/Type Only + if (EV_DoChange(line,numChangeOnly)) + P_ChangeSwitchTexture(line,0); + break; + + case 221: + // Lower floor to next lowest floor + // 221 S1 Lower Floor To Nearest Floor + if (EV_DoFloor(line,lowerFloorToNearest)) + P_ChangeSwitchTexture(line,0); + break; + + case 229: + // Raise elevator next floor + // 229 S1 Raise Elevator next floor + if (EV_DoElevator(line,elevateUp)) + P_ChangeSwitchTexture(line,0); + break; + + case 233: + // Lower elevator next floor + // 233 S1 Lower Elevator next floor + if (EV_DoElevator(line,elevateDown)) + P_ChangeSwitchTexture(line,0); + break; + + case 237: + // Elevator to current floor + // 237 S1 Elevator to current floor + if (EV_DoElevator(line,elevateCurrent)) + P_ChangeSwitchTexture(line,0); + break; + + + // jff 1/29/98 end of added S1 linedef types + + //jff 1/29/98 added linedef types to fill all functions out so that + // all possess SR, S1, WR, W1 types + + case 78: //jff 3/15/98 create texture change no motion type + // Texture Change Only (Numeric) + // 78 SR Change Texture/Type Only + if (EV_DoChange(line,numChangeOnly)) + P_ChangeSwitchTexture(line,1); + break; + + case 176: + // Raise Floor to shortest lower texture + // 176 SR EV_DoFloor(raiseToTexture), CSW(1) + if (EV_DoFloor(line,raiseToTexture)) + P_ChangeSwitchTexture(line,1); + break; + + case 177: + // Raise Floor to shortest lower texture + // 177 SR EV_DoFloor(lowerAndChange) + if (EV_DoFloor(line,lowerAndChange)) + P_ChangeSwitchTexture(line,1); + break; + + case 178: + // Raise Floor 512 + // 178 SR EV_DoFloor(raiseFloor512) + if (EV_DoFloor(line,raiseFloor512)) + P_ChangeSwitchTexture(line,1); + break; + + case 179: + // Raise Floor 24 and change + // 179 SR EV_DoFloor(raiseFloor24AndChange) + if (EV_DoFloor(line,raiseFloor24AndChange)) + P_ChangeSwitchTexture(line,1); + break; + + case 180: + // Raise Floor 24 + // 180 SR EV_DoFloor(raiseFloor24) + if (EV_DoFloor(line,raiseFloor24)) + P_ChangeSwitchTexture(line,1); + break; + + case 181: + // Moving floor min n to max n + // 181 SR EV_DoPlat(perpetualRaise,0) + + EV_DoPlat(line,perpetualRaise,0); + P_ChangeSwitchTexture(line,1); + break; + + case 182: + // Stop Moving floor + // 182 SR EV_DoPlat(perpetualRaise,0) + EV_StopPlat(line); + P_ChangeSwitchTexture(line,1); + break; + + case 183: + // Start fast crusher + // 183 SR EV_DoCeiling(fastCrushAndRaise) + if (EV_DoCeiling(line,fastCrushAndRaise)) + P_ChangeSwitchTexture(line,1); + break; + + case 184: + // Start slow crusher + // 184 SR EV_DoCeiling(crushAndRaise) + if (EV_DoCeiling(line,crushAndRaise)) + P_ChangeSwitchTexture(line,1); + break; + + case 185: + // Start slow silent crusher + // 185 SR EV_DoCeiling(silentCrushAndRaise) + if (EV_DoCeiling(line,silentCrushAndRaise)) + P_ChangeSwitchTexture(line,1); + break; + + case 186: + // Raise ceiling, Lower floor + // 186 SR EV_DoCeiling(raiseToHighest), EV_DoFloor(lowerFloortoLowest) + if (EV_DoCeiling(line, raiseToHighest) || + EV_DoFloor(line, lowerFloorToLowest)) + P_ChangeSwitchTexture(line,1); + break; + + case 187: + // Lower floor and Crush + // 187 SR EV_DoCeiling(lowerAndCrush) + if (EV_DoCeiling(line, lowerAndCrush)) + P_ChangeSwitchTexture(line,1); + break; + + case 188: + // Stop crusher + // 188 SR EV_CeilingCrushStop() + if (EV_CeilingCrushStop(line)) + P_ChangeSwitchTexture(line,1); + break; + + case 190: //jff 3/15/98 create texture change no motion type + // Texture Change Only (Trigger) + // 190 SR Change Texture/Type Only + if (EV_DoChange(line,trigChangeOnly)) + P_ChangeSwitchTexture(line,1); + break; + + case 191: + // Lower Pillar, Raise Donut + // 191 SR EV_DoDonut() + if (EV_DoDonut(line)) + P_ChangeSwitchTexture(line,1); + break; + + case 192: + // Lights to brightest neighbor sector + // 192 SR EV_LightTurnOn(0) + EV_LightTurnOn(line,0); + P_ChangeSwitchTexture(line,1); + break; + + case 193: + // Start Lights Strobing + // 193 SR EV_StartLightStrobing() + EV_StartLightStrobing(line); + P_ChangeSwitchTexture(line,1); + break; + + case 194: + // Lights to Dimmest Near + // 194 SR EV_TurnTagLightsOff() + EV_TurnTagLightsOff(line); + P_ChangeSwitchTexture(line,1); + break; + + case 195: + // Teleport + // 195 SR EV_Teleport(side,thing) + if (EV_Teleport(line,side,thing)) + P_ChangeSwitchTexture(line,1); + break; + + case 196: + // Close Door, Open in 30 secs + // 196 SR EV_DoDoor(close30ThenOpen) + if (EV_DoDoor(line,close30ThenOpen)) + P_ChangeSwitchTexture(line,1); + break; + + case 205: + // Lower ceiling to lowest surrounding ceiling + // 205 SR EV_DoCeiling(lowerToLowest) + if (EV_DoCeiling(line,lowerToLowest)) + P_ChangeSwitchTexture(line,1); + break; + + case 206: + // Lower ceiling to highest surrounding floor + // 206 SR EV_DoCeiling(lowerToMaxFloor) + if (EV_DoCeiling(line,lowerToMaxFloor)) + P_ChangeSwitchTexture(line,1); + break; + + case 210: + // killough 1/31/98: silent teleporter + //jff 210 SR SilentTeleport + if (EV_SilentTeleport(line, side, thing)) + P_ChangeSwitchTexture(line,1); + break; + + case 211: //jff 3/14/98 create instant toggle floor type + // Toggle Floor Between C and F Instantly + // 211 SR Toggle Floor Instant + if (EV_DoPlat(line,toggleUpDn,0)) + P_ChangeSwitchTexture(line,1); + break; + + case 222: + // Lower floor to next lowest floor + // 222 SR Lower Floor To Nearest Floor + if (EV_DoFloor(line,lowerFloorToNearest)) + P_ChangeSwitchTexture(line,1); + break; + + case 230: + // Raise elevator next floor + // 230 SR Raise Elevator next floor + if (EV_DoElevator(line,elevateUp)) + P_ChangeSwitchTexture(line,1); + break; + + case 234: + // Lower elevator next floor + // 234 SR Lower Elevator next floor + if (EV_DoElevator(line,elevateDown)) + P_ChangeSwitchTexture(line,1); + break; + + case 238: + // Elevator to current floor + // 238 SR Elevator to current floor + if (EV_DoElevator(line,elevateCurrent)) + P_ChangeSwitchTexture(line,1); + break; + + case 258: + // Build stairs, step 8 + // 258 SR EV_BuildStairs(build8) + if (EV_BuildStairs(line,build8)) + P_ChangeSwitchTexture(line,1); + break; + + case 259: + // Build stairs, step 16 + // 259 SR EV_BuildStairs(turbo16) + if (EV_BuildStairs(line,turbo16)) + P_ChangeSwitchTexture(line,1); + break; + + // 1/29/98 jff end of added SR linedef types + + } + break; + + // Buttons (retriggerable switches) + case 42: + // Close Door + if (EV_DoDoor(line,close)) + P_ChangeSwitchTexture(line,1); + break; + + case 43: + // Lower Ceiling to Floor + if (EV_DoCeiling(line,lowerToFloor)) + P_ChangeSwitchTexture(line,1); + break; + + case 45: + // Lower Floor to Surrounding floor height + if (EV_DoFloor(line,lowerFloor)) + P_ChangeSwitchTexture(line,1); + break; + + case 60: + // Lower Floor to Lowest + if (EV_DoFloor(line,lowerFloorToLowest)) + P_ChangeSwitchTexture(line,1); + break; + + case 61: + // Open Door + if (EV_DoDoor(line,open)) + P_ChangeSwitchTexture(line,1); + break; + + case 62: + // PlatDownWaitUpStay + if (EV_DoPlat(line,downWaitUpStay,1)) + P_ChangeSwitchTexture(line,1); + break; + + case 63: + // Raise Door + if (EV_DoDoor(line,normal)) + P_ChangeSwitchTexture(line,1); + break; + + case 64: + // Raise Floor to ceiling + if (EV_DoFloor(line,raiseFloor)) + P_ChangeSwitchTexture(line,1); + break; + + case 66: + // Raise Floor 24 and change texture + if (EV_DoPlat(line,raiseAndChange,24)) + P_ChangeSwitchTexture(line,1); + break; + + case 67: + // Raise Floor 32 and change texture + if (EV_DoPlat(line,raiseAndChange,32)) + P_ChangeSwitchTexture(line,1); + break; + + case 65: + // Raise Floor Crush + if (EV_DoFloor(line,raiseFloorCrush)) + P_ChangeSwitchTexture(line,1); + break; + + case 68: + // Raise Plat to next highest floor and change texture + if (EV_DoPlat(line,raiseToNearestAndChange,0)) + P_ChangeSwitchTexture(line,1); + break; + + case 69: + // Raise Floor to next highest floor + if (EV_DoFloor(line, raiseFloorToNearest)) + P_ChangeSwitchTexture(line,1); + break; + + case 70: + // Turbo Lower Floor + if (EV_DoFloor(line,turboLower)) + P_ChangeSwitchTexture(line,1); + break; + + case 114: + // Blazing Door Raise (faster than TURBO!) + if (EV_DoDoor (line,blazeRaise)) + P_ChangeSwitchTexture(line,1); + break; + + case 115: + // Blazing Door Open (faster than TURBO!) + if (EV_DoDoor (line,blazeOpen)) + P_ChangeSwitchTexture(line,1); + break; + + case 116: + // Blazing Door Close (faster than TURBO!) + if (EV_DoDoor (line,blazeClose)) + P_ChangeSwitchTexture(line,1); + break; + + case 123: + // Blazing PlatDownWaitUpStay + if (EV_DoPlat(line,blazeDWUS,0)) + P_ChangeSwitchTexture(line,1); + break; + + case 132: + // Raise Floor Turbo + if (EV_DoFloor(line,raiseFloorTurbo)) + P_ChangeSwitchTexture(line,1); + break; + + case 99: + // BlzOpenDoor BLUE + case 134: + // BlzOpenDoor RED + case 136: + // BlzOpenDoor YELLOW + if (EV_DoLockedDoor (line,blazeOpen,thing)) + P_ChangeSwitchTexture(line,1); + break; + + case 138: + // Light Turn On + EV_LightTurnOn(line,255); + P_ChangeSwitchTexture(line,1); + break; + + case 139: + // Light Turn Off + EV_LightTurnOn(line,35); + P_ChangeSwitchTexture(line,1); + break; + } + return true; +} diff --git a/src/p_telept.c b/src/p_telept.c new file mode 100644 index 0000000..744e901 --- /dev/null +++ b/src/p_telept.c @@ -0,0 +1,345 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2002 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Teleportation. + * + *-----------------------------------------------------------------------------*/ + +#include "doomdef.h" +#include "doomstat.h" +#include "p_spec.h" +#include "p_maputl.h" +#include "p_map.h" +#include "r_main.h" +#include "p_tick.h" +#include "s_sound.h" +#include "sounds.h" +#include "p_user.h" +#include "r_demo.h" + +static mobj_t* P_TeleportDestination(line_t* line) +{ + int i; + for (i = -1; (i = P_FindSectorFromLineTag(line, i)) >= 0;) { + register thinker_t* th = NULL; + while ((th = P_NextThinker(th,th_misc)) != NULL) + if (th->function == P_MobjThinker) { + register mobj_t* m = (mobj_t*)th; + if (m->type == MT_TELEPORTMAN && + m->subsector->sector-sectors == i) + return m; + } + } + return NULL; +} +// +// TELEPORTATION +// +// killough 5/3/98: reformatted, cleaned up + +int EV_Teleport(line_t *line, int side, mobj_t *thing) +{ + mobj_t *m; + + // don't teleport missiles + // Don't teleport if hit back of line, + // so you can get out of teleporter. + if (side || thing->flags & MF_MISSILE) + return 0; + + // killough 1/31/98: improve performance by using + // P_FindSectorFromLineTag instead of simple linear search. + + if ((m = P_TeleportDestination(line)) != NULL) + { + fixed_t oldx = thing->x, oldy = thing->y, oldz = thing->z; + player_t *player = thing->player; + + // killough 5/12/98: exclude voodoo dolls: + if (player && player->mo != thing) + player = NULL; + + if (!P_TeleportMove(thing, m->x, m->y, false)) /* killough 8/9/98 */ + return 0; + + if (compatibility_level != finaldoom_compatibility) + thing->z = thing->floorz; + + if (player) + player->viewz = thing->z + player->viewheight; + + // spawn teleport fog and emit sound at source + S_StartSound(P_SpawnMobj(oldx, oldy, oldz, MT_TFOG), sfx_telept); + + // spawn teleport fog and emit sound at destination + S_StartSound(P_SpawnMobj(m->x + + 20*finecosine[m->angle>>ANGLETOFINESHIFT], + m->y + + 20*finesine[m->angle>>ANGLETOFINESHIFT], + thing->z, MT_TFOG), + sfx_telept); + + /* don't move for a bit + * cph - DEMOSYNC - BOOM had (player) here? */ + if (thing->player) + thing->reactiontime = 18; + + thing->angle = m->angle; + + thing->momx = thing->momy = thing->momz = 0; + + /* killough 10/98: kill all bobbing momentum too */ + if (player) + player->momx = player->momy = 0; + + // e6y + if (player && player->mo == thing) + R_ResetAfterTeleport(player); + + return 1; + } + return 0; +} + +// +// Silent TELEPORTATION, by Lee Killough +// Primarily for rooms-over-rooms etc. +// + +int EV_SilentTeleport(line_t *line, int side, mobj_t *thing) +{ + mobj_t *m; + + // don't teleport missiles + // Don't teleport if hit back of line, + // so you can get out of teleporter. + + if (side || thing->flags & MF_MISSILE) + return 0; + + if ((m = P_TeleportDestination(line)) != NULL) + { + // Height of thing above ground, in case of mid-air teleports: + fixed_t z = thing->z - thing->floorz; + + // Get the angle between the exit thing and source linedef. + // Rotate 90 degrees, so that walking perpendicularly across + // teleporter linedef causes thing to exit in the direction + // indicated by the exit thing. + angle_t angle = + R_PointToAngle2(0, 0, line->dx, line->dy) - m->angle + ANG90; + + // Sine, cosine of angle adjustment + fixed_t s = finesine[angle>>ANGLETOFINESHIFT]; + fixed_t c = finecosine[angle>>ANGLETOFINESHIFT]; + + // Momentum of thing crossing teleporter linedef + fixed_t momx = thing->momx; + fixed_t momy = thing->momy; + + // Whether this is a player, and if so, a pointer to its player_t + player_t *player = thing->player; + + // Attempt to teleport, aborting if blocked + if (!P_TeleportMove(thing, m->x, m->y, false)) /* killough 8/9/98 */ + return 0; + + // Rotate thing according to difference in angles + thing->angle += angle; + + // Adjust z position to be same height above ground as before + thing->z = z + thing->floorz; + + // Rotate thing's momentum to come out of exit just like it entered + thing->momx = FixedMul(momx, c) - FixedMul(momy, s); + thing->momy = FixedMul(momy, c) + FixedMul(momx, s); + + // Adjust player's view, in case there has been a height change + // Voodoo dolls are excluded by making sure player->mo == thing. + if (player && player->mo == thing) + { + // Save the current deltaviewheight, used in stepping + fixed_t deltaviewheight = player->deltaviewheight; + + // Clear deltaviewheight, since we don't want any changes + player->deltaviewheight = 0; + + // Set player's view according to the newly set parameters + P_CalcHeight(player); + + // Reset the delta to have the same dynamics as before + player->deltaviewheight = deltaviewheight; + } + + // e6y + if (player && player->mo == thing) + R_ResetAfterTeleport(player); + + return 1; + } + return 0; +} + +// +// Silent linedef-based TELEPORTATION, by Lee Killough +// Primarily for rooms-over-rooms etc. +// This is the complete player-preserving kind of teleporter. +// It has advantages over the teleporter with thing exits. +// + +// maximum fixed_t units to move object to avoid hiccups +#define FUDGEFACTOR 10 + +int EV_SilentLineTeleport(line_t *line, int side, mobj_t *thing, + boolean reverse) +{ + int i; + line_t *l; + + if (side || thing->flags & MF_MISSILE) + return 0; + + for (i = -1; (i = P_FindLineFromLineTag(line, i)) >= 0;) + if ((l=lines+i) != line && l->backsector) + { + // Get the thing's position along the source linedef + fixed_t pos = D_abs(line->dx) > D_abs(line->dy) ? + FixedDiv(thing->x - line->v1->x, line->dx) : + FixedDiv(thing->y - line->v1->y, line->dy) ; + + // Get the angle between the two linedefs, for rotating + // orientation and momentum. Rotate 180 degrees, and flip + // the position across the exit linedef, if reversed. + angle_t angle = (reverse ? pos = FRACUNIT-pos, 0 : ANG180) + + R_PointToAngle2(0, 0, l->dx, l->dy) - + R_PointToAngle2(0, 0, line->dx, line->dy); + + // Interpolate position across the exit linedef + fixed_t x = l->v2->x - FixedMul(pos, l->dx); + fixed_t y = l->v2->y - FixedMul(pos, l->dy); + + // Sine, cosine of angle adjustment + fixed_t s = finesine[angle>>ANGLETOFINESHIFT]; + fixed_t c = finecosine[angle>>ANGLETOFINESHIFT]; + + // Maximum distance thing can be moved away from interpolated + // exit, to ensure that it is on the correct side of exit linedef + int fudge = FUDGEFACTOR; + + // Whether this is a player, and if so, a pointer to its player_t. + // Voodoo dolls are excluded by making sure thing->player->mo==thing. + player_t *player = thing->player && thing->player->mo == thing ? + thing->player : NULL; + + // Whether walking towards first side of exit linedef steps down + int stepdown = + l->frontsector->floorheight < l->backsector->floorheight; + + // Height of thing above ground + fixed_t z = thing->z - thing->floorz; + + // Side to exit the linedef on positionally. + // + // Notes: + // + // This flag concerns exit position, not momentum. Due to + // roundoff error, the thing can land on either the left or + // the right side of the exit linedef, and steps must be + // taken to make sure it does not end up on the wrong side. + // + // Exit momentum is always towards side 1 in a reversed + // teleporter, and always towards side 0 otherwise. + // + // Exiting positionally on side 1 is always safe, as far + // as avoiding oscillations and stuck-in-wall problems, + // but may not be optimum for non-reversed teleporters. + // + // Exiting on side 0 can cause oscillations if momentum + // is towards side 1, as it is with reversed teleporters. + // + // Exiting on side 1 slightly improves player viewing + // when going down a step on a non-reversed teleporter. + + int side = reverse || (player && stepdown); + + // Make sure we are on correct side of exit linedef. + while (P_PointOnLineSide(x, y, l) != side && --fudge>=0) + if (D_abs(l->dx) > D_abs(l->dy)) + y -= l->dx < 0 != side ? -1 : 1; + else + x += l->dy < 0 != side ? -1 : 1; + + // Attempt to teleport, aborting if blocked + if (!P_TeleportMove(thing, x, y, false)) /* killough 8/9/98 */ + return 0; + + // e6y + if (player && player->mo == thing) + R_ResetAfterTeleport(player); + + // Adjust z position to be same height above ground as before. + // Ground level at the exit is measured as the higher of the + // two floor heights at the exit linedef. + thing->z = z + sides[l->sidenum[stepdown]].sector->floorheight; + + // Rotate thing's orientation according to difference in linedef angles + thing->angle += angle; + + // Momentum of thing crossing teleporter linedef + x = thing->momx; + y = thing->momy; + + // Rotate thing's momentum to come out of exit just like it entered + thing->momx = FixedMul(x, c) - FixedMul(y, s); + thing->momy = FixedMul(y, c) + FixedMul(x, s); + + // Adjust a player's view, in case there has been a height change + if (player) + { + // Save the current deltaviewheight, used in stepping + fixed_t deltaviewheight = player->deltaviewheight; + + // Clear deltaviewheight, since we don't want any changes now + player->deltaviewheight = 0; + + // Set player's view according to the newly set parameters + P_CalcHeight(player); + + // Reset the delta to have the same dynamics as before + player->deltaviewheight = deltaviewheight; + } + + // e6y + if (player && player->mo == thing) + R_ResetAfterTeleport(player); + + return 1; + } + return 0; +} diff --git a/src/p_tick.c b/src/p_tick.c new file mode 100644 index 0000000..6046046 --- /dev/null +++ b/src/p_tick.c @@ -0,0 +1,291 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000,2002 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Thinker, Ticker. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "p_user.h" +#include "p_spec.h" +#include "p_tick.h" +#include "p_map.h" +#include "r_fps.h" + +int leveltime; + +static boolean newthinkerpresent; + +// +// THINKERS +// All thinkers should be allocated by Z_Malloc +// so they can be operated on uniformly. +// The actual structures will vary in size, +// but the first element must be thinker_t. +// + +// killough 8/29/98: we maintain several separate threads, each containing +// a special class of thinkers, to allow more efficient searches. +thinker_t thinkerclasscap[th_all+1]; + +// +// P_InitThinkers +// + +void P_InitThinkers(void) +{ + int i; + + for (i=0; ifunction == P_RemoveThinkerDelayed ? th_delete : + thinker->function == P_MobjThinker && + ((mobj_t *) thinker)->health > 0 && + (((mobj_t *) thinker)->flags & MF_COUNTKILL || + ((mobj_t *) thinker)->type == MT_SKULL) ? + ((mobj_t *) thinker)->flags & MF_FRIEND ? + th_friends : th_enemies : th_misc; + + { + /* Remove from current thread, if in one */ + if ((th = thinker->cnext)!= NULL) + (th->cprev = thinker->cprev)->cnext = th; + } + + // Add to appropriate thread + th = &thinkerclasscap[class]; + th->cprev->cnext = thinker; + thinker->cnext = th; + thinker->cprev = th->cprev; + th->cprev = thinker; +} + +// +// P_AddThinker +// Adds a new thinker at the end of the list. +// + +void P_AddThinker(thinker_t* thinker) +{ + thinkercap.prev->next = thinker; + thinker->next = &thinkercap; + thinker->prev = thinkercap.prev; + thinkercap.prev = thinker; + + thinker->references = 0; // killough 11/98: init reference counter to 0 + + // killough 8/29/98: set sentinel pointers, and then add to appropriate list + thinker->cnext = thinker->cprev = NULL; + P_UpdateThinker(thinker); + newthinkerpresent = true; +} + +// +// killough 11/98: +// +// Make currentthinker external, so that P_RemoveThinkerDelayed +// can adjust currentthinker when thinkers self-remove. + +static thinker_t *currentthinker; + +// +// P_RemoveThinkerDelayed() +// +// Called automatically as part of the thinker loop in P_RunThinkers(), +// on nodes which are pending deletion. +// +// If this thinker has no more pointers referencing it indirectly, +// remove it, and set currentthinker to one node preceeding it, so +// that the next step in P_RunThinkers() will get its successor. +// + +void P_RemoveThinkerDelayed(thinker_t *thinker) +{ + if (!thinker->references) + { + { /* Remove from main thinker list */ + thinker_t *next = thinker->next; + /* Note that currentthinker is guaranteed to point to us, + * and since we're freeing our memory, we had better change that. So + * point it to thinker->prev, so the iterator will correctly move on to + * thinker->prev->next = thinker->next */ + (next->prev = currentthinker = thinker->prev)->next = next; + } + { + /* Remove from current thinker class list */ + thinker_t *th = thinker->cnext; + (th->cprev = thinker->cprev)->cnext = th; + } + Z_Free(thinker); + } +} + +// +// P_RemoveThinker +// +// Deallocation is lazy -- it will not actually be freed +// until its thinking turn comes up. +// +// killough 4/25/98: +// +// Instead of marking the function with -1 value cast to a function pointer, +// set the function to P_RemoveThinkerDelayed(), so that later, it will be +// removed automatically as part of the thinker process. +// + +void P_RemoveThinker(thinker_t *thinker) +{ + R_StopInterpolationIfNeeded(thinker); + thinker->function = P_RemoveThinkerDelayed; + + P_UpdateThinker(thinker); +} + +/* cph 2002/01/13 - iterator for thinker list + * WARNING: Do not modify thinkers between calls to this functin + */ +thinker_t* P_NextThinker(thinker_t* th, th_class cl) +{ + thinker_t* top = &thinkerclasscap[cl]; + if (!th) th = top; + th = cl == th_all ? th->next : th->cnext; + return th == top ? NULL : th; +} + +/* + * P_SetTarget + * + * This function is used to keep track of pointer references to mobj thinkers. + * In Doom, objects such as lost souls could sometimes be removed despite + * their still being referenced. In Boom, 'target' mobj fields were tested + * during each gametic, and any objects pointed to by them would be prevented + * from being removed. But this was incomplete, and was slow (every mobj was + * checked during every gametic). Now, we keep a count of the number of + * references, and delay removal until the count is 0. + */ + +void P_SetTarget(mobj_t **mop, mobj_t *targ) +{ + if (*mop) // If there was a target already, decrease its refcount + (*mop)->thinker.references--; + if ((*mop = targ)) // Set new target and if non-NULL, increase its counter + targ->thinker.references++; +} + +// +// P_RunThinkers +// +// killough 4/25/98: +// +// Fix deallocator to stop using "next" pointer after node has been freed +// (a Doom bug). +// +// Process each thinker. For thinkers which are marked deleted, we must +// load the "next" pointer prior to freeing the node. In Doom, the "next" +// pointer was loaded AFTER the thinker was freed, which could have caused +// crashes. +// +// But if we are not deleting the thinker, we should reload the "next" +// pointer after calling the function, in case additional thinkers are +// added at the end of the list. +// +// killough 11/98: +// +// Rewritten to delete nodes implicitly, by making currentthinker +// external and using P_RemoveThinkerDelayed() implicitly. +// + +static void P_RunThinkers (void) +{ + for (currentthinker = thinkercap.next; + currentthinker != &thinkercap; + currentthinker = currentthinker->next) + { + if (newthinkerpresent) + R_ActivateThinkerInterpolations(currentthinker); + if (currentthinker->function) + currentthinker->function(currentthinker); + } + newthinkerpresent = false; +} + +// +// P_Ticker +// + +void P_Ticker (void) +{ + int i; + + /* pause if in menu and at least one tic has been run + * + * killough 9/29/98: note that this ties in with basetic, + * since G_Ticker does the pausing during recording or + * playback, and compenates by incrementing basetic. + * + * All of this complicated mess is used to preserve demo sync. + */ + + if (paused || (menuactive && !demoplayback && !netgame && + players[consoleplayer].viewz != 1)) + return; + + R_UpdateInterpolations (); + + P_MapStart(); + // not if this is an intermission screen + if(gamestate==GS_LEVEL) + for (i=0; i>= ANGLETOFINESHIFT; + player->mo->momx += FixedMul(move,finecosine[angle]); + player->mo->momy += FixedMul(move,finesine[angle]); + } + + +/* + * P_Bob + * Same as P_Thrust, but only affects bobbing. + * + * killough 10/98: We apply thrust separately between the real physical player + * and the part which affects bobbing. This way, bobbing only comes from player + * motion, nothing external, avoiding many problems, e.g. bobbing should not + * occur on conveyors, unless the player walks on one, and bobbing should be + * reduced at a regular rate, even on ice (where the player coasts). + */ + +static void P_Bob(player_t *player, angle_t angle, fixed_t move) +{ + //e6y + if (!mbf_features) + return; + + player->momx += FixedMul(move,finecosine[angle >>= ANGLETOFINESHIFT]); + player->momy += FixedMul(move,finesine[angle]); +} + +// +// P_CalcHeight +// Calculate the walking / running height adjustment +// + +void P_CalcHeight (player_t* player) + { + int angle; + fixed_t bob; + + // Regular movement bobbing + // (needs to be calculated for gun swing + // even if not on ground) + // OPTIMIZE: tablify angle + // Note: a LUT allows for effects + // like a ramp with low health. + + + /* killough 10/98: Make bobbing depend only on player-applied motion. + * + * Note: don't reduce bobbing here if on ice: if you reduce bobbing here, + * it causes bobbing jerkiness when the player moves from ice to non-ice, + * and vice-versa. + */ + player->bob = !mbf_features ? + (FixedMul (player->mo->momx, player->mo->momx) + + FixedMul (player->mo->momy,player->mo->momy))>>2 : + player_bobbing ? (FixedMul(player->momx,player->momx) + + FixedMul(player->momy,player->momy))>>2 : 0; + + //e6y + if (compatibility_level >= boom_202_compatibility && + compatibility_level <= lxdoom_1_compatibility && + player->mo->friction > ORIG_FRICTION) // ice? + { + if (player->bob > (MAXBOB>>2)) + player->bob = MAXBOB>>2; + } + else + + if (player->bob > MAXBOB) + player->bob = MAXBOB; + + if (!onground || player->cheats & CF_NOMOMENTUM) + { + player->viewz = player->mo->z + VIEWHEIGHT; + + if (player->viewz > player->mo->ceilingz-4*FRACUNIT) + player->viewz = player->mo->ceilingz-4*FRACUNIT; + +// The following line was in the Id source and appears // phares 2/25/98 +// to be a bug. player->viewz is checked in a similar +// manner at a different exit below. + +// player->viewz = player->mo->z + player->viewheight; + return; + } + + angle = (FINEANGLES/20*leveltime)&FINEMASK; + bob = FixedMul(player->bob/2,finesine[angle]); + + // move viewheight + + if (player->playerstate == PST_LIVE) + { + player->viewheight += player->deltaviewheight; + + if (player->viewheight > VIEWHEIGHT) + { + player->viewheight = VIEWHEIGHT; + player->deltaviewheight = 0; + } + + if (player->viewheight < VIEWHEIGHT/2) + { + player->viewheight = VIEWHEIGHT/2; + if (player->deltaviewheight <= 0) + player->deltaviewheight = 1; + } + + if (player->deltaviewheight) + { + player->deltaviewheight += FRACUNIT/4; + if (!player->deltaviewheight) + player->deltaviewheight = 1; + } + } + + player->viewz = player->mo->z + player->viewheight + bob; + + if (player->viewz > player->mo->ceilingz-4*FRACUNIT) + player->viewz = player->mo->ceilingz-4*FRACUNIT; + } + + +// +// P_MovePlayer +// +// Adds momentum if the player is not in the air +// +// killough 10/98: simplified + +void P_MovePlayer (player_t* player) +{ + ticcmd_t *cmd = &player->cmd; + mobj_t *mo = player->mo; + + mo->angle += cmd->angleturn << 16; + onground = mo->z <= mo->floorz; + + // e6y + if (demo_smoothturns && player == &players[displayplayer]) + R_SmoothPlaying_Add(cmd->angleturn << 16); + + // killough 10/98: + // + // We must apply thrust to the player and bobbing separately, to avoid + // anomalies. The thrust applied to bobbing is always the same strength on + // ice, because the player still "works just as hard" to move, while the + // thrust applied to the movement varies with 'movefactor'. + + //e6y + if ((!demo_compatibility && !mbf_features) || (cmd->forwardmove | cmd->sidemove)) // killough 10/98 + { + if (onground || mo->flags & MF_BOUNCES) // killough 8/9/98 + { + int friction, movefactor = P_GetMoveFactor(mo, &friction); + + // killough 11/98: + // On sludge, make bobbing depend on efficiency. + // On ice, make it depend on effort. + + int bobfactor = + friction < ORIG_FRICTION ? movefactor : ORIG_FRICTION_FACTOR; + + if (cmd->forwardmove) + { + P_Bob(player,mo->angle,cmd->forwardmove*bobfactor); + P_Thrust(player,mo->angle,cmd->forwardmove*movefactor); + } + + if (cmd->sidemove) + { + P_Bob(player,mo->angle-ANG90,cmd->sidemove*bobfactor); + P_Thrust(player,mo->angle-ANG90,cmd->sidemove*movefactor); + } + } + if (mo->state == states+S_PLAY) + P_SetMobjState(mo,S_PLAY_RUN1); + } +} + +#define ANG5 (ANG90/18) + +// +// P_DeathThink +// Fall on your face when dying. +// Decrease POV height to floor height. +// + +void P_DeathThink (player_t* player) + { + angle_t angle; + angle_t delta; + + P_MovePsprites (player); + + // fall to the ground + + if (player->viewheight > 6*FRACUNIT) + player->viewheight -= FRACUNIT; + + if (player->viewheight < 6*FRACUNIT) + player->viewheight = 6*FRACUNIT; + + player->deltaviewheight = 0; + onground = (player->mo->z <= player->mo->floorz); + P_CalcHeight (player); + + if (player->attacker && player->attacker != player->mo) + { + angle = R_PointToAngle2 (player->mo->x, + player->mo->y, + player->attacker->x, + player->attacker->y); + + delta = angle - player->mo->angle; + + if (delta < ANG5 || delta > (unsigned)-ANG5) + { + // Looking at killer, + // so fade damage flash down. + + player->mo->angle = angle; + + if (player->damagecount) + player->damagecount--; + } + else if (delta < ANG180) + player->mo->angle += ANG5; + else + player->mo->angle -= ANG5; + } + else if (player->damagecount) + player->damagecount--; + + if (player->cmd.buttons & BT_USE) + player->playerstate = PST_REBORN; + R_SmoothPlaying_Reset(player); // e6y + } + + +// +// P_PlayerThink +// + +void P_PlayerThink (player_t* player) + { + ticcmd_t* cmd; + weapontype_t newweapon; + + if (movement_smooth && players && &players[displayplayer] == player) + { + original_view_vars.viewx = player->mo->x; + original_view_vars.viewy = player->mo->y; + original_view_vars.viewz = player->viewz; + original_view_vars.viewangle = R_SmoothPlaying_Get(player->mo->angle) + viewangleoffset; + } + + // killough 2/8/98, 3/21/98: + if (player->cheats & CF_NOCLIP) + player->mo->flags |= MF_NOCLIP; + else + player->mo->flags &= ~MF_NOCLIP; + + // chain saw run forward + + cmd = &player->cmd; + if (player->mo->flags & MF_JUSTATTACKED) + { + cmd->angleturn = 0; + cmd->forwardmove = 0xc800/512; + cmd->sidemove = 0; + player->mo->flags &= ~MF_JUSTATTACKED; + } + + if (player->playerstate == PST_DEAD) + { + P_DeathThink (player); + return; + } + + // Move around. + // Reactiontime is used to prevent movement + // for a bit after a teleport. + + if (player->mo->reactiontime) + player->mo->reactiontime--; + else + P_MovePlayer (player); + + P_CalcHeight (player); // Determines view height and bobbing + + // Determine if there's anything about the sector you're in that's + // going to affect you, like painful floors. + + if (player->mo->subsector->sector->special) + P_PlayerInSpecialSector (player); + + // Check for weapon change. + + if (cmd->buttons & BT_CHANGE) + { + // The actual changing of the weapon is done + // when the weapon psprite can do it + // (read: not in the middle of an attack). + + newweapon = (cmd->buttons & BT_WEAPONMASK)>>BT_WEAPONSHIFT; + + // killough 3/22/98: For demo compatibility we must perform the fist + // and SSG weapons switches here, rather than in G_BuildTiccmd(). For + // other games which rely on user preferences, we must use the latter. + + if (demo_compatibility) + { // compatibility mode -- required for old demos -- killough + if (newweapon == wp_fist && player->weaponowned[wp_chainsaw] && + (player->readyweapon != wp_chainsaw || + !player->powers[pw_strength])) + newweapon = wp_chainsaw; + if (gamemode == commercial && + newweapon == wp_shotgun && + player->weaponowned[wp_supershotgun] && + player->readyweapon != wp_supershotgun) + newweapon = wp_supershotgun; + } + + // killough 2/8/98, 3/22/98 -- end of weapon selection changes + + if (player->weaponowned[newweapon] && newweapon != player->readyweapon) + + // Do not go to plasma or BFG in shareware, + // even if cheated. + + if ((newweapon != wp_plasma && newweapon != wp_bfg) + || (gamemode != shareware) ) + player->pendingweapon = newweapon; + } + + // check for use + + if (cmd->buttons & BT_USE) + { + if (!player->usedown) + { + P_UseLines (player); + player->usedown = true; + } + } + else + player->usedown = false; + + // cycle psprites + + P_MovePsprites (player); + + // Counters, time dependent power ups. + + // Strength counts up to diminish fade. + + if (player->powers[pw_strength]) + player->powers[pw_strength]++; + + // killough 1/98: Make idbeholdx toggle: + + if (player->powers[pw_invulnerability] > 0) // killough + player->powers[pw_invulnerability]--; + + if (player->powers[pw_invisibility] > 0) // killough + if (! --player->powers[pw_invisibility] ) + player->mo->flags &= ~MF_SHADOW; + + if (player->powers[pw_infrared] > 0) // killough + player->powers[pw_infrared]--; + + if (player->powers[pw_ironfeet] > 0) // killough + player->powers[pw_ironfeet]--; + + if (player->damagecount) + player->damagecount--; + + if (player->bonuscount) + player->bonuscount--; + + // Handling colormaps. + // killough 3/20/98: reformat to terse C syntax + + player->fixedcolormap = player->powers[pw_invulnerability] > 4*32 || + player->powers[pw_invulnerability] & 8 ? INVERSECOLORMAP : + player->powers[pw_infrared] > 4*32 || player->powers[pw_infrared] & 8; + } diff --git a/src/p_user.h b/src/p_user.h new file mode 100644 index 0000000..b0540e8 --- /dev/null +++ b/src/p_user.h @@ -0,0 +1,47 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Player related stuff. + * Bobbing POV/weapon, movement. + * Pending weapon. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __P_USER__ +#define __P_USER__ + +#include "d_player.h" + +void P_PlayerThink(player_t *player); +void P_CalcHeight(player_t *player); +void P_DeathThink(player_t *player); +void P_MovePlayer(player_t *player); +void P_Thrust(player_t *player, angle_t angle, fixed_t move); + +#endif /* __P_USER__ */ diff --git a/src/protocol.h b/src/protocol.h new file mode 100644 index 0000000..c2af10d --- /dev/null +++ b/src/protocol.h @@ -0,0 +1,96 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Doom Network protocol packet definitions. + *-----------------------------------------------------------------------------*/ + +#include "doomtype.h" +#include "d_ticcmd.h" +#include "m_swap.h" + +enum packet_type_e { + PKT_INIT, // initial packet to server + PKT_SETUP, // game information packet + PKT_GO, // game has started + PKT_TICC, // tics from client + PKT_TICS, // tics from server + PKT_RETRANS, // Request for retransmission + PKT_EXTRA, // Extra info packet + PKT_QUIT, // Player quit game + PKT_DOWN, // Server downed + PKT_WAD, // Wad file request + PKT_BACKOFF, // Request for client back-off +}; + +typedef struct { + byte checksum; // Simple checksum of the entire packet + byte type; /* Type of packet */ + byte reserved[2]; /* Was random in prboom <=2.2.4, now 0 */ + unsigned tic; // Timestamp +} PACKEDATTR packet_header_t; + +static inline void packet_set(packet_header_t* p, enum packet_type_e t, unsigned long tic) +{ p->tic = doom_htonl(tic); p->type = t; p->reserved[0] = 0; p->reserved[1] = 0; } + +#ifndef GAME_OPTIONS_SIZE +// From g_game.h +#define GAME_OPTIONS_SIZE 64 +#endif + +struct setup_packet_s { + byte players, yourplayer, skill, episode, level, deathmatch, complevel, ticdup, extratic; + byte game_options[GAME_OPTIONS_SIZE]; + byte numwads; + byte wadnames[1]; // Actually longer +}; + +/* cph - convert network byte stream to usable ticcmd_t and visa-versa + * - the functions are functionally identical apart from parameters + * - the void* param can be unaligned. By using void* as the parameter + * it means gcc won't assume alignment so won't make false assumptions + * when optimising. So I'm told. + */ +inline static void RawToTic(ticcmd_t* dst, const void* src) +{ + memcpy(dst,src,sizeof *dst); + dst->angleturn = doom_ntohs(dst->angleturn); + dst->consistancy = doom_ntohs(dst->consistancy); +} + +inline static void TicToRaw(void* dst, const ticcmd_t* src) +{ + /* We have to make a copy of the source struct, then do byte swaps, + * and fnially copy to the destination (can't do the swaps in the + * destination, because it might not be aligned). + */ + ticcmd_t tmp = *src; + tmp.angleturn = doom_ntohs(tmp.angleturn); + tmp.consistancy = doom_ntohs(tmp.consistancy); + memcpy(dst,&tmp,sizeof tmp); +} diff --git a/src/r_bsp.c b/src/r_bsp.c new file mode 100644 index 0000000..e9ce6c5 --- /dev/null +++ b/src/r_bsp.c @@ -0,0 +1,664 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * BSP traversal, handling of LineSegs for rendering. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "m_bbox.h" +#include "r_main.h" +#include "r_segs.h" +#include "r_plane.h" +#include "r_things.h" +#include "r_bsp.h" // cph - sanity checking +#include "v_video.h" +#include "lprintf.h" + +seg_t *curline; +side_t *sidedef; +line_t *linedef; +sector_t *frontsector; +sector_t *backsector; +drawseg_t *ds_p; + +// killough 4/7/98: indicates doors closed wrt automap bugfix: +// cph - replaced by linedef rendering flags - int doorclosed; + +// killough: New code which removes 2s linedef limit +drawseg_t *drawsegs; +unsigned maxdrawsegs; +// drawseg_t drawsegs[MAXDRAWSEGS]; // old code -- killough + +// +// R_ClearDrawSegs +// + +void R_ClearDrawSegs(void) +{ + ds_p = drawsegs; +} + +// CPhipps - +// Instead of clipsegs, let's try using an array with one entry for each column, +// indicating whether it's blocked by a solid wall yet or not. + +byte solidcol[MAX_SCREENWIDTH]; + +// CPhipps - +// R_ClipWallSegment +// +// Replaces the old R_Clip*WallSegment functions. It draws bits of walls in those +// columns which aren't solid, and updates the solidcol[] array appropriately + +static void R_ClipWallSegment(int first, int last, boolean solid) +{ + byte *p; + while (first < last) { + if (solidcol[first]) { + if (!(p = memchr(solidcol+first, 0, last-first))) return; // All solid + first = p - solidcol; + } else { + int to; + if (!(p = memchr(solidcol+first, 1, last-first))) to = last; + else to = p - solidcol; + R_StoreWallRange(first, to-1); + if (solid) { + memset(solidcol+first,1,to-first); + } + first = to; + } + } +} + +// +// R_ClearClipSegs +// + +void R_ClearClipSegs (void) +{ + memset(solidcol, 0, SCREENWIDTH); +} + +// killough 1/18/98 -- This function is used to fix the automap bug which +// showed lines behind closed doors simply because the door had a dropoff. +// +// cph - converted to R_RecalcLineFlags. This recalculates all the flags for +// a line, including closure and texture tiling. + +static void R_RecalcLineFlags(void) +{ + linedef->r_validcount = gametic; + + /* First decide if the line is closed, normal, or invisible */ + if (!(linedef->flags & ML_TWOSIDED) + || backsector->ceilingheight <= frontsector->floorheight + || backsector->floorheight >= frontsector->ceilingheight + || ( + // if door is closed because back is shut: + backsector->ceilingheight <= backsector->floorheight + + // preserve a kind of transparent door/lift special effect: + && (backsector->ceilingheight >= frontsector->ceilingheight || + curline->sidedef->toptexture) + + && (backsector->floorheight <= frontsector->floorheight || + curline->sidedef->bottomtexture) + + // properly render skies (consider door "open" if both ceilings are sky): + && (backsector->ceilingpic !=skyflatnum || + frontsector->ceilingpic!=skyflatnum) + ) + ) + linedef->r_flags = RF_CLOSED; + else { + // Reject empty lines used for triggers + // and special events. + // Identical floor and ceiling on both sides, + // identical light levels on both sides, + // and no middle texture. + // CPhipps - recode for speed, not certain if this is portable though + if (backsector->ceilingheight != frontsector->ceilingheight + || backsector->floorheight != frontsector->floorheight + || curline->sidedef->midtexture + || memcmp(&backsector->floor_xoffs, &frontsector->floor_xoffs, + sizeof(frontsector->floor_xoffs) + sizeof(frontsector->floor_yoffs) + + sizeof(frontsector->ceiling_xoffs) + sizeof(frontsector->ceiling_yoffs) + + sizeof(frontsector->ceilingpic) + sizeof(frontsector->floorpic) + + sizeof(frontsector->lightlevel) + sizeof(frontsector->floorlightsec) + + sizeof(frontsector->ceilinglightsec))) { + linedef->r_flags = 0; return; + } else + linedef->r_flags = RF_IGNORE; + } + + /* cph - I'm too lazy to try and work with offsets in this */ + if (curline->sidedef->rowoffset) return; + + /* Now decide on texture tiling */ + if (linedef->flags & ML_TWOSIDED) { + int c; + + /* Does top texture need tiling */ + if ((c = frontsector->ceilingheight - backsector->ceilingheight) > 0 && + (textureheight[texturetranslation[curline->sidedef->toptexture]] > c)) + linedef->r_flags |= RF_TOP_TILE; + + /* Does bottom texture need tiling */ + if ((c = frontsector->floorheight - backsector->floorheight) > 0 && + (textureheight[texturetranslation[curline->sidedef->bottomtexture]] > c)) + linedef->r_flags |= RF_BOT_TILE; + } else { + int c; + /* Does middle texture need tiling */ + if ((c = frontsector->ceilingheight - frontsector->floorheight) > 0 && + (textureheight[texturetranslation[curline->sidedef->midtexture]] > c)) + linedef->r_flags |= RF_MID_TILE; + } +} + +// +// killough 3/7/98: Hack floor/ceiling heights for deep water etc. +// +// If player's view height is underneath fake floor, lower the +// drawn ceiling to be just under the floor height, and replace +// the drawn floor and ceiling textures, and light level, with +// the control sector's. +// +// Similar for ceiling, only reflected. +// +// killough 4/11/98, 4/13/98: fix bugs, add 'back' parameter +// + +sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, + int *floorlightlevel, int *ceilinglightlevel, + boolean back) +{ + if (floorlightlevel) + *floorlightlevel = sec->floorlightsec == -1 ? + sec->lightlevel : sectors[sec->floorlightsec].lightlevel; + + if (ceilinglightlevel) + *ceilinglightlevel = sec->ceilinglightsec == -1 ? // killough 4/11/98 + sec->lightlevel : sectors[sec->ceilinglightsec].lightlevel; + + if (sec->heightsec != -1) + { + const sector_t *s = §ors[sec->heightsec]; + int heightsec = viewplayer->mo->subsector->sector->heightsec; + int underwater = heightsec!=-1 && viewz<=sectors[heightsec].floorheight; + + // Replace sector being drawn, with a copy to be hacked + *tempsec = *sec; + + // Replace floor and ceiling height with other sector's heights. + tempsec->floorheight = s->floorheight; + tempsec->ceilingheight = s->ceilingheight; + + // killough 11/98: prevent sudden light changes from non-water sectors: + if (underwater && (tempsec-> floorheight = sec->floorheight, + tempsec->ceilingheight = s->floorheight-1, !back)) + { // head-below-floor hack + tempsec->floorpic = s->floorpic; + tempsec->floor_xoffs = s->floor_xoffs; + tempsec->floor_yoffs = s->floor_yoffs; + + if (underwater) { + if (s->ceilingpic == skyflatnum) { + tempsec->floorheight = tempsec->ceilingheight+1; + tempsec->ceilingpic = tempsec->floorpic; + tempsec->ceiling_xoffs = tempsec->floor_xoffs; + tempsec->ceiling_yoffs = tempsec->floor_yoffs; + } else { + tempsec->ceilingpic = s->ceilingpic; + tempsec->ceiling_xoffs = s->ceiling_xoffs; + tempsec->ceiling_yoffs = s->ceiling_yoffs; + } + } + + tempsec->lightlevel = s->lightlevel; + + if (floorlightlevel) + *floorlightlevel = s->floorlightsec == -1 ? s->lightlevel : + sectors[s->floorlightsec].lightlevel; // killough 3/16/98 + + if (ceilinglightlevel) + *ceilinglightlevel = s->ceilinglightsec == -1 ? s->lightlevel : + sectors[s->ceilinglightsec].lightlevel; // killough 4/11/98 + } + else + if (heightsec != -1 && viewz >= sectors[heightsec].ceilingheight && + sec->ceilingheight > s->ceilingheight) + { // Above-ceiling hack + tempsec->ceilingheight = s->ceilingheight; + tempsec->floorheight = s->ceilingheight + 1; + + tempsec->floorpic = tempsec->ceilingpic = s->ceilingpic; + tempsec->floor_xoffs = tempsec->ceiling_xoffs = s->ceiling_xoffs; + tempsec->floor_yoffs = tempsec->ceiling_yoffs = s->ceiling_yoffs; + + if (s->floorpic != skyflatnum) + { + tempsec->ceilingheight = sec->ceilingheight; + tempsec->floorpic = s->floorpic; + tempsec->floor_xoffs = s->floor_xoffs; + tempsec->floor_yoffs = s->floor_yoffs; + } + + tempsec->lightlevel = s->lightlevel; + + if (floorlightlevel) + *floorlightlevel = s->floorlightsec == -1 ? s->lightlevel : + sectors[s->floorlightsec].lightlevel; // killough 3/16/98 + + if (ceilinglightlevel) + *ceilinglightlevel = s->ceilinglightsec == -1 ? s->lightlevel : + sectors[s->ceilinglightsec].lightlevel; // killough 4/11/98 + } + sec = tempsec; // Use other sector + } + return sec; +} + +// +// R_AddLine +// Clips the given segment +// and adds any visible pieces to the line list. +// + +static void R_AddLine (seg_t *line) +{ + int x1; + int x2; + angle_t angle1; + angle_t angle2; + angle_t span; + angle_t tspan; + static sector_t tempsec; // killough 3/8/98: ceiling/water hack + + curline = line; + + angle1 = R_PointToAngle (line->v1->x, line->v1->y); + angle2 = R_PointToAngle (line->v2->x, line->v2->y); + + // Clip to view edges. + span = angle1 - angle2; + + // Back side, i.e. backface culling + if (span >= ANG180) + return; + + // Global angle needed by segcalc. + rw_angle1 = angle1; + angle1 -= viewangle; + angle2 -= viewangle; + + tspan = angle1 + clipangle; + if (tspan > 2*clipangle) + { + tspan -= 2*clipangle; + + // Totally off the left edge? + if (tspan >= span) + return; + + angle1 = clipangle; + } + + tspan = clipangle - angle2; + if (tspan > 2*clipangle) + { + tspan -= 2*clipangle; + + // Totally off the left edge? + if (tspan >= span) + return; + angle2 = 0-clipangle; + } + + // The seg is in the view range, + // but not necessarily visible. + + angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT; + angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT; + + // killough 1/31/98: Here is where "slime trails" can SOMETIMES occur: + x1 = viewangletox[angle1]; + x2 = viewangletox[angle2]; + +#ifdef GL_DOOM + // proff 11/99: we have to add these segs to avoid gaps in OpenGL + if (x1 >= x2) // killough 1/31/98 -- change == to >= for robustness + { + if (V_GetMode() == VID_MODEGL) + { + if (ds_p == drawsegs+maxdrawsegs) // killough 1/98 -- fix 2s line HOM + { + unsigned pos = ds_p - drawsegs; // jff 8/9/98 fix from ZDOOM1.14a + unsigned newmax = maxdrawsegs ? maxdrawsegs*2 : 128; // killough + drawsegs = realloc(drawsegs,newmax*sizeof(*drawsegs)); + //ds_p = drawsegs+maxdrawsegs; + ds_p = drawsegs + pos; // jff 8/9/98 fix from ZDOOM1.14a + maxdrawsegs = newmax; + } + ds_p->curline = curline; + ds_p++; + gld_AddWall(curline); + return; + } + else + return; + } +#else + // Does not cross a pixel? + if (x1 >= x2) // killough 1/31/98 -- change == to >= for robustness + return; +#endif + + backsector = line->backsector; + + // Single sided line? + if (backsector) + // killough 3/8/98, 4/4/98: hack for invisible ceilings / deep water + backsector = R_FakeFlat(backsector, &tempsec, NULL, NULL, true); + + /* cph - roll up linedef properties in flags */ + if ((linedef = curline->linedef)->r_validcount != gametic) + R_RecalcLineFlags(); + + if (linedef->r_flags & RF_IGNORE) + { + return; + } + else + R_ClipWallSegment (x1, x2, linedef->r_flags & RF_CLOSED); +} + +// +// R_CheckBBox +// Checks BSP node/subtree bounding box. +// Returns true +// if some part of the bbox might be visible. +// + +static const int checkcoord[12][4] = // killough -- static const +{ + {3,0,2,1}, + {3,0,2,0}, + {3,1,2,0}, + {0}, + {2,0,2,1}, + {0,0,0,0}, + {3,1,3,0}, + {0}, + {2,0,3,1}, + {2,1,3,1}, + {2,1,3,0} +}; + +// killough 1/28/98: static // CPhipps - const parameter, reformatted +static boolean R_CheckBBox(const fixed_t *bspcoord) +{ + angle_t angle1, angle2; + + { + int boxpos; + const int* check; + + // Find the corners of the box + // that define the edges from current viewpoint. + boxpos = (viewx <= bspcoord[BOXLEFT] ? 0 : viewx < bspcoord[BOXRIGHT ] ? 1 : 2) + + (viewy >= bspcoord[BOXTOP ] ? 0 : viewy > bspcoord[BOXBOTTOM] ? 4 : 8); + + if (boxpos == 5) + return true; + + check = checkcoord[boxpos]; + angle1 = R_PointToAngle (bspcoord[check[0]], bspcoord[check[1]]) - viewangle; + angle2 = R_PointToAngle (bspcoord[check[2]], bspcoord[check[3]]) - viewangle; + } + + // cph - replaced old code, which was unclear and badly commented + // Much more efficient code now + if ((signed)angle1 < (signed)angle2) { /* it's "behind" us */ + /* Either angle1 or angle2 is behind us, so it doesn't matter if we + * change it to the corect sign + */ + if ((angle1 >= ANG180) && (angle1 < ANG270)) + angle1 = INT_MAX; /* which is ANG180-1 */ + else + angle2 = INT_MIN; + } + + if ((signed)angle2 >= (signed)clipangle) return false; // Both off left edge + if ((signed)angle1 <= -(signed)clipangle) return false; // Both off right edge + if ((signed)angle1 >= (signed)clipangle) angle1 = clipangle; // Clip at left edge + if ((signed)angle2 <= -(signed)clipangle) angle2 = 0-clipangle; // Clip at right edge + + // Find the first clippost + // that touches the source post + // (adjacent pixels are touching). + angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT; + angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT; + { + int sx1 = viewangletox[angle1]; + int sx2 = viewangletox[angle2]; + // const cliprange_t *start; + + // Does not cross a pixel. + if (sx1 == sx2) + return false; + + if (!memchr(solidcol+sx1, 0, sx2-sx1)) return false; + // All columns it covers are already solidly covered + } + + return true; +} + +// +// R_Subsector +// Determine floor/ceiling planes. +// Add sprites of things in sector. +// Draw one or more line segments. +// +// killough 1/31/98 -- made static, polished + +static void R_Subsector(int num) +{ + int count; + seg_t *line; + subsector_t *sub; + sector_t tempsec; // killough 3/7/98: deep water hack + int floorlightlevel; // killough 3/16/98: set floor lightlevel + int ceilinglightlevel; // killough 4/11/98 +#ifdef GL_DOOM + visplane_t dummyfloorplane; + visplane_t dummyceilingplane; +#endif + +#ifdef RANGECHECK + if (num>=numsubsectors) + I_Error ("R_Subsector: ss %i with numss = %i", num, numsubsectors); +#endif + + sub = &subsectors[num]; + frontsector = sub->sector; + count = sub->numlines; + line = &segs[sub->firstline]; + + // killough 3/8/98, 4/4/98: Deep water / fake ceiling effect + frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel, + &ceilinglightlevel, false); // killough 4/11/98 + + // killough 3/7/98: Add (x,y) offsets to flats, add deep water check + // killough 3/16/98: add floorlightlevel + // killough 10/98: add support for skies transferred from sidedefs + + floorplane = frontsector->floorheight < viewz || // killough 3/7/98 + (frontsector->heightsec != -1 && + sectors[frontsector->heightsec].ceilingpic == skyflatnum) ? + R_FindPlane(frontsector->floorheight, + frontsector->floorpic == skyflatnum && // kilough 10/98 + frontsector->sky & PL_SKYFLAT ? frontsector->sky : + frontsector->floorpic, + floorlightlevel, // killough 3/16/98 + frontsector->floor_xoffs, // killough 3/7/98 + frontsector->floor_yoffs + ) : NULL; + + ceilingplane = frontsector->ceilingheight > viewz || + frontsector->ceilingpic == skyflatnum || + (frontsector->heightsec != -1 && + sectors[frontsector->heightsec].floorpic == skyflatnum) ? + R_FindPlane(frontsector->ceilingheight, // killough 3/8/98 + frontsector->ceilingpic == skyflatnum && // kilough 10/98 + frontsector->sky & PL_SKYFLAT ? frontsector->sky : + frontsector->ceilingpic, + ceilinglightlevel, // killough 4/11/98 + frontsector->ceiling_xoffs, // killough 3/7/98 + frontsector->ceiling_yoffs + ) : NULL; +#ifdef GL_DOOM + // check if the sector is faked + if ((frontsector==sub->sector) && (V_GetMode() == VID_MODEGL)) + { + // if the sector has bottomtextures, then the floorheight will be set to the + // highest surounding floorheight + if ((frontsector->no_bottomtextures) || (!floorplane)) + { + int i=frontsector->linecount; + + dummyfloorplane.height=INT_MIN; + while (i--) + { + line_t *tmpline=frontsector->lines[i]; + if (tmpline->backsector) + if (tmpline->backsector != frontsector) + if (tmpline->backsector->floorheight>dummyfloorplane.height) + { + dummyfloorplane.height=tmpline->backsector->floorheight; + dummyfloorplane.lightlevel=tmpline->backsector->lightlevel; + } + if (tmpline->frontsector) + if (tmpline->frontsector != frontsector) + if (tmpline->frontsector->floorheight>dummyfloorplane.height) + { + dummyfloorplane.height=tmpline->frontsector->floorheight; + dummyfloorplane.lightlevel=tmpline->frontsector->lightlevel; + } + } + if (dummyfloorplane.height!=INT_MIN) + floorplane=&dummyfloorplane; + } + // the same for ceilings. they will be set to the lowest ceilingheight + if ((frontsector->no_toptextures) || (!ceilingplane)) + { + int i=frontsector->linecount; + + dummyceilingplane.height=INT_MAX; + while (i--) + { + line_t *tmpline=frontsector->lines[i]; + if (tmpline->backsector) + if (tmpline->backsector != frontsector) + if (tmpline->backsector->ceilingheightbacksector->ceilingheight; + dummyceilingplane.lightlevel=tmpline->backsector->lightlevel; + } + if (tmpline->frontsector) + if (tmpline->frontsector != frontsector) + if (tmpline->frontsector->ceilingheightfrontsector->ceilingheight; + dummyceilingplane.lightlevel=tmpline->frontsector->lightlevel; + } + } + if (dummyceilingplane.height!=INT_MAX) + ceilingplane=&dummyceilingplane; + } + } +#endif + + // killough 9/18/98: Fix underwater slowdown, by passing real sector + // instead of fake one. Improve sprite lighting by basing sprite + // lightlevels on floor & ceiling lightlevels in the surrounding area. + // + // 10/98 killough: + // + // NOTE: TeamTNT fixed this bug incorrectly, messing up sprite lighting!!! + // That is part of the 242 effect!!! If you simply pass sub->sector to + // the old code you will not get correct lighting for underwater sprites!!! + // Either you must pass the fake sector and handle validcount here, on the + // real sector, or you must account for the lighting in some other way, + // like passing it as an argument. + + R_AddSprites(sub, (floorlightlevel+ceilinglightlevel)/2); + while (count--) + { + if (line->miniseg == false) + R_AddLine (line); + line++; + curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so R_ColourMap doesn't try using it for other things */ + } +#ifdef GL_DOOM + if (V_GetMode() == VID_MODEGL) + gld_AddPlane(num, floorplane, ceilingplane); +#endif +} + +// +// RenderBSPNode +// Renders all subsectors below a given node, +// traversing subtree recursively. +// Just call with BSP root. +// +// killough 5/2/98: reformatted, removed tail recursion + +void R_RenderBSPNode(int bspnum) +{ + while (!(bspnum & NF_SUBSECTOR)) // Found a subsector? + { + const node_t *bsp = &nodes[bspnum]; + + // Decide which side the view point is on. + int side = R_PointOnSide(viewx, viewy, bsp); + // Recursively divide front space. + R_RenderBSPNode(bsp->children[side]); + + // Possibly divide back space. + + if (!R_CheckBBox(bsp->bbox[side^1])) + return; + + bspnum = bsp->children[side^1]; + } + R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); +} diff --git a/src/r_bsp.h b/src/r_bsp.h new file mode 100644 index 0000000..4ba9190 --- /dev/null +++ b/src/r_bsp.h @@ -0,0 +1,64 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Refresh module, BSP traversal and handling. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_BSP__ +#define __R_BSP__ + +#ifdef __GNUG__ +#pragma interface +#endif + +extern seg_t *curline; +extern side_t *sidedef; +extern line_t *linedef; +extern sector_t *frontsector; +extern sector_t *backsector; + +/* old code -- killough: + * extern drawseg_t drawsegs[MAXDRAWSEGS]; + * new code -- killough: */ +extern drawseg_t *drawsegs; +extern unsigned maxdrawsegs; + +extern byte solidcol[MAX_SCREENWIDTH]; + +extern drawseg_t *ds_p; + +void R_ClearClipSegs(void); +void R_ClearDrawSegs(void); +void R_RenderBSPNode(int bspnum); + +/* killough 4/13/98: fake floors/ceilings for deep water / fake ceilings: */ +sector_t *R_FakeFlat(sector_t *, sector_t *, int *, int *, boolean); + +#endif diff --git a/src/r_data.c b/src/r_data.c new file mode 100644 index 0000000..bf2c6c7 --- /dev/null +++ b/src/r_data.c @@ -0,0 +1,745 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2002 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Preparation of data for rendering, + * generation of lookups, caching, retrieval by name. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "w_wad.h" +#include "r_draw.h" +#include "r_main.h" +#include "r_sky.h" +#include "i_system.h" +#include "r_bsp.h" +#include "r_things.h" +#include "p_tick.h" +#include "lprintf.h" // jff 08/03/98 - declaration of lprintf +#include "p_tick.h" + +// +// Graphics. +// DOOM graphics for walls and sprites +// is stored in vertical runs of opaque pixels (posts). +// A column is composed of zero or more posts, +// a patch or sprite is composed of zero or more columns. +// + +// +// Texture definition. +// Each texture is composed of one or more patches, +// with patches being lumps stored in the WAD. +// The lumps are referenced by number, and patched +// into the rectangular texture space using origin +// and possibly other attributes. +// + +typedef struct +{ + short originx; + short originy; + short patch; + short stepdir; // unused in Doom but might be used in Phase 2 Boom + short colormap; // unused in Doom but might be used in Phase 2 Boom +} PACKEDATTR mappatch_t; + + +typedef struct +{ + char name[8]; + char pad2[4]; // unused + short width; + short height; + char pad[4]; // unused in Doom but might be used in Boom Phase 2 + short patchcount; + mappatch_t patches[1]; +} PACKEDATTR maptexture_t; + +// A maptexturedef_t describes a rectangular texture, which is composed +// of one or more mappatch_t structures that arrange graphic patches. + +// killough 4/17/98: make firstcolormaplump,lastcolormaplump external +int firstcolormaplump, lastcolormaplump; // killough 4/17/98 + +int firstflat, lastflat, numflats; +int firstspritelump, lastspritelump, numspritelumps; +int numtextures; +texture_t **textures; // proff - 04/05/2000 removed static for OpenGL +fixed_t *textureheight; //needed for texture pegging (and TFE fix - killough) +int *flattranslation; // for global animation +int *texturetranslation; + +// +// R_GetTextureColumn +// + +const byte *R_GetTextureColumn(const rpatch_t *texpatch, int col) { + while (col < 0) + col += texpatch->width; + col &= texpatch->widthmask; + + return texpatch->columns[col].pixels; +} + +// +// R_InitTextures +// Initializes the texture list +// with the textures from the world map. +// + +static void R_InitTextures (void) +{ + const maptexture_t *mtexture; + texture_t *texture; + const mappatch_t *mpatch; + texpatch_t *patch; + int i, j; + int maptex_lump[2] = {-1, -1}; + const int *maptex; + const int *maptex1, *maptex2; + char name[9]; + int names_lump; // cph - new wad lump handling + const char *names; // cph - + const char *name_p;// const*'s + int *patchlookup; + int totalwidth; + int nummappatches; + int offset; + int maxoff, maxoff2; + int numtextures1, numtextures2; + const int *directory; + int errors = 0; + + // Load the patch names from pnames.lmp. + name[8] = 0; + names = W_CacheLumpNum(names_lump = W_GetNumForName("PNAMES")); + nummappatches = LONG(*((const int *)names)); + name_p = names+4; + patchlookup = malloc(nummappatches*sizeof(*patchlookup)); // killough + + for (i=0 ; i maxoff) + I_Error("R_InitTextures: Bad texture directory"); + + mtexture = (const maptexture_t *) ( (const byte *)maptex + offset); + + texture = textures[i] = + Z_Malloc(sizeof(texture_t) + + sizeof(texpatch_t)*(SHORT(mtexture->patchcount)-1), + PU_STATIC, 0); + + texture->width = SHORT(mtexture->width); + texture->height = SHORT(mtexture->height); + texture->patchcount = SHORT(mtexture->patchcount); + + /* Mattias Engdegård emailed me of the following explenation of + * why memcpy doesnt work on some systems: + * "I suppose it is the mad unaligned allocation + * going on (and which gcc in some way manages to cope with + * through the __attribute__ ((packed))), and which it forgets + * when optimizing memcpy (to a single word move) since it appears + * to be aligned. Technically a gcc bug, but I can't blame it when + * it's stressed with that amount of + * non-standard nonsense." + * So in short the unaligned struct confuses gcc's optimizer so + * i took the memcpy out alltogether to avoid future problems-Jess + */ + /* The above was #ifndef SPARC, but i got a mail from + * Putera Joseph F NPRI containing: + * I had to use the memcpy function on a sparc machine. The + * other one would give me a core dump. + * cph - I find it hard to believe that sparc memcpy is broken, + * but I don't believe the pointers to memcpy have to be aligned + * either. Use fast memcpy on other machines anyway. + */ +/* + proff - I took this out, because Oli Kraus (olikraus@yahoo.com) told + me the memcpy produced a buserror. Since this function isn't time- + critical I'm using the for loop now. +*/ +/* +#ifndef GCC + memcpy(texture->name, mtexture->name, sizeof(texture->name)); +#else +*/ + { + int j; + for(j=0;jname);j++) + texture->name[j]=mtexture->name[j]; + } +/* #endif */ + + mpatch = mtexture->patches; + patch = texture->patches; + + for (j=0 ; jpatchcount ; j++, mpatch++, patch++) + { + patch->originx = SHORT(mpatch->originx); + patch->originy = SHORT(mpatch->originy); + patch->patch = patchlookup[SHORT(mpatch->patch)]; + if (patch->patch == -1) + { + //jff 8/3/98 use logical output routine + lprintf(LO_ERROR,"\nR_InitTextures: Missing patch %d in texture %.8s", + SHORT(mpatch->patch), texture->name); // killough 4/17/98 + ++errors; + } + } + + for (j=1; j*2 <= texture->width; j<<=1) + ; + texture->widthmask = j-1; + textureheight[i] = texture->height<width; + } + + free(patchlookup); // killough + + for (i=0; i<2; i++) // cph - release the TEXTUREx lumps + if (maptex_lump[i] != -1) + W_UnlockLumpNum(maptex_lump[i]); + + if (errors) + I_Error("R_InitTextures: %d errors", errors); + + // Precalculate whatever possible. + if (devparm) // cph - If in development mode, generate now so all errors are found at once + for (i=0 ; iindex = -1; + while (--i >= 0) + { + int j = W_LumpNameHash(textures[i]->name) % (unsigned) numtextures; + textures[i]->next = textures[j]->index; // Prepend to chain + textures[j]->index = i; + } +} + +// +// R_InitFlats +// +static void R_InitFlats(void) +{ + int i; + + firstflat = W_GetNumForName("F_START") + 1; + lastflat = W_GetNumForName("F_END") - 1; + numflats = lastflat - firstflat + 1; + + // Create translation table for global animation. + // killough 4/9/98: make column offsets 32-bit; + // clean up malloc-ing to use sizeof + + flattranslation = + Z_Malloc((numflats+1)*sizeof(*flattranslation), PU_STATIC, 0); + + for (i=0 ; i x ? l : x > u ? u : x); } + +const lighttable_t* R_ColourMap(int lightlevel, fixed_t spryscale) +{ + if (fixedcolormap) return fixedcolormap; + else { + if (curline) + if (curline->v1->y == curline->v2->y) + lightlevel -= 1 << LIGHTSEGSHIFT; + else + if (curline->v1->x == curline->v2->x) + lightlevel += 1 << LIGHTSEGSHIFT; + + lightlevel += extralight << LIGHTSEGSHIFT; + + /* cph 2001/11/17 - + * Work out what colour map to use, remembering to clamp it to the number of + * colour maps we actually have. This formula is basically the one from the + * original source, just brought into one place. The main difference is it + * throws away less precision in the lightlevel half, so it supports 32 + * light levels in WADs compared to Doom's 16. + * + * Note we can make it more accurate if we want - we should keep all the + * precision until the final step, so slight scale differences can count + * against slight light level variations. + */ + return fullcolormap + between(0,NUMCOLORMAPS-1, + ((256-lightlevel)*2*NUMCOLORMAPS/256) - 4 + - (FixedMul(spryscale,pspriteiscale)/2 >> LIGHTSCALESHIFT) + )*256; + } +} + +// +// R_InitTranMap +// +// Initialize translucency filter map +// +// By Lee Killough 2/21/98 +// + +int tran_filter_pct = 66; // filter percent + +#define TSC 12 /* number of fixed point digits in filter percent */ + +void R_InitTranMap(int progress) +{ + int lump = W_CheckNumForName("TRANMAP"); + + // If a tranlucency filter map lump is present, use it + + if (lump != -1) // Set a pointer to the translucency filter maps. + main_tranmap = W_CacheLumpNum(lump); // killough 4/11/98 + else if (W_CheckNumForName("PLAYPAL")!=-1) // can be called before WAD loaded + { // Compose a default transparent filter map based on PLAYPAL. + const byte *playpal = W_CacheLumpName("PLAYPAL"); + byte *my_tranmap; + + char fname[PATH_MAX+1]; + struct { + unsigned char pct; + unsigned char playpal[256]; + } cache; + FILE *cachefp = fopen(strcat(strcpy(fname, I_DoomExeDir()), "/tranmap.dat"),"rb"); + + main_tranmap = my_tranmap = Z_Malloc(256*256, PU_STATIC, 0); // killough 4/11/98 + + // Use cached translucency filter if it's available + + if (!cachefp || + fread(&cache, 1, sizeof cache, cachefp) != sizeof cache || + cache.pct != tran_filter_pct || + memcmp(cache.playpal, playpal, sizeof cache.playpal) || + fread(my_tranmap, 256, 256, cachefp) != 256 ) // killough 4/11/98 + { + long pal[3][256], tot[256], pal_w1[3][256]; + long w1 = ((unsigned long) tran_filter_pct<=0); + } + + // Next, compute all entries using minimum arithmetic. + + { + int i,j; + byte *tp = my_tranmap; + for (i=0;i<256;i++) + { + long r1 = pal[0][i] * w2; + long g1 = pal[1][i] * w2; + long b1 = pal[2][i] * w2; + if (!(i & 31) && progress) + //jff 8/3/98 use logical output routine + lprintf(LO_INFO,"."); + for (j=0;j<256;j++,tp++) + { + register int color = 255; + register long err; + long r = pal_w1[0][j] + r1; + long g = pal_w1[1][j] + g1; + long b = pal_w1[2][j] + b1; + long best = LONG_MAX; + do + if ((err = tot[color] - pal[0][color]*r + - pal[1][color]*g - pal[2][color]*b) < best) + best = err, *tp = color; + while (--color >= 0); + } + } + } + if ((cachefp = fopen(fname,"wb")) != NULL) // write out the cached translucency map + { + cache.pct = tran_filter_pct; + memcpy(cache.playpal, playpal, 256); + fseek(cachefp, 0, SEEK_SET); + fwrite(&cache, 1, sizeof cache, cachefp); + fwrite(main_tranmap, 256, 256, cachefp); + // CPhipps - leave close for a few lines... + } + } + + if (cachefp) // killough 11/98: fix filehandle leak + fclose(cachefp); + + W_UnlockLumpName("PLAYPAL"); + } +} + +// +// R_InitData +// Locates all the lumps +// that will be used by all views +// Must be called after W_Init. +// + +void R_InitData(void) +{ + lprintf(LO_INFO, "Textures "); + R_InitTextures(); + lprintf(LO_INFO, "Flats "); + R_InitFlats(); + lprintf(LO_INFO, "Sprites "); + R_InitSpriteLumps(); + if (default_translucency) // killough 3/1/98 + R_InitTranMap(1); // killough 2/21/98, 3/6/98 + R_InitColormaps(); // killough 3/20/98 +} + +// +// R_FlatNumForName +// Retrieval, get a flat number for a flat name. +// +// killough 4/17/98: changed to use ns_flats namespace +// + +int R_FlatNumForName(const char *name) // killough -- const added +{ + int i = (W_CheckNumForName)(name, ns_flats); + if (i == -1) + I_Error("R_FlatNumForName: %.8s not found", name); + return i - firstflat; +} + +// +// R_CheckTextureNumForName +// Check whether texture is available. +// Filter out NoTexture indicator. +// +// Rewritten by Lee Killough to use hash table for fast lookup. Considerably +// reduces the time needed to start new levels. See w_wad.c for comments on +// the hashing algorithm, which is also used for lump searches. +// +// killough 1/21/98, 1/31/98 +// + +int PUREFUNC R_CheckTextureNumForName(const char *name) +{ + int i = NO_TEXTURE; + if (*name != '-') // "NoTexture" marker. + { + i = textures[W_LumpNameHash(name) % (unsigned) numtextures]->index; + while (i >= 0 && strncasecmp(textures[i]->name,name,8)) + i = textures[i]->next; + } + return i; +} + +// +// R_TextureNumForName +// Calls R_CheckTextureNumForName, +// aborts with error message. +// + +int PUREFUNC R_TextureNumForName(const char *name) // const added -- killough +{ + int i = R_CheckTextureNumForName(name); + if (i == -1) + I_Error("R_TextureNumForName: %.8s not found", name); + return i; +} + +// +// R_SafeTextureNumForName +// Calls R_CheckTextureNumForName, and changes any error to NO_TEXTURE +int PUREFUNC R_SafeTextureNumForName(const char *name, int snum) +{ + int i = R_CheckTextureNumForName(name); + if (i == -1) { + i = NO_TEXTURE; // e6y - return "no texture" + lprintf(LO_DEBUG,"bad texture '%s' in sidedef %d\n",name,snum); + } + return i; +} + +// +// R_PrecacheLevel +// Preloads all relevant graphics for the level. +// +// Totally rewritten by Lee Killough to use less memory, +// to avoid using alloca(), and to improve performance. +// cph - new wad lump handling, calls cache functions but acquires no locks + +static inline void precache_lump(int l) +{ + W_CacheLumpNum(l); W_UnlockLumpNum(l); +} + +void R_PrecacheLevel(void) +{ + register int i; + register byte *hitlist; + + if (demoplayback) + return; + + { + size_t size = numflats > numsprites ? numflats : numsprites; + hitlist = malloc((size_t)numtextures > size ? numtextures : size); + } + + // Precache flats. + + memset(hitlist, 0, numflats); + + for (i = numsectors; --i >= 0; ) + hitlist[sectors[i].floorpic] = hitlist[sectors[i].ceilingpic] = 1; + + for (i = numflats; --i >= 0; ) + if (hitlist[i]) + precache_lump(firstflat + i); + + // Precache textures. + + memset(hitlist, 0, numtextures); + + for (i = numsides; --i >= 0;) + hitlist[sides[i].bottomtexture] = + hitlist[sides[i].toptexture] = + hitlist[sides[i].midtexture] = 1; + + // Sky texture is always present. + // Note that F_SKY1 is the name used to + // indicate a sky floor/ceiling as a flat, + // while the sky texture is stored like + // a wall texture, with an episode dependend + // name. + + hitlist[skytexture] = 1; + + for (i = numtextures; --i >= 0; ) + if (hitlist[i]) + { + texture_t *texture = textures[i]; + int j = texture->patchcount; + while (--j >= 0) + precache_lump(texture->patches[j].patch); + } + + // Precache sprites. + memset(hitlist, 0, numsprites); + + { + thinker_t *th = NULL; + while ((th = P_NextThinker(th,th_all)) != NULL) + if (th->function == P_MobjThinker) + hitlist[((mobj_t *)th)->sprite] = 1; + } + + for (i=numsprites; --i >= 0;) + if (hitlist[i]) + { + int j = sprites[i].numframes; + while (--j >= 0) + { + short *sflump = sprites[i].spriteframes[j].lump; + int k = 7; + do + precache_lump(firstspritelump + sflump[k]); + while (--k >= 0); + } + } + free(hitlist); +} + +// Proff - Added for OpenGL +void R_SetPatchNum(patchnum_t *patchnum, const char *name) +{ + const rpatch_t *patch = R_CachePatchName(name); + patchnum->width = patch->width; + patchnum->height = patch->height; + patchnum->leftoffset = patch->leftoffset; + patchnum->topoffset = patch->topoffset; + patchnum->lumpnum = W_GetNumForName(name); + R_UnlockPatchName(name); +} diff --git a/src/r_data.h b/src/r_data.h new file mode 100644 index 0000000..98f15b4 --- /dev/null +++ b/src/r_data.h @@ -0,0 +1,109 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Refresh module, data I/O, caching, retrieval of graphics + * by name. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __R_DATA__ +#define __R_DATA__ + +#include "r_defs.h" +#include "r_state.h" +#include "r_patch.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +// A single patch from a texture definition, basically +// a rectangular area within the texture rectangle. +typedef struct +{ + int originx, originy; // Block origin, which has already accounted + int patch; // for the internal origin of the patch. +} texpatch_t; + +// +// Texture definition. +// A DOOM wall texture is a list of patches +// which are to be combined in a predefined order. +// + +typedef struct +{ + char name[8]; // Keep name for switch changing, etc. + int next, index; // killough 1/31/98: used in hashing algorithm + // CPhipps - moved arrays with per-texture entries to elements here + unsigned widthmask; + // CPhipps - end of additions + short width, height; + short patchcount; // All the patches[patchcount] are drawn + texpatch_t patches[1]; // back-to-front into the cached texture. +} texture_t; + +extern int numtextures; +extern texture_t **textures; + + +const byte *R_GetTextureColumn(const rpatch_t *texpatch, int col); + + +// I/O, setting up the stuff. +void R_InitData (void); +void R_PrecacheLevel (void); + + +// Retrieval. +// Floor/ceiling opaque texture tiles, +// lookup by name. For animation? +int R_FlatNumForName (const char* name); // killough -- const added + + +// R_*TextureNumForName returns the texture number for the texture name, or NO_TEXTURE if +// there is no texture (i.e. "-") specified. +/* cph 2006/07/23 - defined value for no-texture marker (texture "-" in the WAD file) */ +#define NO_TEXTURE 0 +int PUREFUNC R_TextureNumForName (const char *name); // killough -- const added; cph - now PUREFUNC +int PUREFUNC R_SafeTextureNumForName (const char *name, int snum); +int PUREFUNC R_CheckTextureNumForName (const char *name); + +void R_InitTranMap(int); // killough 3/6/98: translucency initialization +int R_ColormapNumForName(const char *name); // killough 4/4/98 +/* cph 2001/11/17 - new func to do lighting calcs and get suitable colour map */ +const lighttable_t* R_ColourMap(int lightlevel, fixed_t spryscale); + +extern const byte *main_tranmap, *tranmap; + +/* Proff - Added for OpenGL - cph - const char* param */ +void R_SetPatchNum(patchnum_t *patchnum, const char *name); + +#endif diff --git a/src/r_defs.h b/src/r_defs.h new file mode 100644 index 0000000..07057bb --- /dev/null +++ b/src/r_defs.h @@ -0,0 +1,428 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Refresh/rendering module, shared data struct definitions. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_DEFS__ +#define __R_DEFS__ + +// Screenwidth. +#include "doomdef.h" + +// Some more or less basic data types +// we depend on. +#include "m_fixed.h" + +// We rely on the thinker data struct +// to handle sound origins in sectors. +#include "d_think.h" + +// SECTORS do store MObjs anyway. +#include "p_mobj.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +// Silhouette, needed for clipping Segs (mainly) +// and sprites representing things. +#define SIL_NONE 0 +#define SIL_BOTTOM 1 +#define SIL_TOP 2 +#define SIL_BOTH 3 + +#define MAXDRAWSEGS 256 + +// +// INTERNAL MAP TYPES +// used by play and refresh +// + +// +// Your plain vanilla vertex. +// Note: transformed values not buffered locally, +// like some DOOM-alikes ("wt", "WebView") do. +// +typedef struct +{ + fixed_t x, y; +} vertex_t; + +// Each sector has a degenmobj_t in its center for sound origin purposes. +typedef struct +{ + thinker_t thinker; // not used for anything + fixed_t x, y, z; +} degenmobj_t; + +// +// The SECTORS record, at runtime. +// Stores things/mobjs. +// + +typedef struct +{ + int iSectorID; // proff 04/05/2000: needed for OpenGL and used in debugmode by the HUD to draw sectornum + boolean no_toptextures; + boolean no_bottomtextures; + fixed_t floorheight; + fixed_t ceilingheight; + int nexttag,firsttag; // killough 1/30/98: improves searches for tags. + int soundtraversed; // 0 = untraversed, 1,2 = sndlines-1 + mobj_t *soundtarget; // thing that made a sound (or null) + int blockbox[4]; // mapblock bounding box for height changes + degenmobj_t soundorg; // origin for any sounds played by the sector + int validcount; // if == validcount, already checked + mobj_t *thinglist; // list of mobjs in sector + + /* killough 8/28/98: friction is a sector property, not an mobj property. + * these fields used to be in mobj_t, but presented performance problems + * when processed as mobj properties. Fix is to make them sector properties. + */ + int friction,movefactor; + + // thinker_t for reversable actions + void *floordata; // jff 2/22/98 make thinkers on + void *ceilingdata; // floors, ceilings, lighting, + void *lightingdata; // independent of one another + + // jff 2/26/98 lockout machinery for stairbuilding + int stairlock; // -2 on first locked -1 after thinker done 0 normally + int prevsec; // -1 or number of sector for previous step + int nextsec; // -1 or number of next step sector + + // killough 3/7/98: support flat heights drawn at another sector's heights + int heightsec; // other sector, or -1 if no other sector + + int bottommap, midmap, topmap; // killough 4/4/98: dynamic colormaps + + // list of mobjs that are at least partially in the sector + // thinglist is a subset of touching_thinglist + struct msecnode_s *touching_thinglist; // phares 3/14/98 + + int linecount; + struct line_s **lines; + + // killough 10/98: support skies coming from sidedefs. Allows scrolling + // skies and other effects. No "level info" kind of lump is needed, + // because you can use an arbitrary number of skies per level with this + // method. This field only applies when skyflatnum is used for floorpic + // or ceilingpic, because the rest of Doom needs to know which is sky + // and which isn't, etc. + + int sky; + + // killough 3/7/98: floor and ceiling texture offsets + fixed_t floor_xoffs, floor_yoffs; + fixed_t ceiling_xoffs, ceiling_yoffs; + + // killough 4/11/98: support for lightlevels coming from another sector + int floorlightsec, ceilinglightsec; + + short floorpic; + short ceilingpic; + short lightlevel; + short special; + short oldspecial; //jff 2/16/98 remembers if sector WAS secret (automap) + short tag; +} sector_t; + +// +// The SideDef. +// + +typedef struct +{ + fixed_t textureoffset; // add this to the calculated texture column + fixed_t rowoffset; // add this to the calculated texture top + short toptexture; // Texture indices. We do not maintain names here. + short bottomtexture; + short midtexture; + sector_t* sector; // Sector the SideDef is facing. + + // killough 4/4/98, 4/11/98: highest referencing special linedef's type, + // or lump number of special effect. Allows texture names to be overloaded + // for other functions. + + int special; + +} side_t; + +// +// Move clipping aid for LineDefs. +// +typedef enum +{ + ST_HORIZONTAL, + ST_VERTICAL, + ST_POSITIVE, + ST_NEGATIVE +} slopetype_t; + +typedef struct line_s +{ + int iLineID; // proff 04/05/2000: needed for OpenGL + vertex_t *v1, *v2; // Vertices, from v1 to v2. + fixed_t dx, dy; // Precalculated v2 - v1 for side checking. + unsigned short flags; // Animation related. + short special; + short tag; + unsigned short sidenum[2]; // Visual appearance: SideDefs. + fixed_t bbox[4]; // A bounding box, for the linedef's extent + slopetype_t slopetype; // To aid move clipping. + sector_t *frontsector; // Front and back sector. + sector_t *backsector; + int validcount; // if == validcount, already checked + void *specialdata; // thinker_t for reversable actions + int tranlump; // killough 4/11/98: translucency filter, -1 == none + int firsttag,nexttag; // killough 4/17/98: improves searches for tags. + int r_validcount; // cph: if == gametic, r_flags already done + enum { // cph: + RF_TOP_TILE = 1, // Upper texture needs tiling + RF_MID_TILE = 2, // Mid texture needs tiling + RF_BOT_TILE = 4, // Lower texture needs tiling + RF_IGNORE = 8, // Renderer can skip this line + RF_CLOSED =16, // Line blocks view + } r_flags; + degenmobj_t soundorg; // sound origin for switches/buttons +} line_t; + + +// phares 3/14/98 +// +// Sector list node showing all sectors an object appears in. +// +// There are two threads that flow through these nodes. The first thread +// starts at touching_thinglist in a sector_t and flows through the m_snext +// links to find all mobjs that are entirely or partially in the sector. +// The second thread starts at touching_sectorlist in an mobj_t and flows +// through the m_tnext links to find all sectors a thing touches. This is +// useful when applying friction or push effects to sectors. These effects +// can be done as thinkers that act upon all objects touching their sectors. +// As an mobj moves through the world, these nodes are created and +// destroyed, with the links changed appropriately. +// +// For the links, NULL means top or end of list. + +typedef struct msecnode_s +{ + sector_t *m_sector; // a sector containing this object + struct mobj_s *m_thing; // this object + struct msecnode_s *m_tprev; // prev msecnode_t for this thing + struct msecnode_s *m_tnext; // next msecnode_t for this thing + struct msecnode_s *m_sprev; // prev msecnode_t for this sector + struct msecnode_s *m_snext; // next msecnode_t for this sector + boolean visited; // killough 4/4/98, 4/7/98: used in search algorithms +} msecnode_t; + +// +// The LineSeg. +// +typedef struct +{ + vertex_t *v1, *v2; + fixed_t offset; + angle_t angle; + side_t* sidedef; + line_t* linedef; + + int iSegID; // proff 11/05/2000: needed for OpenGL + // figgi -- needed for glnodes + float length; + boolean miniseg; + + + // Sector references. + // Could be retrieved from linedef, too + // (but that would be slower -- killough) + // backsector is NULL for one sided lines + + sector_t *frontsector, *backsector; +} seg_t; + + +// +// A SubSector. +// References a Sector. +// Basically, this is a list of LineSegs, +// indicating the visible walls that define +// (all or some) sides of a convex BSP leaf. +// + +typedef struct subsector_s +{ + sector_t *sector; + unsigned short numlines, firstline; +} subsector_t; + + +// +// BSP node. +// +typedef struct +{ + fixed_t x, y, dx, dy; // Partition line. + fixed_t bbox[2][4]; // Bounding box for each child. + unsigned short children[2]; // If NF_SUBSECTOR its a subsector. +} node_t; + +// +// OTHER TYPES +// + +// This could be wider for >8 bit display. +// Indeed, true color support is posibble +// precalculating 24bpp lightmap/colormap LUT. +// from darkening PLAYPAL to all black. +// Could use even more than 32 levels. + +typedef byte lighttable_t; + +// +// Masked 2s linedefs +// + +typedef struct drawseg_s +{ + seg_t *curline; + int x1, x2; + fixed_t scale1, scale2, scalestep; + int silhouette; // 0=none, 1=bottom, 2=top, 3=both + fixed_t bsilheight; // do not clip sprites above this + fixed_t tsilheight; // do not clip sprites below this + + // Added for filtering (fractional texture u coord) support - POPE + fixed_t rw_offset, rw_distance, rw_centerangle; + + // Pointers to lists for sprite clipping, + // all three adjusted so [x1] is first value. + + int *sprtopclip, *sprbottomclip, *maskedtexturecol; // dropoff overflow +} drawseg_t; + +// proff: Added for OpenGL +typedef struct +{ + int width,height; + int leftoffset,topoffset; + int lumpnum; +} patchnum_t; + +// +// A vissprite_t is a thing that will be drawn during a refresh. +// i.e. a sprite object that is partly visible. +// + +typedef struct vissprite_s +{ + mobj_t *thing; + boolean flip; + int x1, x2; + fixed_t gx, gy; // for line side calculation + fixed_t gz, gzt; // global bottom / top for silhouette clipping + fixed_t startfrac; // horizontal position of x1 + fixed_t scale; + fixed_t xiscale; // negative if flipped + fixed_t texturemid; + int patch; + uint_64_t mobjflags; + + // for color translation and shadow draw, maxbright frames as well + const lighttable_t *colormap; + + // killough 3/27/98: height sector for underwater/fake ceiling support + int heightsec; + + boolean isplayersprite; +} vissprite_t; + +// +// Sprites are patches with a special naming convention +// so they can be recognized by R_InitSprites. +// The base name is NNNNFx or NNNNFxFx, with +// x indicating the rotation, x = 0, 1-7. +// The sprite and frame specified by a thing_t +// is range checked at run time. +// A sprite is a patch_t that is assumed to represent +// a three dimensional object and may have multiple +// rotations pre drawn. +// Horizontal flipping is used to save space, +// thus NNNNF2F5 defines a mirrored patch. +// Some sprites will only have one picture used +// for all views: NNNNF0 +// + +typedef struct +{ + // If false use 0 for any position. + // Note: as eight entries are available, + // we might as well insert the same name eight times. + boolean rotate; + + // Lump to use for view angles 0-7. + short lump[8]; + + // Flip bit (1 = flip) to use for view angles 0-7. + byte flip[8]; + +} spriteframe_t; + +// +// A sprite definition: +// a number of animation frames. +// + +typedef struct +{ + int numframes; + spriteframe_t *spriteframes; +} spritedef_t; + +// +// Now what is a visplane, anyway? +// +// Go to http://classicgaming.com/doom/editing/ to find out -- killough +// + +typedef struct visplane +{ + struct visplane *next; // Next visplane in hash chain -- killough + int picnum, lightlevel, minx, maxx; + fixed_t height; + fixed_t xoffs, yoffs; // killough 2/28/98: Support scrolling flats + unsigned int pad1; // leave pads for [minx-1]/[maxx+1] + unsigned int top[MAX_SCREENWIDTH]; + unsigned int pad2, pad3; // killough 2/8/98, 4/25/98 + unsigned int bottom[MAX_SCREENWIDTH]; + unsigned int pad4; // dropoff overflow +} visplane_t; + +#endif diff --git a/src/r_demo.c b/src/r_demo.c new file mode 100644 index 0000000..0f9e6f1 --- /dev/null +++ b/src/r_demo.c @@ -0,0 +1,88 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Demo stuff + * + *--------------------------------------------------------------------- + */ + +#include "doomstat.h" +#include "r_demo.h" +#include "r_fps.h" + +int demo_smoothturns = false; +int demo_smoothturnsfactor = 6; + +static int smooth_playing_turns[SMOOTH_PLAYING_MAXFACTOR]; +static int_64_t smooth_playing_sum; +static int smooth_playing_index; +static angle_t smooth_playing_angle; + +void R_SmoothPlaying_Reset(player_t *player) +{ + if (demo_smoothturns && demoplayback && players) + { + if (!player) + player = &players[displayplayer]; + + if (player==&players[displayplayer]) + { + smooth_playing_angle = players[displayplayer].mo->angle; + memset(smooth_playing_turns, 0, sizeof(smooth_playing_turns[0]) * SMOOTH_PLAYING_MAXFACTOR); + smooth_playing_sum = 0; + smooth_playing_index = 0; + } + } +} + +void R_SmoothPlaying_Add(int delta) +{ + if (demo_smoothturns && demoplayback) + { + smooth_playing_sum -= smooth_playing_turns[smooth_playing_index]; + smooth_playing_turns[smooth_playing_index] = delta; + smooth_playing_index = (smooth_playing_index + 1)%(demo_smoothturnsfactor); + smooth_playing_sum += delta; + smooth_playing_angle += (int)(smooth_playing_sum/(demo_smoothturnsfactor)); + } +} + +angle_t R_SmoothPlaying_Get(angle_t defangle) +{ + if (demo_smoothturns && demoplayback) + return smooth_playing_angle; + else + return defangle; +} + +void R_ResetAfterTeleport(player_t *player) +{ + R_ResetViewInterpolation(); + R_SmoothPlaying_Reset(player); +} diff --git a/src/r_demo.h b/src/r_demo.h new file mode 100644 index 0000000..e5be4cb --- /dev/null +++ b/src/r_demo.h @@ -0,0 +1,45 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Demo stuff + * + *--------------------------------------------------------------------- + */ + +#include "doomstat.h" + +#define SMOOTH_PLAYING_MAXFACTOR 16 + +extern int demo_smoothturns; +extern int demo_smoothturnsfactor; + +void R_SmoothPlaying_Reset(player_t *player); +void R_SmoothPlaying_Add(int delta); +angle_t R_SmoothPlaying_Get(angle_t defangle); +void R_ResetAfterTeleport(player_t *player); diff --git a/src/r_draw.c b/src/r_draw.c new file mode 100644 index 0000000..388bd76 --- /dev/null +++ b/src/r_draw.c @@ -0,0 +1,1128 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * The actual span/column drawing functions. + * Here find the main potential for optimization, + * e.g. inline assembly, different algorithms. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_draw.h" +#include "r_filter.h" +#include "v_video.h" +#include "st_stuff.h" +#include "g_game.h" +#include "am_map.h" +#include "lprintf.h" + +// +// All drawing to the view buffer is accomplished in this file. +// The other refresh files only know about ccordinates, +// not the architecture of the frame buffer. +// Conveniently, the frame buffer is a linear one, +// and we need only the base address, +// and the total size == width*height*depth/8., +// + +byte *viewimage; +int viewwidth; +int scaledviewwidth; +int viewheight; +int viewwindowx; +int viewwindowy; + +// Color tables for different players, +// translate a limited part to another +// (color ramps used for suit colors). +// + +// CPhipps - made const*'s +const byte *tranmap; // translucency filter maps 256x256 // phares +const byte *main_tranmap; // killough 4/11/98 + +// +// R_DrawColumn +// Source is the top of the column to scale. +// + +// SoM: OPTIMIZE for ANYRES +typedef enum +{ + COL_NONE, + COL_OPAQUE, + COL_TRANS, + COL_FLEXTRANS, + COL_FUZZ, + COL_FLEXADD +} columntype_e; + +static int temp_x = 0; +static int tempyl[4], tempyh[4]; +static byte byte_tempbuf[MAX_SCREENHEIGHT * 4]; +static unsigned short short_tempbuf[MAX_SCREENHEIGHT * 4]; +static unsigned int int_tempbuf[MAX_SCREENHEIGHT * 4]; +static int startx = 0; +static int temptype = COL_NONE; +static int commontop, commonbot; +static const byte *temptranmap = NULL; +// SoM 7-28-04: Fix the fuzz problem. +static const byte *tempfuzzmap; + +// +// Spectre/Invisibility. +// + +#define FUZZTABLE 50 +// proff 08/17/98: Changed for high-res +//#define FUZZOFF (SCREENWIDTH) +#define FUZZOFF 1 + +static const int fuzzoffset_org[FUZZTABLE] = { + FUZZOFF,-FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF, + FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF, + FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF, + FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF, + FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF, + FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF, + FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF +}; + +static int fuzzoffset[FUZZTABLE]; + +static int fuzzpos = 0; + +// render pipelines +#define RDC_STANDARD 1 +#define RDC_TRANSLUCENT 2 +#define RDC_TRANSLATED 4 +#define RDC_FUZZ 8 +// no color mapping +#define RDC_NOCOLMAP 16 +// filter modes +#define RDC_DITHERZ 32 +#define RDC_BILINEAR 64 +#define RDC_ROUNDED 128 + +draw_vars_t drawvars = { + NULL, // byte_topleft + NULL, // short_topleft + NULL, // int_topleft + 0, // byte_pitch + 0, // short_pitch + 0, // int_pitch + RDRAW_FILTER_POINT, // filterwall + RDRAW_FILTER_POINT, // filterfloor + RDRAW_FILTER_POINT, // filtersprite + RDRAW_FILTER_POINT, // filterz + RDRAW_FILTER_POINT, // filterpatch + + RDRAW_MASKEDCOLUMNEDGE_SQUARE, // sprite_edges + RDRAW_MASKEDCOLUMNEDGE_SQUARE, // patch_edges + + // 49152 = FRACUNIT * 0.75 + // 81920 = FRACUNIT * 1.25 + 49152 // mag_threshold +}; + +// +// Error functions that will abort if R_FlushColumns tries to flush +// columns without a column type. +// + +static void R_FlushWholeError(void) +{ + I_Error("R_FlushWholeColumns called without being initialized.\n"); +} + +static void R_FlushHTError(void) +{ + I_Error("R_FlushHTColumns called without being initialized.\n"); +} + +static void R_QuadFlushError(void) +{ + I_Error("R_FlushQuadColumn called without being initialized.\n"); +} + +static void (*R_FlushWholeColumns)(void) = R_FlushWholeError; +static void (*R_FlushHTColumns)(void) = R_FlushHTError; +static void (*R_FlushQuadColumn)(void) = R_QuadFlushError; + +static void R_FlushColumns(void) +{ + if(temp_x != 4 || commontop >= commonbot) + R_FlushWholeColumns(); + else + { + R_FlushHTColumns(); + R_FlushQuadColumn(); + } + temp_x = 0; +} + +// +// R_ResetColumnBuffer +// +// haleyjd 09/13/04: new function to call from main rendering loop +// which gets rid of the unnecessary reset of various variables during +// column drawing. +// +void R_ResetColumnBuffer(void) +{ + // haleyjd 10/06/05: this must not be done if temp_x == 0! + if(temp_x) + R_FlushColumns(); + temptype = COL_NONE; + R_FlushWholeColumns = R_FlushWholeError; + R_FlushHTColumns = R_FlushHTError; + R_FlushQuadColumn = R_QuadFlushError; +} + +#define R_DRAWCOLUMN_PIPELINE RDC_STANDARD +#define R_DRAWCOLUMN_PIPELINE_BITS 8 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole8 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT8 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad8 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_TRANSLUCENT +#define R_DRAWCOLUMN_PIPELINE_BITS 8 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL8 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL8 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL8 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_FUZZ +#define R_DRAWCOLUMN_PIPELINE_BITS 8 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz8 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz8 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz8 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_STANDARD +#define R_DRAWCOLUMN_PIPELINE_BITS 15 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole15 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT15 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad15 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_TRANSLUCENT +#define R_DRAWCOLUMN_PIPELINE_BITS 15 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL15 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL15 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL15 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_FUZZ +#define R_DRAWCOLUMN_PIPELINE_BITS 15 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz15 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz15 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz15 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_STANDARD +#define R_DRAWCOLUMN_PIPELINE_BITS 16 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole16 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT16 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad16 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_TRANSLUCENT +#define R_DRAWCOLUMN_PIPELINE_BITS 16 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL16 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL16 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL16 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_FUZZ +#define R_DRAWCOLUMN_PIPELINE_BITS 16 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz16 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz16 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz16 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_STANDARD +#define R_DRAWCOLUMN_PIPELINE_BITS 32 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole32 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT32 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad32 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_TRANSLUCENT +#define R_DRAWCOLUMN_PIPELINE_BITS 32 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL32 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL32 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL32 +#include "r_drawflush.inl" + +#define R_DRAWCOLUMN_PIPELINE RDC_FUZZ +#define R_DRAWCOLUMN_PIPELINE_BITS 32 +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz32 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz32 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz32 +#include "r_drawflush.inl" + +// +// R_DrawColumn +// + +// +// A column is a vertical slice/span from a wall texture that, +// given the DOOM style restrictions on the view orientation, +// will always have constant z depth. +// Thus a special case loop for very fast rendering can +// be used. It has also been used with Wolfenstein 3D. +// + +byte *translationtables; + +#define R_DRAWCOLUMN_PIPELINE_TYPE RDC_PIPELINE_STANDARD +#define R_DRAWCOLUMN_PIPELINE_BASE RDC_STANDARD + +#define R_DRAWCOLUMN_PIPELINE_BITS 8 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawColumn8 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole8 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT8 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad8 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 15 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawColumn15 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole15 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT15 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad15 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 16 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawColumn16 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole16 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT16 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad16 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 32 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawColumn32 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole32 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT32 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad32 +#include "r_drawcolpipeline.inl" + +#undef R_DRAWCOLUMN_PIPELINE_BASE +#undef R_DRAWCOLUMN_PIPELINE_TYPE + +// Here is the version of R_DrawColumn that deals with translucent // phares +// textures and sprites. It's identical to R_DrawColumn except // | +// for the spot where the color index is stuffed into *dest. At // V +// that point, the existing color index and the new color index +// are mapped through the TRANMAP lump filters to get a new color +// index whose RGB values are the average of the existing and new +// colors. +// +// Since we're concerned about performance, the 'translucent or +// opaque' decision is made outside this routine, not down where the +// actual code differences are. + +#define R_DRAWCOLUMN_PIPELINE_TYPE RDC_PIPELINE_TRANSLUCENT +#define R_DRAWCOLUMN_PIPELINE_BASE RDC_TRANSLUCENT + +#define R_DRAWCOLUMN_PIPELINE_BITS 8 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTLColumn8 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL8 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL8 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL8 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 15 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTLColumn15 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL15 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL15 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL15 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 16 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTLColumn16 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL16 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL16 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL16 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 32 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTLColumn32 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeTL32 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTTL32 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadTL32 +#include "r_drawcolpipeline.inl" + +#undef R_DRAWCOLUMN_PIPELINE_BASE +#undef R_DRAWCOLUMN_PIPELINE_TYPE + +// +// R_DrawTranslatedColumn +// Used to draw player sprites +// with the green colorramp mapped to others. +// Could be used with different translation +// tables, e.g. the lighter colored version +// of the BaronOfHell, the HellKnight, uses +// identical sprites, kinda brightened up. +// + +#define R_DRAWCOLUMN_PIPELINE_TYPE RDC_PIPELINE_TRANSLATED +#define R_DRAWCOLUMN_PIPELINE_BASE RDC_TRANSLATED + +#define R_DRAWCOLUMN_PIPELINE_BITS 8 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTranslatedColumn8 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole8 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT8 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad8 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 15 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTranslatedColumn15 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole15 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT15 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad15 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 16 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTranslatedColumn16 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole16 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT16 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad16 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 32 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawTranslatedColumn32 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWhole32 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHT32 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuad32 +#include "r_drawcolpipeline.inl" + +#undef R_DRAWCOLUMN_PIPELINE_BASE +#undef R_DRAWCOLUMN_PIPELINE_TYPE + +// +// Framebuffer postprocessing. +// Creates a fuzzy image by copying pixels +// from adjacent ones to left and right. +// Used with an all black colormap, this +// could create the SHADOW effect, +// i.e. spectres and invisible players. +// + +#define R_DRAWCOLUMN_PIPELINE_TYPE RDC_PIPELINE_FUZZ +#define R_DRAWCOLUMN_PIPELINE_BASE RDC_FUZZ + +#define R_DRAWCOLUMN_PIPELINE_BITS 8 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawFuzzColumn8 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz8 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz8 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz8 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 15 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawFuzzColumn15 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz15 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz15 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz15 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 16 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawFuzzColumn16 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz16 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz16 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz16 +#include "r_drawcolpipeline.inl" + +#define R_DRAWCOLUMN_PIPELINE_BITS 32 +#define R_DRAWCOLUMN_FUNCNAME_COMPOSITE(postfix) R_DrawFuzzColumn32 ## postfix +#define R_FLUSHWHOLE_FUNCNAME R_FlushWholeFuzz32 +#define R_FLUSHHEADTAIL_FUNCNAME R_FlushHTFuzz32 +#define R_FLUSHQUAD_FUNCNAME R_FlushQuadFuzz32 +#include "r_drawcolpipeline.inl" + +#undef R_DRAWCOLUMN_PIPELINE_BASE +#undef R_DRAWCOLUMN_PIPELINE_TYPE + +static R_DrawColumn_f drawcolumnfuncs[VID_MODEMAX][RDRAW_FILTER_MAXFILTERS][RDRAW_FILTER_MAXFILTERS][RDC_PIPELINE_MAXPIPELINES] = { + { + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn8_PointUV, + R_DrawTLColumn8_PointUV, + R_DrawTranslatedColumn8_PointUV, + R_DrawFuzzColumn8_PointUV,}, + {R_DrawColumn8_LinearUV, + R_DrawTLColumn8_LinearUV, + R_DrawTranslatedColumn8_LinearUV, + R_DrawFuzzColumn8_LinearUV,}, + {R_DrawColumn8_RoundedUV, + R_DrawTLColumn8_RoundedUV, + R_DrawTranslatedColumn8_RoundedUV, + R_DrawFuzzColumn8_RoundedUV,}, + }, + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn8_PointUV_PointZ, + R_DrawTLColumn8_PointUV_PointZ, + R_DrawTranslatedColumn8_PointUV_PointZ, + R_DrawFuzzColumn8_PointUV_PointZ,}, + {R_DrawColumn8_LinearUV_PointZ, + R_DrawTLColumn8_LinearUV_PointZ, + R_DrawTranslatedColumn8_LinearUV_PointZ, + R_DrawFuzzColumn8_LinearUV_PointZ,}, + {R_DrawColumn8_RoundedUV_PointZ, + R_DrawTLColumn8_RoundedUV_PointZ, + R_DrawTranslatedColumn8_RoundedUV_PointZ, + R_DrawFuzzColumn8_RoundedUV_PointZ,}, + }, + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn8_PointUV_LinearZ, + R_DrawTLColumn8_PointUV_LinearZ, + R_DrawTranslatedColumn8_PointUV_LinearZ, + R_DrawFuzzColumn8_PointUV_LinearZ,}, + {R_DrawColumn8_LinearUV_LinearZ, + R_DrawTLColumn8_LinearUV_LinearZ, + R_DrawTranslatedColumn8_LinearUV_LinearZ, + R_DrawFuzzColumn8_LinearUV_LinearZ,}, + {R_DrawColumn8_RoundedUV_LinearZ, + R_DrawTLColumn8_RoundedUV_LinearZ, + R_DrawTranslatedColumn8_RoundedUV_LinearZ, + R_DrawFuzzColumn8_RoundedUV_LinearZ,}, + }, + }, + { + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn15_PointUV, + R_DrawTLColumn15_PointUV, + R_DrawTranslatedColumn15_PointUV, + R_DrawFuzzColumn15_PointUV,}, + {R_DrawColumn15_LinearUV, + R_DrawTLColumn15_LinearUV, + R_DrawTranslatedColumn15_LinearUV, + R_DrawFuzzColumn15_LinearUV,}, + {R_DrawColumn15_RoundedUV, + R_DrawTLColumn15_RoundedUV, + R_DrawTranslatedColumn15_RoundedUV, + R_DrawFuzzColumn15_RoundedUV,}, + }, + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn15_PointUV_PointZ, + R_DrawTLColumn15_PointUV_PointZ, + R_DrawTranslatedColumn15_PointUV_PointZ, + R_DrawFuzzColumn15_PointUV_PointZ,}, + {R_DrawColumn15_LinearUV_PointZ, + R_DrawTLColumn15_LinearUV_PointZ, + R_DrawTranslatedColumn15_LinearUV_PointZ, + R_DrawFuzzColumn15_LinearUV_PointZ,}, + {R_DrawColumn15_RoundedUV_PointZ, + R_DrawTLColumn15_RoundedUV_PointZ, + R_DrawTranslatedColumn15_RoundedUV_PointZ, + R_DrawFuzzColumn15_RoundedUV_PointZ,}, + }, + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn15_PointUV_LinearZ, + R_DrawTLColumn15_PointUV_LinearZ, + R_DrawTranslatedColumn15_PointUV_LinearZ, + R_DrawFuzzColumn15_PointUV_LinearZ,}, + {R_DrawColumn15_LinearUV_LinearZ, + R_DrawTLColumn15_LinearUV_LinearZ, + R_DrawTranslatedColumn15_LinearUV_LinearZ, + R_DrawFuzzColumn15_LinearUV_LinearZ,}, + {R_DrawColumn15_RoundedUV_LinearZ, + R_DrawTLColumn15_RoundedUV_LinearZ, + R_DrawTranslatedColumn15_RoundedUV_LinearZ, + R_DrawFuzzColumn15_RoundedUV_LinearZ,}, + }, + }, + { + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn16_PointUV, + R_DrawTLColumn16_PointUV, + R_DrawTranslatedColumn16_PointUV, + R_DrawFuzzColumn16_PointUV,}, + {R_DrawColumn16_LinearUV, + R_DrawTLColumn16_LinearUV, + R_DrawTranslatedColumn16_LinearUV, + R_DrawFuzzColumn16_LinearUV,}, + {R_DrawColumn16_RoundedUV, + R_DrawTLColumn16_RoundedUV, + R_DrawTranslatedColumn16_RoundedUV, + R_DrawFuzzColumn16_RoundedUV,}, + }, + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn16_PointUV_PointZ, + R_DrawTLColumn16_PointUV_PointZ, + R_DrawTranslatedColumn16_PointUV_PointZ, + R_DrawFuzzColumn16_PointUV_PointZ,}, + {R_DrawColumn16_LinearUV_PointZ, + R_DrawTLColumn16_LinearUV_PointZ, + R_DrawTranslatedColumn16_LinearUV_PointZ, + R_DrawFuzzColumn16_LinearUV_PointZ,}, + {R_DrawColumn16_RoundedUV_PointZ, + R_DrawTLColumn16_RoundedUV_PointZ, + R_DrawTranslatedColumn16_RoundedUV_PointZ, + R_DrawFuzzColumn16_RoundedUV_PointZ,}, + }, + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn16_PointUV_LinearZ, + R_DrawTLColumn16_PointUV_LinearZ, + R_DrawTranslatedColumn16_PointUV_LinearZ, + R_DrawFuzzColumn16_PointUV_LinearZ,}, + {R_DrawColumn16_LinearUV_LinearZ, + R_DrawTLColumn16_LinearUV_LinearZ, + R_DrawTranslatedColumn16_LinearUV_LinearZ, + R_DrawFuzzColumn16_LinearUV_LinearZ,}, + {R_DrawColumn16_RoundedUV_LinearZ, + R_DrawTLColumn16_RoundedUV_LinearZ, + R_DrawTranslatedColumn16_RoundedUV_LinearZ, + R_DrawFuzzColumn16_RoundedUV_LinearZ,}, + }, + }, + { + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn32_PointUV, + R_DrawTLColumn32_PointUV, + R_DrawTranslatedColumn32_PointUV, + R_DrawFuzzColumn32_PointUV,}, + {R_DrawColumn32_LinearUV, + R_DrawTLColumn32_LinearUV, + R_DrawTranslatedColumn32_LinearUV, + R_DrawFuzzColumn32_LinearUV,}, + {R_DrawColumn32_RoundedUV, + R_DrawTLColumn32_RoundedUV, + R_DrawTranslatedColumn32_RoundedUV, + R_DrawFuzzColumn32_RoundedUV,}, + }, + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn32_PointUV_PointZ, + R_DrawTLColumn32_PointUV_PointZ, + R_DrawTranslatedColumn32_PointUV_PointZ, + R_DrawFuzzColumn32_PointUV_PointZ,}, + {R_DrawColumn32_LinearUV_PointZ, + R_DrawTLColumn32_LinearUV_PointZ, + R_DrawTranslatedColumn32_LinearUV_PointZ, + R_DrawFuzzColumn32_LinearUV_PointZ,}, + {R_DrawColumn32_RoundedUV_PointZ, + R_DrawTLColumn32_RoundedUV_PointZ, + R_DrawTranslatedColumn32_RoundedUV_PointZ, + R_DrawFuzzColumn32_RoundedUV_PointZ,}, + }, + { + {NULL, NULL, NULL, NULL,}, + {R_DrawColumn32_PointUV_LinearZ, + R_DrawTLColumn32_PointUV_LinearZ, + R_DrawTranslatedColumn32_PointUV_LinearZ, + R_DrawFuzzColumn32_PointUV_LinearZ,}, + {R_DrawColumn32_LinearUV_LinearZ, + R_DrawTLColumn32_LinearUV_LinearZ, + R_DrawTranslatedColumn32_LinearUV_LinearZ, + R_DrawFuzzColumn32_LinearUV_LinearZ,}, + {R_DrawColumn32_RoundedUV_LinearZ, + R_DrawTLColumn32_RoundedUV_LinearZ, + R_DrawTranslatedColumn32_RoundedUV_LinearZ, + R_DrawFuzzColumn32_RoundedUV_LinearZ,}, + }, + }, +}; + +R_DrawColumn_f R_GetDrawColumnFunc(enum column_pipeline_e type, + enum draw_filter_type_e filter, + enum draw_filter_type_e filterz) { + R_DrawColumn_f result = drawcolumnfuncs[V_GetMode()][filterz][filter][type]; + if (result == NULL) + I_Error("R_GetDrawColumnFunc: undefined function (%d, %d, %d)", + type, filter, filterz); + return result; +} + +void R_SetDefaultDrawColumnVars(draw_column_vars_t *dcvars) { + dcvars->x = dcvars->yl = dcvars->yh = dcvars->z = 0; + dcvars->iscale = dcvars->texturemid = dcvars->texheight = dcvars->texu = 0; + dcvars->source = dcvars->prevsource = dcvars->nextsource = NULL; + dcvars->colormap = dcvars->nextcolormap = colormaps[0]; + dcvars->translation = NULL; + dcvars->edgeslope = dcvars->drawingmasked = 0; + dcvars->edgetype = drawvars.sprite_edges; +} + +// +// R_InitTranslationTables +// Creates the translation tables to map +// the green color ramp to gray, brown, red. +// Assumes a given structure of the PLAYPAL. +// Could be read from a lump instead. +// + +byte playernumtotrans[MAXPLAYERS]; +extern lighttable_t *(*c_zlight)[LIGHTLEVELS][MAXLIGHTZ]; + +void R_InitTranslationTables (void) +{ + int i, j; +#define MAXTRANS 3 + byte transtocolour[MAXTRANS]; + + // killough 5/2/98: + // Remove dependency of colormaps aligned on 256-byte boundary + + if (translationtables == NULL) // CPhipps - allow multiple calls + translationtables = Z_Malloc(256*MAXTRANS, PU_STATIC, 0); + + for (i=0; i= 0x70 && i<= 0x7f) + { + // CPhipps - configurable player colours + translationtables[i] = colormaps[0][((i&0xf)<<9) + transtocolour[0]]; + translationtables[i+256] = colormaps[0][((i&0xf)<<9) + transtocolour[1]]; + translationtables[i+512] = colormaps[0][((i&0xf)<<9) + transtocolour[2]]; + } + else // Keep all other colors as is. + translationtables[i]=translationtables[i+256]=translationtables[i+512]=i; +} + +// +// R_DrawSpan +// With DOOM style restrictions on view orientation, +// the floors and ceilings consist of horizontal slices +// or spans with constant z depth. +// However, rotation around the world z axis is possible, +// thus this mapping, while simpler and faster than +// perspective correct texture mapping, has to traverse +// the texture at an angle in all but a few cases. +// In consequence, flats are not stored by column (like walls), +// and the inner loop has to step in texture space u and v. +// + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_PointUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 8 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_PointUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 8 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_LinearUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 8 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_LinearUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 8 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_RoundedUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 8 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan8_RoundedUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 8 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_PointUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 15 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_PointUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 15 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_LinearUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 15 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_LinearUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 15 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_RoundedUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 15 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan15_RoundedUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 15 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_PointUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 16 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_PointUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 16 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_LinearUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 16 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_LinearUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 16 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_RoundedUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 16 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan16_RoundedUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 16 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_PointUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 32 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_PointUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 32 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_LinearUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 32 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_LinearUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 32 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_BILINEAR | RDC_DITHERZ) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_RoundedUV_PointZ +#define R_DRAWSPAN_PIPELINE_BITS 32 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED) +#include "r_drawspan.inl" + +#define R_DRAWSPAN_FUNCNAME R_DrawSpan32_RoundedUV_LinearZ +#define R_DRAWSPAN_PIPELINE_BITS 32 +#define R_DRAWSPAN_PIPELINE (RDC_STANDARD | RDC_ROUNDED | RDC_DITHERZ) +#include "r_drawspan.inl" + +static R_DrawSpan_f drawspanfuncs[VID_MODEMAX][RDRAW_FILTER_MAXFILTERS][RDRAW_FILTER_MAXFILTERS] = { + { + { + NULL, + NULL, + NULL, + NULL, + }, + { + NULL, + R_DrawSpan8_PointUV_PointZ, + R_DrawSpan8_LinearUV_PointZ, + R_DrawSpan8_RoundedUV_PointZ, + }, + { + NULL, + R_DrawSpan8_PointUV_LinearZ, + R_DrawSpan8_LinearUV_LinearZ, + R_DrawSpan8_RoundedUV_LinearZ, + }, + { + NULL, + NULL, + NULL, + NULL, + }, + }, + { + { + NULL, + NULL, + NULL, + NULL, + }, + { + NULL, + R_DrawSpan15_PointUV_PointZ, + R_DrawSpan15_LinearUV_PointZ, + R_DrawSpan15_RoundedUV_PointZ, + }, + { + NULL, + R_DrawSpan15_PointUV_LinearZ, + R_DrawSpan15_LinearUV_LinearZ, + R_DrawSpan15_RoundedUV_LinearZ, + }, + { + NULL, + NULL, + NULL, + NULL, + }, + }, + { + { + NULL, + NULL, + NULL, + NULL, + }, + { + NULL, + R_DrawSpan16_PointUV_PointZ, + R_DrawSpan16_LinearUV_PointZ, + R_DrawSpan16_RoundedUV_PointZ, + }, + { + NULL, + R_DrawSpan16_PointUV_LinearZ, + R_DrawSpan16_LinearUV_LinearZ, + R_DrawSpan16_RoundedUV_LinearZ, + }, + { + NULL, + NULL, + NULL, + NULL, + }, + }, + { + { + NULL, + NULL, + NULL, + NULL, + }, + { + NULL, + R_DrawSpan32_PointUV_PointZ, + R_DrawSpan32_LinearUV_PointZ, + R_DrawSpan32_RoundedUV_PointZ, + }, + { + NULL, + R_DrawSpan32_PointUV_LinearZ, + R_DrawSpan32_LinearUV_LinearZ, + R_DrawSpan32_RoundedUV_LinearZ, + }, + { + NULL, + NULL, + NULL, + NULL, + }, + }, +}; + +R_DrawSpan_f R_GetDrawSpanFunc(enum draw_filter_type_e filter, + enum draw_filter_type_e filterz) { + R_DrawSpan_f result = drawspanfuncs[V_GetMode()][filterz][filter]; + if (result == NULL) + I_Error("R_GetDrawSpanFunc: undefined function (%d, %d)", + filter, filterz); + return result; +} + +void R_DrawSpan(draw_span_vars_t *dsvars) { + R_GetDrawSpanFunc(drawvars.filterfloor, drawvars.filterz)(dsvars); +} + +// +// R_InitBuffer +// Creats lookup tables that avoid +// multiplies and other hazzles +// for getting the framebuffer address +// of a pixel to draw. +// + +void R_InitBuffer(int width, int height) +{ + int i=0; + // Handle resize, + // e.g. smaller view windows + // with border and/or status bar. + + viewwindowx = (SCREENWIDTH-width) >> 1; + + // Same with base row offset. + + viewwindowy = width==SCREENWIDTH ? 0 : (SCREENHEIGHT-(ST_SCALED_HEIGHT-1)-height)>>1; + + drawvars.byte_topleft = screens[0].data + viewwindowy*screens[0].byte_pitch + viewwindowx; + drawvars.short_topleft = (unsigned short *)(screens[0].data) + viewwindowy*screens[0].short_pitch + viewwindowx; + drawvars.int_topleft = (unsigned int *)(screens[0].data) + viewwindowy*screens[0].int_pitch + viewwindowx; + drawvars.byte_pitch = screens[0].byte_pitch; + drawvars.short_pitch = screens[0].short_pitch; + drawvars.int_pitch = screens[0].int_pitch; + + if (V_GetMode() == VID_MODE8) { + for (i=0; i 0) { + for (i = (SCREENHEIGHT - ST_SCALED_HEIGHT); i < SCREENHEIGHT; i++) + { + R_VideoErase (0, i, side); + R_VideoErase (ST_SCALED_WIDTH+side, i, side); + } + } + } + + if ( viewheight >= ( SCREENHEIGHT - ST_SCALED_HEIGHT )) + return; // if high-res, don´t go any further! + + top = ((SCREENHEIGHT-ST_SCALED_HEIGHT)-viewheight)/2; + side = (SCREENWIDTH-scaledviewwidth)/2; + + // copy top + for (i = 0; i < top; i++) + R_VideoErase (0, i, SCREENWIDTH); + + // copy sides + for (i = top; i < (top+viewheight); i++) { + R_VideoErase (0, i, side); + R_VideoErase (viewwidth+side, i, side); + } + + // copy bottom + for (i = top+viewheight; i < (SCREENHEIGHT - ST_SCALED_HEIGHT); i++) + R_VideoErase (0, i, SCREENWIDTH); +} diff --git a/src/r_draw.h b/src/r_draw.h new file mode 100644 index 0000000..1b9bc62 --- /dev/null +++ b/src/r_draw.h @@ -0,0 +1,163 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * System specific interface stuff. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_DRAW__ +#define __R_DRAW__ + +#include "r_defs.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +enum column_pipeline_e { + RDC_PIPELINE_STANDARD, + RDC_PIPELINE_TRANSLUCENT, + RDC_PIPELINE_TRANSLATED, + RDC_PIPELINE_FUZZ, + RDC_PIPELINE_MAXPIPELINES, +}; + +// Used to specify what kind of filering you want +enum draw_filter_type_e { + RDRAW_FILTER_NONE, + RDRAW_FILTER_POINT, + RDRAW_FILTER_LINEAR, + RDRAW_FILTER_ROUNDED, + RDRAW_FILTER_MAXFILTERS +}; + +// Used to specify what kind of column edge rendering to use on masked +// columns. SQUARE = standard, SLOPED = slope the column edge up or down +// based on neighboring columns +enum sloped_edge_type_e { + RDRAW_MASKEDCOLUMNEDGE_SQUARE, + RDRAW_MASKEDCOLUMNEDGE_SLOPED +}; + +// Packaged into a struct - POPE +typedef struct { + int x; + int yl; + int yh; + fixed_t z; // the current column z coord + fixed_t iscale; + fixed_t texturemid; + int texheight; // killough + fixed_t texu; // the current column u coord + const byte *source; // first pixel in a column + const byte *prevsource; // first pixel in previous column + const byte *nextsource; // first pixel in next column + const lighttable_t *colormap; + const lighttable_t *nextcolormap; + const byte *translation; + int edgeslope; // OR'ed RDRAW_EDGESLOPE_* + // 1 if R_DrawColumn* is currently drawing a masked column, otherwise 0 + int drawingmasked; + enum sloped_edge_type_e edgetype; +} draw_column_vars_t; + +void R_SetDefaultDrawColumnVars(draw_column_vars_t *dcvars); + +void R_VideoErase(int x, int y, int count); + +typedef struct { + int y; + int x1; + int x2; + fixed_t z; // the current span z coord + fixed_t xfrac; + fixed_t yfrac; + fixed_t xstep; + fixed_t ystep; + const byte *source; // start of a 64*64 tile image + const lighttable_t *colormap; + const lighttable_t *nextcolormap; +} draw_span_vars_t; + +typedef struct { + byte *byte_topleft; + unsigned short *short_topleft; + unsigned int *int_topleft; + int byte_pitch; + int short_pitch; + int int_pitch; + + enum draw_filter_type_e filterwall; + enum draw_filter_type_e filterfloor; + enum draw_filter_type_e filtersprite; + enum draw_filter_type_e filterz; + enum draw_filter_type_e filterpatch; + + enum sloped_edge_type_e sprite_edges; + enum sloped_edge_type_e patch_edges; + + // Used to specify an early-out magnification threshold for filtering. + // If a texture is being minified (dcvars.iscale > rdraw_magThresh), then it + // drops back to point filtering. + fixed_t mag_threshold; +} draw_vars_t; + +extern draw_vars_t drawvars; + +extern byte playernumtotrans[MAXPLAYERS]; // CPhipps - what translation table for what player +extern byte *translationtables; + +typedef void (*R_DrawColumn_f)(draw_column_vars_t *dcvars); +R_DrawColumn_f R_GetDrawColumnFunc(enum column_pipeline_e type, + enum draw_filter_type_e filter, + enum draw_filter_type_e filterz); + +// Span blitting for rows, floor/ceiling. No Spectre effect needed. +typedef void (*R_DrawSpan_f)(draw_span_vars_t *dsvars); +R_DrawSpan_f R_GetDrawSpanFunc(enum draw_filter_type_e filter, + enum draw_filter_type_e filterz); +void R_DrawSpan(draw_span_vars_t *dsvars); + +void R_InitBuffer(int width, int height); + +// Initialize color translation tables, for player rendering etc. +void R_InitTranslationTables(void); + +// Rendering function. +void R_FillBackScreen(void); + +// If the view size is not full screen, draws a border around it. +void R_DrawViewBorder(void); + +// haleyjd 09/13/04: new function to call from main rendering loop +// which gets rid of the unnecessary reset of various variables during +// column drawing. +void R_ResetColumnBuffer(void); + +#endif diff --git a/src/r_drawcolpipeline.inl b/src/r_drawcolpipeline.inl new file mode 100644 index 0000000..8e122cd --- /dev/null +++ b/src/r_drawcolpipeline.inl @@ -0,0 +1,51 @@ + +// no color mapping +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_PointUV) +#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_NOCOLMAP) +#include "r_drawcolumn.inl" + +// simple depth color mapping +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_PointUV_PointZ) +#define R_DRAWCOLUMN_PIPELINE R_DRAWCOLUMN_PIPELINE_BASE +#include "r_drawcolumn.inl" + +// z-dither +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_PointUV_LinearZ) +#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_DITHERZ) +#include "r_drawcolumn.inl" + +// bilinear with no color mapping +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_LinearUV) +#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_BILINEAR | RDC_NOCOLMAP) +#include "r_drawcolumn.inl" + +// bilinear with simple depth color mapping +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_LinearUV_PointZ) +#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_BILINEAR) +#include "r_drawcolumn.inl" + +// bilinear + z-dither +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_LinearUV_LinearZ) +#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_BILINEAR | RDC_DITHERZ) +#include "r_drawcolumn.inl" + +// rounded with no color mapping +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_RoundedUV) +#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_ROUNDED | RDC_NOCOLMAP) +#include "r_drawcolumn.inl" + +// rounded with simple depth color mapping +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_RoundedUV_PointZ) +#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_ROUNDED) +#include "r_drawcolumn.inl" + +// rounded + z-dither +#define R_DRAWCOLUMN_FUNCNAME R_DRAWCOLUMN_FUNCNAME_COMPOSITE(_RoundedUV_LinearZ) +#define R_DRAWCOLUMN_PIPELINE (R_DRAWCOLUMN_PIPELINE_BASE | RDC_ROUNDED | RDC_DITHERZ) +#include "r_drawcolumn.inl" + +#undef R_FLUSHWHOLE_FUNCNAME +#undef R_FLUSHHEADTAIL_FUNCNAME +#undef R_FLUSHQUAD_FUNCNAME +#undef R_DRAWCOLUMN_FUNCNAME_COMPOSITE +#undef R_DRAWCOLUMN_PIPELINE_BITS diff --git a/src/r_drawcolumn.inl b/src/r_drawcolumn.inl new file mode 100644 index 0000000..199a24e --- /dev/null +++ b/src/r_drawcolumn.inl @@ -0,0 +1,378 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + *-----------------------------------------------------------------------------*/ + + +#if (R_DRAWCOLUMN_PIPELINE_BITS == 8) +#define SCREENTYPE byte +#define TEMPBUF byte_tempbuf +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 15) +#define SCREENTYPE unsigned short +#define TEMPBUF short_tempbuf +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 16) +#define SCREENTYPE unsigned short +#define TEMPBUF short_tempbuf +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 32) +#define SCREENTYPE unsigned int +#define TEMPBUF int_tempbuf +#endif + +#define GETDESTCOLOR8(col) (col) +#define GETDESTCOLOR15(col) (col) +#define GETDESTCOLOR16(col) (col) +#define GETDESTCOLOR32(col) (col) + +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLATED) +#define GETCOL8_MAPPED(col) (translation[(col)]) +#else +#define GETCOL8_MAPPED(col) (col) +#endif + +#if (R_DRAWCOLUMN_PIPELINE & RDC_NOCOLMAP) + #define GETCOL8_DEPTH(col) GETCOL8_MAPPED(col) +#else + #if (R_DRAWCOLUMN_PIPELINE & RDC_DITHERZ) + #define GETCOL8_DEPTH(col) (dither_colormaps[filter_getDitheredPixelLevel(x, y, fracz)][GETCOL8_MAPPED(col)]) + #else + #define GETCOL8_DEPTH(col) colormap[GETCOL8_MAPPED(col)] + #endif +#endif + +#if (R_DRAWCOLUMN_PIPELINE & RDC_BILINEAR) + #define GETCOL8(frac, nextfrac) GETCOL8_DEPTH(filter_getDitheredForColumn(x,y,frac,nextfrac)) + #define GETCOL15(frac, nextfrac) filter_getFilteredForColumn15(GETCOL8_DEPTH,frac,nextfrac) + #define GETCOL16(frac, nextfrac) filter_getFilteredForColumn16(GETCOL8_DEPTH,frac,nextfrac) + #define GETCOL32(frac, nextfrac) filter_getFilteredForColumn32(GETCOL8_DEPTH,frac,nextfrac) +#elif (R_DRAWCOLUMN_PIPELINE & RDC_ROUNDED) + #define GETCOL8(frac, nextfrac) GETCOL8_DEPTH(filter_getRoundedForColumn(frac,nextfrac)) + #define GETCOL15(frac, nextfrac) VID_PAL15(GETCOL8_DEPTH(filter_getRoundedForColumn(frac,nextfrac)), VID_COLORWEIGHTMASK) + #define GETCOL16(frac, nextfrac) VID_PAL16(GETCOL8_DEPTH(filter_getRoundedForColumn(frac,nextfrac)), VID_COLORWEIGHTMASK) + #define GETCOL32(frac, nextfrac) VID_PAL32(GETCOL8_DEPTH(filter_getRoundedForColumn(frac,nextfrac)), VID_COLORWEIGHTMASK) +#else + #define GETCOL8(frac, nextfrac) GETCOL8_DEPTH(source[(frac)>>FRACBITS]) + #define GETCOL15(frac, nextfrac) VID_PAL15(GETCOL8_DEPTH(source[(frac)>>FRACBITS]), VID_COLORWEIGHTMASK) + #define GETCOL16(frac, nextfrac) VID_PAL16(GETCOL8_DEPTH(source[(frac)>>FRACBITS]), VID_COLORWEIGHTMASK) + #define GETCOL32(frac, nextfrac) VID_PAL32(GETCOL8_DEPTH(source[(frac)>>FRACBITS]), VID_COLORWEIGHTMASK) +#endif + +#if (R_DRAWCOLUMN_PIPELINE & (RDC_BILINEAR|RDC_ROUNDED|RDC_DITHERZ)) + #define INCY(y) (y++) +#else + #define INCY(y) +#endif + +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT) +#define COLTYPE (COL_TRANS) +#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) +#define COLTYPE (COL_FUZZ) +#else +#define COLTYPE (COL_OPAQUE) +#endif + +#if (R_DRAWCOLUMN_PIPELINE_BITS == 8) + #define GETCOL(frac, nextfrac) GETCOL8(frac, nextfrac) + #define GETDESTCOLOR(col) GETDESTCOLOR8(col) +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 15) + #define GETCOL(frac, nextfrac) GETCOL15(frac, nextfrac) + #define GETDESTCOLOR(col) GETDESTCOLOR15(col) +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 16) + #define GETCOL(frac, nextfrac) GETCOL16(frac, nextfrac) + #define GETDESTCOLOR(col) GETDESTCOLOR16(col) +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 32) + #define GETCOL(frac, nextfrac) GETCOL32(frac, nextfrac) + #define GETDESTCOLOR(col) GETDESTCOLOR32(col) +#endif + +static void R_DRAWCOLUMN_FUNCNAME(draw_column_vars_t *dcvars) +{ + int count; + SCREENTYPE *dest; // killough + fixed_t frac; + const fixed_t fracstep = dcvars->iscale; +#if ((R_DRAWCOLUMN_PIPELINE & RDC_BILINEAR) && (R_DRAWCOLUMN_PIPELINE_BITS != 8)) + const fixed_t slope_texu = (dcvars->source == dcvars->nextsource) ? 0 : dcvars->texu & 0xffff; +#else + const fixed_t slope_texu = dcvars->texu; +#endif + + // drop back to point filtering if we're minifying +#if (R_DRAWCOLUMN_PIPELINE & (RDC_BILINEAR|RDC_ROUNDED)) + if (dcvars->iscale > drawvars.mag_threshold) { + R_GetDrawColumnFunc(R_DRAWCOLUMN_PIPELINE_TYPE, + RDRAW_FILTER_POINT, + drawvars.filterz)(dcvars); + return; + } +#endif + +#if (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) + // Adjust borders. Low... + if (!dcvars->yl) + dcvars->yl = 1; + + // .. and high. + if (dcvars->yh == viewheight-1) + dcvars->yh = viewheight - 2; +#endif + + // leban 1/17/99: + // removed the + 1 here, adjusted the if test, and added an increment + // later. this helps a compiler pipeline a bit better. the x86 + // assembler also does this. + + count = dcvars->yh - dcvars->yl; + + // leban 1/17/99: + // this case isn't executed too often. depending on how many instructions + // there are between here and the second if test below, this case could + // be moved down and might save instructions overall. since there are + // probably different wads that favor one way or the other, i'll leave + // this alone for now. + if (count < 0) // Zero length, column does not exceed a pixel. + return; + +#ifdef RANGECHECK + if (dcvars->x >= SCREENWIDTH + || dcvars->yl < 0 + || dcvars->yh >= SCREENHEIGHT) + I_Error("R_DrawColumn: %i to %i at %i", dcvars->yl, dcvars->yh, dcvars->x); +#endif + + // Determine scaling, which is the only mapping to be done. + #if (R_DRAWCOLUMN_PIPELINE & RDC_BILINEAR) + frac = dcvars->texturemid - (FRACUNIT>>1) + (dcvars->yl-centery)*fracstep; + #else + frac = dcvars->texturemid + (dcvars->yl-centery)*fracstep; + #endif + + if (dcvars->drawingmasked && dcvars->edgetype == RDRAW_MASKEDCOLUMNEDGE_SLOPED) { + // slope the top and bottom column edge based on the fractional u coordinate + // and dcvars->edgeslope, which were set in R_DrawMaskedColumn + // in r_things.c + if (dcvars->yl != 0) { + if (dcvars->edgeslope & RDRAW_EDGESLOPE_TOP_UP) { + // [/#] + int shift = ((0xffff-(slope_texu & 0xffff))/dcvars->iscale); + dcvars->yl += shift; + count -= shift; + frac += 0xffff-(slope_texu & 0xffff); + } + else if (dcvars->edgeslope & RDRAW_EDGESLOPE_TOP_DOWN) { + // [#\] + int shift = ((slope_texu & 0xffff)/dcvars->iscale); + dcvars->yl += shift; + count -= shift; + frac += slope_texu & 0xffff; + } + } + if (dcvars->yh != viewheight-1) { + if (dcvars->edgeslope & RDRAW_EDGESLOPE_BOT_UP) { + // [#/] + int shift = ((0xffff-(slope_texu & 0xffff))/dcvars->iscale); + dcvars->yh -= shift; + count -= shift; + } + else if (dcvars->edgeslope & RDRAW_EDGESLOPE_BOT_DOWN) { + // [\#] + int shift = ((slope_texu & 0xffff)/dcvars->iscale); + dcvars->yh -= shift; + count -= shift; + } + } + if (count <= 0) return; + } + + // Framebuffer destination address. + // SoM: MAGIC + { + // haleyjd: reordered predicates + if(temp_x == 4 || + (temp_x && (temptype != COLTYPE || temp_x + startx != dcvars->x))) + R_FlushColumns(); + + if(!temp_x) + { + startx = dcvars->x; + tempyl[0] = commontop = dcvars->yl; + tempyh[0] = commonbot = dcvars->yh; + temptype = COLTYPE; +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT) + temptranmap = tranmap; +#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) + tempfuzzmap = fullcolormap; // SoM 7-28-04: Fix the fuzz problem. +#endif + R_FlushWholeColumns = R_FLUSHWHOLE_FUNCNAME; + R_FlushHTColumns = R_FLUSHHEADTAIL_FUNCNAME; + R_FlushQuadColumn = R_FLUSHQUAD_FUNCNAME; + dest = &TEMPBUF[dcvars->yl << 2]; + } else { + tempyl[temp_x] = dcvars->yl; + tempyh[temp_x] = dcvars->yh; + + if(dcvars->yl > commontop) + commontop = dcvars->yl; + if(dcvars->yh < commonbot) + commonbot = dcvars->yh; + + dest = &TEMPBUF[(dcvars->yl << 2) + temp_x]; + } + temp_x += 1; + } + +// do nothing else when drawin fuzz columns +#if (!(R_DRAWCOLUMN_PIPELINE & RDC_FUZZ)) + { + const byte *source = dcvars->source; + const lighttable_t *colormap = dcvars->colormap; + const byte *translation = dcvars->translation; +#if (R_DRAWCOLUMN_PIPELINE & (RDC_BILINEAR|RDC_ROUNDED|RDC_DITHERZ)) + int y = dcvars->yl; + const int x = dcvars->x; +#endif +#if (R_DRAWCOLUMN_PIPELINE & RDC_DITHERZ) + const int fracz = (dcvars->z >> 6) & 255; + const byte *dither_colormaps[2] = { dcvars->colormap, dcvars->nextcolormap }; +#endif +#if (R_DRAWCOLUMN_PIPELINE & RDC_BILINEAR) + #if (R_DRAWCOLUMN_PIPELINE_BITS == 8) + const int yl = dcvars->yl; + const byte *dither_sources[2] = { dcvars->source, dcvars->nextsource }; + const unsigned int filter_fracu = (dcvars->source == dcvars->nextsource) ? 0 : (dcvars->texu>>8) & 0xff; + #else + const byte *nextsource = dcvars->nextsource; + const unsigned int filter_fracu = (dcvars->source == dcvars->nextsource) ? 0 : dcvars->texu & 0xffff; + #endif +#endif +#if (R_DRAWCOLUMN_PIPELINE & RDC_ROUNDED) + const byte *prevsource = dcvars->prevsource; + const byte *nextsource = dcvars->nextsource; + const unsigned int filter_fracu = (dcvars->source == dcvars->nextsource) ? 0 : (dcvars->texu>>8) & 0xff; +#endif + + count++; + + // Inner loop that does the actual texture mapping, + // e.g. a DDA-lile scaling. + // This is as fast as it gets. (Yeah, right!!! -- killough) + // + // killough 2/1/98: more performance tuning + + if (dcvars->texheight == 128) { + #define FIXEDT_128MASK ((127<texheight == 0) { + /* cph - another special case */ + while (count--) { + *dest = GETDESTCOLOR(GETCOL(frac, (frac+FRACUNIT))); + INCY(y); + dest += 4; + frac += fracstep; + } + } else { + unsigned heightmask = dcvars->texheight-1; // CPhipps - specify type + if (! (dcvars->texheight & heightmask) ) { // power of 2 -- killough + fixed_t fixedt_heightmask = (heightmask<=0) { // texture height is a power of 2 -- killough + *dest = GETDESTCOLOR(GETCOL(frac & fixedt_heightmask, (frac+FRACUNIT) & fixedt_heightmask)); + INCY(y); + dest += 4; + frac += fracstep; + *dest = GETDESTCOLOR(GETCOL(frac & fixedt_heightmask, (frac+FRACUNIT) & fixedt_heightmask)); + INCY(y); + dest += 4; + frac += fracstep; + } + if (count & 1) + *dest = GETDESTCOLOR(GETCOL(frac & fixedt_heightmask, (frac+FRACUNIT) & fixedt_heightmask)); + INCY(y); + } else { + fixed_t nextfrac = 0; + + heightmask++; + heightmask <<= FRACBITS; + + if (frac < 0) + while ((frac += heightmask) < 0); + else + while (frac >= (int)heightmask) + frac -= heightmask; + +#if (R_DRAWCOLUMN_PIPELINE & (RDC_BILINEAR|RDC_ROUNDED)) + nextfrac = frac + FRACUNIT; + while (nextfrac >= (int)heightmask) + nextfrac -= heightmask; +#endif + +#define INCFRAC(f) if ((f += fracstep) >= (int)heightmask) f -= heightmask; + + while (count--) { + // Re-map color indices from wall texture column + // using a lighting/special effects LUT. + + // heightmask is the Tutti-Frutti fix -- killough + + *dest = GETDESTCOLOR(GETCOL(frac, nextfrac)); + INCY(y); + dest += 4; + INCFRAC(frac); +#if (R_DRAWCOLUMN_PIPELINE & (RDC_BILINEAR|RDC_ROUNDED)) + INCFRAC(nextfrac); +#endif + } + } + } + } +#endif // (!(R_DRAWCOLUMN_PIPELINE & RDC_FUZZ)) +} + +#undef GETDESTCOLOR32 +#undef GETDESTCOLOR16 +#undef GETDESTCOLOR15 +#undef GETDESTCOLOR8 +#undef GETDESTCOLOR +#undef GETCOL8_MAPPED +#undef GETCOL8_DEPTH +#undef GETCOL32 +#undef GETCOL16 +#undef GETCOL15 +#undef GETCOL8 +#undef GETCOL +#undef INCY +#undef INCFRAC +#undef COLTYPE +#undef TEMPBUF +#undef SCREENTYPE + +#undef R_DRAWCOLUMN_FUNCNAME +#undef R_DRAWCOLUMN_PIPELINE diff --git a/src/r_drawflush.inl b/src/r_drawflush.inl new file mode 100644 index 0000000..ab8ce61 --- /dev/null +++ b/src/r_drawflush.inl @@ -0,0 +1,300 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + *-----------------------------------------------------------------------------*/ + +#if (R_DRAWCOLUMN_PIPELINE_BITS == 8) +#define SCREENTYPE byte +#define TOPLEFT byte_topleft +#define PITCH byte_pitch +#define TEMPBUF byte_tempbuf +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 15) +#define SCREENTYPE unsigned short +#define TOPLEFT short_topleft +#define PITCH short_pitch +#define TEMPBUF short_tempbuf +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 16) +#define SCREENTYPE unsigned short +#define TOPLEFT short_topleft +#define PITCH short_pitch +#define TEMPBUF short_tempbuf +#elif (R_DRAWCOLUMN_PIPELINE_BITS == 32) +#define SCREENTYPE unsigned int +#define TOPLEFT int_topleft +#define PITCH int_pitch +#define TEMPBUF int_tempbuf +#endif + +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT) +#define GETDESTCOLOR8(col1, col2) (temptranmap[((col1)<<8)+(col2)]) +#define GETDESTCOLOR15(col1, col2) (GETBLENDED15_3268((col1), (col2))) +#define GETDESTCOLOR16(col1, col2) (GETBLENDED16_3268((col1), (col2))) +#define GETDESTCOLOR32(col1, col2) (GETBLENDED32_3268((col1), (col2))) +#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) +#define GETDESTCOLOR8(col) (tempfuzzmap[6*256+(col)]) +#define GETDESTCOLOR15(col) GETBLENDED15_9406(col, 0) +#define GETDESTCOLOR16(col) GETBLENDED16_9406(col, 0) +#define GETDESTCOLOR32(col) GETBLENDED32_9406(col, 0) +#else +#define GETDESTCOLOR8(col) (col) +#define GETDESTCOLOR15(col) (col) +#define GETDESTCOLOR16(col) (col) +#define GETDESTCOLOR32(col) (col) +#endif + +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT) + #if (R_DRAWCOLUMN_PIPELINE_BITS == 8) + #define GETDESTCOLOR(col1, col2) GETDESTCOLOR8(col1, col2) + #elif (R_DRAWCOLUMN_PIPELINE_BITS == 15) + #define GETDESTCOLOR(col1, col2) GETDESTCOLOR15(col1, col2) + #elif (R_DRAWCOLUMN_PIPELINE_BITS == 16) + #define GETDESTCOLOR(col1, col2) GETDESTCOLOR16(col1, col2) + #elif (R_DRAWCOLUMN_PIPELINE_BITS == 32) + #define GETDESTCOLOR(col1, col2) GETDESTCOLOR32(col1, col2) + #endif +#else + #if (R_DRAWCOLUMN_PIPELINE_BITS == 8) + #define GETDESTCOLOR(col) GETDESTCOLOR8(col) + #elif (R_DRAWCOLUMN_PIPELINE_BITS == 15) + #define GETDESTCOLOR(col) GETDESTCOLOR15(col) + #elif (R_DRAWCOLUMN_PIPELINE_BITS == 16) + #define GETDESTCOLOR(col) GETDESTCOLOR16(col) + #elif (R_DRAWCOLUMN_PIPELINE_BITS == 32) + #define GETDESTCOLOR(col) GETDESTCOLOR32(col) + #endif +#endif + +// +// R_FlushWholeOpaque +// +// Flushes the entire columns in the buffer, one at a time. +// This is used when a quad flush isn't possible. +// Opaque version -- no remapping whatsoever. +// +static void R_FLUSHWHOLE_FUNCNAME(void) +{ + SCREENTYPE *source; + SCREENTYPE *dest; + int count, yl; + + while(--temp_x >= 0) + { + yl = tempyl[temp_x]; + source = &TEMPBUF[temp_x + (yl << 2)]; + dest = drawvars.TOPLEFT + yl*drawvars.PITCH + startx + temp_x; + count = tempyh[temp_x] - yl + 1; + + while(--count >= 0) + { +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT) + *dest = GETDESTCOLOR(*dest, *source); +#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) + // SoM 7-28-04: Fix the fuzz problem. + *dest = GETDESTCOLOR(dest[fuzzoffset[fuzzpos]]); + + // Clamp table lookup index. + if(++fuzzpos == FUZZTABLE) + fuzzpos = 0; +#else + *dest = *source; +#endif + + source += 4; + dest += drawvars.PITCH; + } + } +} + +// +// R_FlushHTOpaque +// +// Flushes the head and tail of columns in the buffer in +// preparation for a quad flush. +// Opaque version -- no remapping whatsoever. +// +static void R_FLUSHHEADTAIL_FUNCNAME(void) +{ + SCREENTYPE *source; + SCREENTYPE *dest; + int count, colnum = 0; + int yl, yh; + + while(colnum < 4) + { + yl = tempyl[colnum]; + yh = tempyh[colnum]; + + // flush column head + if(yl < commontop) + { + source = &TEMPBUF[colnum + (yl << 2)]; + dest = drawvars.TOPLEFT + yl*drawvars.PITCH + startx + colnum; + count = commontop - yl; + + while(--count >= 0) + { +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT) + // haleyjd 09/11/04: use temptranmap here + *dest = GETDESTCOLOR(*dest, *source); +#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) + // SoM 7-28-04: Fix the fuzz problem. + *dest = GETDESTCOLOR(dest[fuzzoffset[fuzzpos]]); + + // Clamp table lookup index. + if(++fuzzpos == FUZZTABLE) + fuzzpos = 0; +#else + *dest = *source; +#endif + + source += 4; + dest += drawvars.PITCH; + } + } + + // flush column tail + if(yh > commonbot) + { + source = &TEMPBUF[colnum + ((commonbot + 1) << 2)]; + dest = drawvars.TOPLEFT + (commonbot + 1)*drawvars.PITCH + startx + colnum; + count = yh - commonbot; + + while(--count >= 0) + { +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT) + // haleyjd 09/11/04: use temptranmap here + *dest = GETDESTCOLOR(*dest, *source); +#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) + // SoM 7-28-04: Fix the fuzz problem. + *dest = GETDESTCOLOR(dest[fuzzoffset[fuzzpos]]); + + // Clamp table lookup index. + if(++fuzzpos == FUZZTABLE) + fuzzpos = 0; +#else + *dest = *source; +#endif + + source += 4; + dest += drawvars.PITCH; + } + } + ++colnum; + } +} + +static void R_FLUSHQUAD_FUNCNAME(void) +{ + SCREENTYPE *source = &TEMPBUF[commontop << 2]; + SCREENTYPE *dest = drawvars.TOPLEFT + commontop*drawvars.PITCH + startx; + int count; +#if (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) + int fuzz1, fuzz2, fuzz3, fuzz4; + + fuzz1 = fuzzpos; + fuzz2 = (fuzz1 + tempyl[1]) % FUZZTABLE; + fuzz3 = (fuzz2 + tempyl[2]) % FUZZTABLE; + fuzz4 = (fuzz3 + tempyl[3]) % FUZZTABLE; +#endif + + count = commonbot - commontop + 1; + +#if (R_DRAWCOLUMN_PIPELINE & RDC_TRANSLUCENT) + while(--count >= 0) + { + dest[0] = GETDESTCOLOR(dest[0], source[0]); + dest[1] = GETDESTCOLOR(dest[1], source[1]); + dest[2] = GETDESTCOLOR(dest[2], source[2]); + dest[3] = GETDESTCOLOR(dest[3], source[3]); + source += 4 * sizeof(byte); + dest += drawvars.PITCH * sizeof(byte); + } +#elif (R_DRAWCOLUMN_PIPELINE & RDC_FUZZ) + while(--count >= 0) + { + dest[0] = GETDESTCOLOR(dest[0 + fuzzoffset[fuzz1]]); + dest[1] = GETDESTCOLOR(dest[1 + fuzzoffset[fuzz2]]); + dest[2] = GETDESTCOLOR(dest[2 + fuzzoffset[fuzz3]]); + dest[3] = GETDESTCOLOR(dest[3 + fuzzoffset[fuzz4]]); + fuzz1 = (fuzz1 + 1) % FUZZTABLE; + fuzz2 = (fuzz2 + 1) % FUZZTABLE; + fuzz3 = (fuzz3 + 1) % FUZZTABLE; + fuzz4 = (fuzz4 + 1) % FUZZTABLE; + source += 4 * sizeof(byte); + dest += drawvars.PITCH * sizeof(byte); + } +#else + #if (R_DRAWCOLUMN_PIPELINE_BITS == 8) + if ((sizeof(int) == 4) && (((int)source % 4) == 0) && (((int)dest % 4) == 0)) { + while(--count >= 0) + { + *(int *)dest = *(int *)source; + source += 4 * sizeof(byte); + dest += drawvars.PITCH * sizeof(byte); + } + } else { + while(--count >= 0) + { + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; + source += 4 * sizeof(byte); + dest += drawvars.PITCH * sizeof(byte); + } + } + #else + while(--count >= 0) + { + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; + source += 4; + dest += drawvars.PITCH; + } + #endif +#endif +} + +#undef GETDESTCOLOR32 +#undef GETDESTCOLOR16 +#undef GETDESTCOLOR15 +#undef GETDESTCOLOR8 +#undef GETDESTCOLOR + +#undef TEMPBUF +#undef PITCH +#undef TOPLEFT +#undef SCREENTYPE + +#undef R_DRAWCOLUMN_PIPELINE_BITS +#undef R_DRAWCOLUMN_PIPELINE +#undef R_FLUSHWHOLE_FUNCNAME +#undef R_FLUSHHEADTAIL_FUNCNAME +#undef R_FLUSHQUAD_FUNCNAME diff --git a/src/r_drawspan.inl b/src/r_drawspan.inl new file mode 100644 index 0000000..84cc95d --- /dev/null +++ b/src/r_drawspan.inl @@ -0,0 +1,160 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + *-----------------------------------------------------------------------------*/ + +// +// R_DrawSpan +// + +#if (R_DRAWSPAN_PIPELINE_BITS == 8) +#define SCREENTYPE byte +#define TOPLEFT byte_topleft +#define PITCH byte_pitch +#elif (R_DRAWSPAN_PIPELINE_BITS == 15) +#define SCREENTYPE unsigned short +#define TOPLEFT short_topleft +#define PITCH short_pitch +#elif (R_DRAWSPAN_PIPELINE_BITS == 16) +#define SCREENTYPE unsigned short +#define TOPLEFT short_topleft +#define PITCH short_pitch +#elif (R_DRAWSPAN_PIPELINE_BITS == 32) +#define SCREENTYPE unsigned int +#define TOPLEFT int_topleft +#define PITCH int_pitch +#endif + +#if (R_DRAWSPAN_PIPELINE & RDC_DITHERZ) + #define GETDEPTHMAP(col) dither_colormaps[filter_getDitheredPixelLevel(x1, y, fracz)][(col)] +#else + #define GETDEPTHMAP(col) colormap[(col)] +#endif + +#if (R_DRAWSPAN_PIPELINE_BITS == 8) + #define GETCOL_POINT(col) GETDEPTHMAP(col) + #define GETCOL_LINEAR(col) GETDEPTHMAP(col) +#elif (R_DRAWSPAN_PIPELINE_BITS == 15) + #define GETCOL_POINT(col) VID_PAL15(GETDEPTHMAP(col), VID_COLORWEIGHTMASK) + #define GETCOL_LINEAR(col) filter_getFilteredForSpan15(GETDEPTHMAP, xfrac, yfrac) +#elif (R_DRAWSPAN_PIPELINE_BITS == 16) + #define GETCOL_POINT(col) VID_PAL16(GETDEPTHMAP(col), VID_COLORWEIGHTMASK) + #define GETCOL_LINEAR(col) filter_getFilteredForSpan16(GETDEPTHMAP, xfrac, yfrac) +#elif (R_DRAWSPAN_PIPELINE_BITS == 32) + #define GETCOL_POINT(col) VID_PAL32(GETDEPTHMAP(col), VID_COLORWEIGHTMASK) + #define GETCOL_LINEAR(col) filter_getFilteredForSpan32(GETDEPTHMAP, xfrac, yfrac) +#endif + +#if (R_DRAWSPAN_PIPELINE & RDC_BILINEAR) + #define GETCOL(col) GETCOL_LINEAR(col) +#else + #define GETCOL(col) GETCOL_POINT(col) +#endif + +static void R_DRAWSPAN_FUNCNAME(draw_span_vars_t *dsvars) +{ +#if (R_DRAWSPAN_PIPELINE & (RDC_ROUNDED|RDC_BILINEAR)) + // drop back to point filtering if we're minifying + // 49152 = FRACUNIT * 0.75 + if ((D_abs(dsvars->xstep) > drawvars.mag_threshold) + || (D_abs(dsvars->ystep) > drawvars.mag_threshold)) + { + R_GetDrawSpanFunc(RDRAW_FILTER_POINT, + drawvars.filterz)(dsvars); + return; + } +#endif + { + unsigned count = dsvars->x2 - dsvars->x1 + 1; + fixed_t xfrac = dsvars->xfrac; + fixed_t yfrac = dsvars->yfrac; + const fixed_t xstep = dsvars->xstep; + const fixed_t ystep = dsvars->ystep; + const byte *source = dsvars->source; + const byte *colormap = dsvars->colormap; + SCREENTYPE *dest = drawvars.TOPLEFT + dsvars->y*drawvars.PITCH + dsvars->x1; +#if (R_DRAWSPAN_PIPELINE & (RDC_DITHERZ|RDC_BILINEAR)) + const int y = dsvars->y; + int x1 = dsvars->x1; +#endif +#if (R_DRAWSPAN_PIPELINE & RDC_DITHERZ) + const int fracz = (dsvars->z >> 12) & 255; + const byte *dither_colormaps[2] = { dsvars->colormap, dsvars->nextcolormap }; +#endif + + while (count) { +#if ((R_DRAWSPAN_PIPELINE_BITS != 8) && (R_DRAWSPAN_PIPELINE & RDC_BILINEAR)) + // truecolor bilinear filtered + *dest++ = GETCOL(0); + xfrac += xstep; + yfrac += ystep; + count--; + #if (R_DRAWSPAN_PIPELINE & RDC_DITHERZ) + x1--; + #endif +#elif (R_DRAWSPAN_PIPELINE & RDC_ROUNDED) + *dest++ = GETCOL(filter_getRoundedForSpan(xfrac, yfrac)); + xfrac += xstep; + yfrac += ystep; + count--; + #if (R_DRAWSPAN_PIPELINE & RDC_DITHERZ) + x1--; + #endif +#else + #if (R_DRAWSPAN_PIPELINE & RDC_BILINEAR) + // 8 bit bilinear + const fixed_t xtemp = ((xfrac >> 16) + (filter_getDitheredPixelLevel(x1, y, ((xfrac>>8)&0xff)))) & 63; + const fixed_t ytemp = ((yfrac >> 10) + 64*(filter_getDitheredPixelLevel(x1, y, ((yfrac>>8)&0xff)))) & 4032; + #else + const fixed_t xtemp = (xfrac >> 16) & 63; + const fixed_t ytemp = (yfrac >> 10) & 4032; + #endif + const fixed_t spot = xtemp | ytemp; + xfrac += xstep; + yfrac += ystep; + *dest++ = GETCOL(source[spot]); + count--; + #if (R_DRAWSPAN_PIPELINE & (RDC_DITHERZ|RDC_BILINEAR)) + x1--; + #endif +#endif + } + } +} + +#undef GETDEPTHMAP +#undef GETCOL_LINEAR +#undef GETCOL_POINT +#undef GETCOL +#undef PITCH +#undef TOPLEFT +#undef SCREENTYPE + +#undef R_DRAWSPAN_PIPELINE_BITS +#undef R_DRAWSPAN_PIPELINE +#undef R_DRAWSPAN_FUNCNAME diff --git a/src/r_filter.c b/src/r_filter.c new file mode 100644 index 0000000..4b44f14 --- /dev/null +++ b/src/r_filter.c @@ -0,0 +1,119 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + *-----------------------------------------------------------------------------*/ + +#include "doomtype.h" +#include "r_filter.h" + +#define DMR 16 +byte filter_ditherMatrix[DITHER_DIM][DITHER_DIM] = { + 0*DMR, 14*DMR, 3*DMR, 13*DMR, 11*DMR, 5*DMR, 8*DMR, 6*DMR, + 12*DMR, 2*DMR, 15*DMR, 1*DMR, 7*DMR, 9*DMR, 4*DMR, 10*DMR +}; + +byte filter_roundedUVMap[FILTER_UVDIM*FILTER_UVDIM]; +byte filter_roundedRowMap[4*16]; + +void R_FilterInit(void) { + int i,j,s,t; + + // scale2x takes the following source: + // A B C + // D E F + // G H I + // + // and doubles the size of E to produce: + // E0 E1 + // E2 E3 + // + // E0 = D == B && B != F && D != H ? D : E; + // E1 = B == F && B != D && F != H ? F : E; + // E2 = D == H && D != B && H != F ? D : E; + // E3 = H == F && D != H && B != F ? F : E; + // + // to make this comparison regimen faster, we encode source color + // equivalency into a single byte with the getCode() macro + // + // #define getCode(b,f,h,d) ( (b == f)<<0 | (f == h)<<1 | (h == d)<<2 | (d == b)<<3 ) + + // encode the scale2x conditionals into a lookup code + for (i=0; i<16; i++) { + // E0 = D == B && B != F && D != H ? D : E; // 10-0 => 1000 or 1010 => 8 or A + filter_roundedRowMap[0*16+i] = (i == 0x8 || i == 0xA) ? 0 : 1; + // E1 = B == F && B != D && F != H ? F : E; // 0-01 => 0101 or 0001 => 5 or 1 + filter_roundedRowMap[1*16+i] = (i == 0x5 || i == 0x1) ? 2 : 1; + // E2 = D == H && D != B && H != F ? D : E; // 010- => 0101 or 0100 => 5 or 4 + filter_roundedRowMap[2*16+i] = (i == 0x4 || i == 0x5) ? 0 : 1; + // E3 = H == F && D != H && B != F ? F : E; // -010 => 1010 or 0010 => A or 2 + filter_roundedRowMap[3*16+i] = (i == 0xA || i == 0x2) ? 2 : 1; + } + + // fill the uvMap. this will return: + // 0/\1 + // /4 \ + // \ / + // 2\/3 + // .. based on the uv coordinates + for (i=0; i=0 && t>=0) filter_roundedUVMap[i*FILTER_UVDIM+j] = (s+t > FILTER_UVDIM/2) ? 0 : 4; + else if (s>=0 && t<=0) filter_roundedUVMap[i*FILTER_UVDIM+j] = (s-t > FILTER_UVDIM/2) ? 2 : 4; + else if (s<=0 && t>=0) filter_roundedUVMap[i*FILTER_UVDIM+j] = (-s+t > FILTER_UVDIM/2) ? 1 : 4; + else if (s<=0 && t<=0) filter_roundedUVMap[i*FILTER_UVDIM+j] = (-s-t > FILTER_UVDIM/2) ? 3 : 4; + else filter_roundedUVMap[i*FILTER_UVDIM+j] = 4; + } + } +} + +byte *filter_getScale2xQuadColors(byte e, byte b, byte f, byte h, byte d) { + // A B C + // D E F + // G H I + // perform the Scale2x algorithm (quickly) to get the new quad to represent E + static byte quad[5]; + static byte rowColors[3]; + int code; + + rowColors[0] = d; + rowColors[1] = e; + rowColors[2] = f; + + #define getCode(b,f,h,d) ( (b == f)<<0 | (f == h)<<1 | (h == d)<<2 | (d == b)<<3 ) + + code = getCode(b,f,h,d); + quad[0] = rowColors[filter_roundedRowMap[0*16+code]]; + quad[1] = rowColors[filter_roundedRowMap[1*16+code]]; + quad[2] = rowColors[filter_roundedRowMap[2*16+code]]; + quad[3] = rowColors[filter_roundedRowMap[3*16+code]]; + quad[4] = e; + + return quad; +} diff --git a/src/r_filter.h b/src/r_filter.h new file mode 100644 index 0000000..8151eac --- /dev/null +++ b/src/r_filter.h @@ -0,0 +1,174 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + *-----------------------------------------------------------------------------*/ + +#ifndef R_FILTER_H +#define R_FILTER_H + +#define DITHER_DIM 4 + +extern byte filter_ditherMatrix[DITHER_DIM][DITHER_DIM]; +#define FILTER_UVBITS 6 +#define FILTER_UVDIM (1<> 8), which was empirically +// derived. the "-dcvars.yl" is apparently required to offset some minor +// shaking in coordinate y-axis and prevents dithering seams +#define FILTER_GETV(x,y,texV,nextRowTexV) \ + (filter_getDitheredPixelLevel(x, y, (((texV) - yl) >> 8)&0xff) ? ((nextRowTexV)>>FRACBITS) : ((texV)>>FRACBITS)) + +// Choose current column or next column to the right based on dither of the +// fractional texture U coord +#define filter_getDitheredForColumn(x, y, texV, nextRowTexV) \ + dither_sources[(filter_getDitheredPixelLevel(x, y, filter_fracu))][FILTER_GETV(x,y,texV,nextRowTexV)] + +#define filter_getRoundedForColumn(texV, nextRowTexV) \ + filter_getScale2xQuadColors( \ + source[ ((texV)>>FRACBITS) ], \ + source[ (MAX(0, ((texV)>>FRACBITS)-1)) ], \ + nextsource[ ((texV)>>FRACBITS) ], \ + source[ ((nextRowTexV)>>FRACBITS) ], \ + prevsource[ ((texV)>>FRACBITS) ] \ + ) \ + [ filter_roundedUVMap[ \ + ((filter_fracu>>(8-FILTER_UVBITS))<>8) & 0xff)>>(8-FILTER_UVBITS)) \ + ] ] + +#define filter_getRoundedForSpan(texU, texV) \ + filter_getScale2xQuadColors( \ + source[ (((texU)>>16)&0x3f) | (((texV)>>10)&0xfc0) ], \ + source[ (((texU)>>16)&0x3f) | ((((texV)-FRACUNIT)>>10)&0xfc0) ], \ + source[ ((((texU)+FRACUNIT)>>16)&0x3f) | (((texV)>>10)&0xfc0) ], \ + source[ (((texU)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0) ], \ + source[ ((((texU)-FRACUNIT)>>16)&0x3f) | (((texV)>>10)&0xfc0) ] \ + ) \ + [ filter_roundedUVMap[ \ + (((((texU)>>8) & 0xff)>>(8-FILTER_UVBITS))<>8) & 0xff)>>(8-FILTER_UVBITS)) \ + ] ] + +byte *filter_getScale2xQuadColors(byte e, byte b, byte f, byte h, byte d); + +// This is the horrendous macro version of the function commented out of +// r_filter.c. It does a bilinear blend on the four source texels for a +// given u and v +#define filter_getFilteredForColumn32(depthmap, texV, nextRowTexV) ( \ + VID_PAL32( depthmap(nextsource[(nextRowTexV)>>FRACBITS]), (filter_fracu*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL32( depthmap(source[(nextRowTexV)>>FRACBITS]), ((0xffff-filter_fracu)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL32( depthmap(source[(texV)>>FRACBITS]), ((0xffff-filter_fracu)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL32( depthmap(nextsource[(texV)>>FRACBITS]), (filter_fracu*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) )) + +// The 16 bit method of the filtering doesn't really maintain enough +// accuracy for discerning viewers, but the alternative requires converting +// from 32 bit, which is slow and requires both the intPalette and the +// shortPalette to be in memory at the same time. +#define filter_getFilteredForColumn16(depthmap, texV, nextRowTexV) ( \ + VID_PAL16( depthmap(nextsource[(nextRowTexV)>>FRACBITS]), (filter_fracu*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL16( depthmap(source[(nextRowTexV)>>FRACBITS]), ((0xffff-filter_fracu)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL16( depthmap(source[(texV)>>FRACBITS]), ((0xffff-filter_fracu)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL16( depthmap(nextsource[(texV)>>FRACBITS]), (filter_fracu*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) )) + +#define filter_getFilteredForColumn15(depthmap, texV, nextRowTexV) ( \ + VID_PAL15( depthmap(nextsource[(nextRowTexV)>>FRACBITS]), (filter_fracu*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL15( depthmap(source[(nextRowTexV)>>FRACBITS]), ((0xffff-filter_fracu)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL15( depthmap(source[(texV)>>FRACBITS]), ((0xffff-filter_fracu)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) ) + \ + VID_PAL15( depthmap(nextsource[(texV)>>FRACBITS]), (filter_fracu*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS) )) + +// Same as for column but wrapping at 64 +#define filter_getFilteredForSpan32(depthmap, texU, texV) ( \ + VID_PAL32( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL32( depthmap(source[ (((texU)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL32( depthmap(source[ (((texU)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL32( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS))) + +// Use 16 bit addition here since it's a little faster and the defects from +// such low-accuracy blending are less visible on spans +#define filter_getFilteredForSpan16(depthmap, texU, texV) ( \ + VID_PAL16( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL16( depthmap(source[ (((texU)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL16( depthmap(source[ (((texU)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL16( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS))) + +#define filter_getFilteredForSpan15(depthmap, texU, texV) ( \ + VID_PAL15( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL15( depthmap(source[ (((texU)>>16)&0x3f) | ((((texV)+FRACUNIT)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*((texV)&0xffff))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL15( depthmap(source[ (((texU)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)((0xffff-((texU)&0xffff))*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS)) + \ + VID_PAL15( depthmap(source[ ((((texU)+FRACUNIT)>>16)&0x3f) | (((texV)>>10)&0xfc0)]), (unsigned int)(((texU)&0xffff)*(0xffff-((texV)&0xffff)))>>(32-VID_COLORWEIGHTBITS))) + +// do red and blue at once for slight speedup + +#define GETBLENDED15_5050(col1, col2) \ + ((((col1&0x7c1f)+(col2&0x7c1f))>>1)&0x7c1f) | \ + ((((col1&0x03e0)+(col2&0x03e0))>>1)&0x03e0) + +#define GETBLENDED16_5050(col1, col2) \ + ((((col1&0xf81f)+(col2&0xf81f))>>1)&0xf81f) | \ + ((((col1&0x07e0)+(col2&0x07e0))>>1)&0x07e0) + +#define GETBLENDED32_5050(col1, col2) \ + ((((col1&0xff00ff)+(col2&0xff00ff))>>1)&0xff00ff) | \ + ((((col1&0x00ff00)+(col2&0x00ff00))>>1)&0x00ff00) + +#define GETBLENDED15_3268(col1, col2) \ + ((((col1&0x7c1f)*5+(col2&0x7c1f)*11)>>4)&0x7c1f) | \ + ((((col1&0x03e0)*5+(col2&0x03e0)*11)>>4)&0x03e0) + +#define GETBLENDED16_3268(col1, col2) \ + ((((col1&0xf81f)*5+(col2&0xf81f)*11)>>4)&0xf81f) | \ + ((((col1&0x07e0)*5+(col2&0x07e0)*11)>>4)&0x07e0) + +#define GETBLENDED32_3268(col1, col2) \ + ((((col1&0xff00ff)*5+(col2&0xff00ff)*11)>>4)&0xff00ff) | \ + ((((col1&0x00ff00)*5+(col2&0x00ff00)*11)>>4)&0x00ff00) + +#define GETBLENDED15_9406(col1, col2) \ + ((((col1&0x7c1f)*15+(col2&0x7c1f))>>4)&0x7c1f) | \ + ((((col1&0x03e0)*15+(col2&0x03e0))>>4)&0x03e0) + +#define GETBLENDED16_9406(col1, col2) \ + ((((col1&0xf81f)*15+(col2&0xf81f))>>4)&0xf81f) | \ + ((((col1&0x07e0)*15+(col2&0x07e0))>>4)&0x07e0) + +#define GETBLENDED32_9406(col1, col2) \ + ((((col1&0xff00ff)*15+(col2&0xff00ff))>>4)&0xff00ff) | \ + ((((col1&0x00ff00)*15+(col2&0x00ff00))>>4)&0x00ff00) + +#endif diff --git a/src/r_fps.c b/src/r_fps.c new file mode 100644 index 0000000..09b7bc0 --- /dev/null +++ b/src/r_fps.c @@ -0,0 +1,450 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Uncapped framerate stuff + * + *--------------------------------------------------------------------- + */ + +#include "doomstat.h" +#include "r_defs.h" +#include "r_state.h" +#include "p_spec.h" +#include "r_demo.h" +#include "r_fps.h" + +int movement_smooth = false; + +typedef enum +{ + INTERP_SectorFloor, + INTERP_SectorCeiling, + INTERP_Vertex, + INTERP_WallPanning, + INTERP_FloorPanning, + INTERP_CeilingPanning +} interpolation_type_e; + +typedef struct +{ + interpolation_type_e type; + void *address; +} interpolation_t; + +static int numinterpolations = 0; + +tic_vars_t tic_vars; + +view_vars_t original_view_vars; + +extern int realtic_clock_rate; +void D_Display(void); + +void R_InitInterpolation(void) +{ + tic_vars.msec = realtic_clock_rate * TICRATE / 100000.0f; +} + +typedef fixed_t fixed2_t[2]; +static fixed2_t *oldipos; +static fixed2_t *bakipos; +static interpolation_t *curipos; + +static boolean NoInterpolateView; +static boolean didInterp; +boolean WasRenderedInTryRunTics; + +void R_InterpolateView (player_t *player, fixed_t frac) +{ + if (movement_smooth) + { + if (NoInterpolateView) + { + NoInterpolateView = false; + original_view_vars.viewx = player->mo->x; + original_view_vars.viewy = player->mo->y; + original_view_vars.viewz = player->viewz; + + original_view_vars.viewangle = player->mo->angle + viewangleoffset; + } + + viewx = original_view_vars.viewx + FixedMul (frac, player->mo->x - original_view_vars.viewx); + viewy = original_view_vars.viewy + FixedMul (frac, player->mo->y - original_view_vars.viewy); + viewz = original_view_vars.viewz + FixedMul (frac, player->viewz - original_view_vars.viewz); + + viewangle = original_view_vars.viewangle + FixedMul (frac, R_SmoothPlaying_Get(player->mo->angle) + viewangleoffset - original_view_vars.viewangle); + } + else + { + viewx = player->mo->x; + viewy = player->mo->y; + viewz = player->viewz; + viewangle = R_SmoothPlaying_Get(player->mo->angle); + } +} + +void R_ResetViewInterpolation () +{ + NoInterpolateView = true; +} + +static void R_CopyInterpToOld (int i) +{ + switch (curipos[i].type) + { + case INTERP_SectorFloor: + oldipos[i][0] = ((sector_t*)curipos[i].address)->floorheight; + break; + case INTERP_SectorCeiling: + oldipos[i][0] = ((sector_t*)curipos[i].address)->ceilingheight; + break; + case INTERP_Vertex: + oldipos[i][0] = ((vertex_t*)curipos[i].address)->x; + oldipos[i][1] = ((vertex_t*)curipos[i].address)->y; + break; + case INTERP_WallPanning: + oldipos[i][0] = ((side_t*)curipos[i].address)->rowoffset; + oldipos[i][1] = ((side_t*)curipos[i].address)->textureoffset; + break; + case INTERP_FloorPanning: + oldipos[i][0] = ((sector_t*)curipos[i].address)->floor_xoffs; + oldipos[i][1] = ((sector_t*)curipos[i].address)->floor_yoffs; + break; + case INTERP_CeilingPanning: + oldipos[i][0] = ((sector_t*)curipos[i].address)->ceiling_xoffs; + oldipos[i][1] = ((sector_t*)curipos[i].address)->ceiling_yoffs; + break; + } +} + +static void R_CopyBakToInterp (int i) +{ + switch (curipos[i].type) + { + case INTERP_SectorFloor: + ((sector_t*)curipos[i].address)->floorheight = bakipos[i][0]; + break; + case INTERP_SectorCeiling: + ((sector_t*)curipos[i].address)->ceilingheight = bakipos[i][0]; + break; + case INTERP_Vertex: + ((vertex_t*)curipos[i].address)->x = bakipos[i][0]; + ((vertex_t*)curipos[i].address)->y = bakipos[i][1]; + break; + case INTERP_WallPanning: + ((side_t*)curipos[i].address)->rowoffset = bakipos[i][0]; + ((side_t*)curipos[i].address)->textureoffset = bakipos[i][1]; + break; + case INTERP_FloorPanning: + ((sector_t*)curipos[i].address)->floor_xoffs = bakipos[i][0]; + ((sector_t*)curipos[i].address)->floor_yoffs = bakipos[i][1]; + break; + case INTERP_CeilingPanning: + ((sector_t*)curipos[i].address)->ceiling_xoffs = bakipos[i][0]; + ((sector_t*)curipos[i].address)->ceiling_yoffs = bakipos[i][1]; + break; + } +} + +static void R_DoAnInterpolation (int i, fixed_t smoothratio) +{ + fixed_t pos; + fixed_t *adr1 = NULL; + fixed_t *adr2 = NULL; + + switch (curipos[i].type) + { + case INTERP_SectorFloor: + adr1 = &((sector_t*)curipos[i].address)->floorheight; + break; + case INTERP_SectorCeiling: + adr1 = &((sector_t*)curipos[i].address)->ceilingheight; + break; + case INTERP_Vertex: + adr1 = &((vertex_t*)curipos[i].address)->x; +//// adr2 = &((vertex_t*)curipos[i].Address)->y; + break; + case INTERP_WallPanning: + adr1 = &((side_t*)curipos[i].address)->rowoffset; + adr2 = &((side_t*)curipos[i].address)->textureoffset; + break; + case INTERP_FloorPanning: + adr1 = &((sector_t*)curipos[i].address)->floor_xoffs; + adr2 = &((sector_t*)curipos[i].address)->floor_yoffs; + break; + case INTERP_CeilingPanning: + adr1 = &((sector_t*)curipos[i].address)->ceiling_xoffs; + adr2 = &((sector_t*)curipos[i].address)->ceiling_yoffs; + break; + + default: + return; + } + + if (adr1) + { + pos = bakipos[i][0] = *adr1; + *adr1 = oldipos[i][0] + FixedMul (pos - oldipos[i][0], smoothratio); + } + + if (adr2) + { + pos = bakipos[i][1] = *adr2; + *adr2 = oldipos[i][1] + FixedMul (pos - oldipos[i][1], smoothratio); + } +} + +void R_UpdateInterpolations() +{ + int i; + if (!movement_smooth) + return; + for (i = numinterpolations-1; i >= 0; --i) + R_CopyInterpToOld (i); +} + +int interpolations_max = 0; + +static void R_SetInterpolation(interpolation_type_e type, void *posptr) +{ + int i; + if (!movement_smooth) + return; + + if (numinterpolations >= interpolations_max) { + interpolations_max = interpolations_max ? interpolations_max * 2 : 256; + + oldipos = (fixed2_t*)realloc(oldipos, sizeof(*oldipos) * interpolations_max); + bakipos = (fixed2_t*)realloc(bakipos, sizeof(*bakipos) * interpolations_max); + curipos = (interpolation_t*)realloc(curipos, sizeof(*curipos) * interpolations_max); + } + + for(i = numinterpolations-1; i >= 0; i--) + if (curipos[i].address == posptr && curipos[i].type == type) + return; + + curipos[numinterpolations].address = posptr; + curipos[numinterpolations].type = type; + R_CopyInterpToOld (numinterpolations); + numinterpolations++; +} + +static void R_StopInterpolation(interpolation_type_e type, void *posptr) +{ + int i; + + if (!movement_smooth) + return; + + for(i=numinterpolations-1; i>= 0; --i) + { + if (curipos[i].address == posptr && curipos[i].type == type) + { + numinterpolations--; + oldipos[i][0] = oldipos[numinterpolations][0]; + oldipos[i][1] = oldipos[numinterpolations][1]; + bakipos[i][0] = bakipos[numinterpolations][0]; + bakipos[i][1] = bakipos[numinterpolations][1]; + curipos[i] = curipos[numinterpolations]; + break; + } + } +} + +void R_StopAllInterpolations(void) +{ + int i; + + if (!movement_smooth) + return; + + for(i=numinterpolations-1; i>= 0; --i) + { + numinterpolations--; + oldipos[i][0] = oldipos[numinterpolations][0]; + oldipos[i][1] = oldipos[numinterpolations][1]; + bakipos[i][0] = bakipos[numinterpolations][0]; + bakipos[i][1] = bakipos[numinterpolations][1]; + curipos[i] = curipos[numinterpolations]; + } +} + +void R_DoInterpolations(fixed_t smoothratio) +{ + int i; + if (!movement_smooth) + return; + + if (smoothratio == FRACUNIT) + { + didInterp = false; + return; + } + + didInterp = true; + + for (i = numinterpolations-1; i >= 0; --i) + { + R_DoAnInterpolation (i, smoothratio); + } +} + +void R_RestoreInterpolations() +{ + int i; + + if (!movement_smooth) + return; + + if (didInterp) + { + didInterp = false; + for (i = numinterpolations-1; i >= 0; --i) + { + R_CopyBakToInterp (i); + } + } +} + +void R_ActivateSectorInterpolations() +{ + int i; + sector_t *sec; + + if (!movement_smooth) + return; + + for (i=0, sec = sectors ; ifloordata) + R_SetInterpolation (INTERP_SectorFloor, sec); + if (sec->ceilingdata) + R_SetInterpolation (INTERP_SectorCeiling, sec); + } +} + +static void R_InterpolationGetData(thinker_t *th, + interpolation_type_e *type1, interpolation_type_e *type2, + void **posptr1, void **posptr2) +{ + *posptr1 = NULL; + *posptr2 = NULL; + + if (th->function == T_MoveFloor) + { + *type1 = INTERP_SectorFloor; + *posptr1 = ((floormove_t *)th)->sector; + } + else + if (th->function == T_PlatRaise) + { + *type1 = INTERP_SectorFloor; + *posptr1 = ((plat_t *)th)->sector; + } + else + if (th->function == T_MoveCeiling) + { + *type1 = INTERP_SectorCeiling; + *posptr1 = ((ceiling_t *)th)->sector; + } + else + if (th->function == T_VerticalDoor) + { + *type1 = INTERP_SectorCeiling; + *posptr1 = ((vldoor_t *)th)->sector; + } + else + if (th->function == T_MoveElevator) + { + *type1 = INTERP_SectorFloor; + *posptr1 = ((elevator_t *)th)->sector; + *type2 = INTERP_SectorCeiling; + *posptr2 = ((elevator_t *)th)->sector; + } + else + if (th->function == T_Scroll) + { + switch (((scroll_t *)th)->type) + { + case sc_side: + *type1 = INTERP_WallPanning; + *posptr1 = sides + ((scroll_t *)th)->affectee; + break; + case sc_floor: + *type1 = INTERP_FloorPanning; + *posptr1 = sectors + ((scroll_t *)th)->affectee; + break; + case sc_ceiling: + *type1 = INTERP_CeilingPanning; + *posptr1 = sectors + ((scroll_t *)th)->affectee; + break; + default: ; + } + } +} + +void R_ActivateThinkerInterpolations(thinker_t *th) +{ + void *posptr1; + void *posptr2; + interpolation_type_e type1, type2; + + if (!movement_smooth) + return; + + R_InterpolationGetData(th, &type1, &type2, &posptr1, &posptr2); + + if(posptr1) + { + R_SetInterpolation (type1, posptr1); + + if(posptr2) + R_SetInterpolation (type2, posptr2); + } +} + +void R_StopInterpolationIfNeeded(thinker_t *th) +{ + void *posptr1; + void *posptr2; + interpolation_type_e type1, type2; + + if (!movement_smooth) + return; + + R_InterpolationGetData(th, &type1, &type2, &posptr1, &posptr2); + + if(posptr1) + { + R_StopInterpolation (type1, posptr1); + if(posptr2) + R_StopInterpolation (type2, posptr2); + } +} + diff --git a/src/r_fps.h b/src/r_fps.h new file mode 100644 index 0000000..bfbeab0 --- /dev/null +++ b/src/r_fps.h @@ -0,0 +1,76 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Uncapped framerate stuff + * + *--------------------------------------------------------------------- + */ + +#ifndef __R_FPS__ +#define __R_FPS__ + +#include "doomstat.h" + +extern int movement_smooth; + +typedef struct { + fixed_t viewx; + fixed_t viewy; + fixed_t viewz; + angle_t viewangle; + angle_t viewpitch; +} view_vars_t; + +extern view_vars_t original_view_vars; + +typedef struct { + unsigned int start; + unsigned int next; + unsigned int step; + fixed_t frac; + float msec; +} tic_vars_t; + +extern tic_vars_t tic_vars; + +void R_InitInterpolation(void); +void R_InterpolateView (player_t *player, fixed_t frac); + +extern boolean WasRenderedInTryRunTics; + +void R_ResetViewInterpolation (); +void R_UpdateInterpolations(); +void R_StopAllInterpolations(void); +void R_DoInterpolations(fixed_t smoothratio); +void R_RestoreInterpolations(); +void R_ActivateSectorInterpolations(); +void R_ActivateThinkerInterpolations(thinker_t *th); +void R_StopInterpolationIfNeeded(thinker_t *th); + +#endif diff --git a/src/r_main.c b/src/r_main.c new file mode 100644 index 0000000..cab5997 --- /dev/null +++ b/src/r_main.c @@ -0,0 +1,649 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Rendering main loop and setup functions, + * utility functions (BSP, geometry, trigonometry). + * See tables.c, too. + * + *-----------------------------------------------------------------------------*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef USE_SDL +#include "SDL.h" +#endif +#include "doomstat.h" +#include "d_net.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_things.h" +#include "r_plane.h" +#include "r_bsp.h" +#include "r_draw.h" +#include "m_bbox.h" +#include "r_sky.h" +#include "v_video.h" +#include "lprintf.h" +#include "st_stuff.h" +#include "i_main.h" +#include "i_system.h" +#include "g_game.h" +#include "r_demo.h" +#include "r_fps.h" + +// Fineangles in the SCREENWIDTH wide window. +#define FIELDOFVIEW 2048 + +// killough: viewangleoffset is a legacy from the pre-v1.2 days, when Doom +// had Left/Mid/Right viewing. +/-ANG90 offsets were placed here on each +// node, by d_net.c, to set up a L/M/R session. + +int viewangleoffset; +int validcount = 1; // increment every time a check is made +const lighttable_t *fixedcolormap; +int centerx, centery; +fixed_t centerxfrac, centeryfrac; +fixed_t viewheightfrac; //e6y: for correct clipping of things +fixed_t projection; +// proff 11/06/98: Added for high-res +fixed_t projectiony; +fixed_t viewx, viewy, viewz; +angle_t viewangle; +fixed_t viewcos, viewsin; +player_t *viewplayer; +extern lighttable_t **walllights; + +static mobj_t *oviewer; + +// +// precalculated math tables +// + +angle_t clipangle; + +// The viewangletox[viewangle + FINEANGLES/4] lookup +// maps the visible view angles to screen X coordinates, +// flattening the arc to a flat projection plane. +// There will be many angles mapped to the same X. + +int viewangletox[FINEANGLES/2]; + +// The xtoviewangleangle[] table maps a screen pixel +// to the lowest viewangle that maps back to x ranges +// from clipangle to -clipangle. + +angle_t xtoviewangle[MAX_SCREENWIDTH+1]; // killough 2/8/98 + +// killough 3/20/98: Support dynamic colormaps, e.g. deep water +// killough 4/4/98: support dynamic number of them as well + +int numcolormaps; +const lighttable_t *(*c_zlight)[LIGHTLEVELS][MAXLIGHTZ]; +const lighttable_t *(*zlight)[MAXLIGHTZ]; +const lighttable_t *fullcolormap; +const lighttable_t **colormaps; + +// killough 3/20/98, 4/4/98: end dynamic colormaps + +int extralight; // bumped light from gun blasts + +// +// R_PointOnSide +// Traverse BSP (sub) tree, +// check point against partition plane. +// Returns side 0 (front) or 1 (back). +// +// killough 5/2/98: reformatted +// + +PUREFUNC int R_PointOnSide(fixed_t x, fixed_t y, const node_t *node) +{ + if (!node->dx) + return x <= node->x ? node->dy > 0 : node->dy < 0; + + if (!node->dy) + return y <= node->y ? node->dx < 0 : node->dx > 0; + + x -= node->x; + y -= node->y; + + // Try to quickly decide by looking at sign bits. + if ((node->dy ^ node->dx ^ x ^ y) < 0) + return (node->dy ^ x) < 0; // (left is negative) + return FixedMul(y, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, x); +} + +// killough 5/2/98: reformatted + +PUREFUNC int R_PointOnSegSide(fixed_t x, fixed_t y, const seg_t *line) +{ + fixed_t lx = line->v1->x; + fixed_t ly = line->v1->y; + fixed_t ldx = line->v2->x - lx; + fixed_t ldy = line->v2->y - ly; + + if (!ldx) + return x <= lx ? ldy > 0 : ldy < 0; + + if (!ldy) + return y <= ly ? ldx < 0 : ldx > 0; + + x -= lx; + y -= ly; + + // Try to quickly decide by looking at sign bits. + if ((ldy ^ ldx ^ x ^ y) < 0) + return (ldy ^ x) < 0; // (left is negative) + return FixedMul(y, ldx>>FRACBITS) >= FixedMul(ldy>>FRACBITS, x); +} + +// +// R_PointToAngle +// 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 of tantoangle[] +// is to handle the case when x==y without additional +// checking. +// +// killough 5/2/98: reformatted, cleaned up + +#include + +angle_t R_PointToAngle(fixed_t x, fixed_t y) +{ + static fixed_t oldx, oldy; + static angle_t oldresult; + + x -= viewx; y -= viewy; + + if ( /* !render_precise && */ + // e6y: here is where "slime trails" can SOMETIMES occur +#ifdef GL_DOOM + (V_GetMode() != VID_MODEGL) && +#endif + (x < INT_MAX/4 && x > -INT_MAX/4 && y < INT_MAX/4 && y > -INT_MAX/4) + ) + { + // old R_PointToAngle + return (x || y) ? + x >= 0 ? + y >= 0 ? + (x > y) ? tantoangle[SlopeDiv(y,x)] : // octant 0 + ANG90-1-tantoangle[SlopeDiv(x,y)] : // octant 1 + x > (y = -y) ? 0-tantoangle[SlopeDiv(y,x)] : // octant 8 + ANG270+tantoangle[SlopeDiv(x,y)] : // octant 7 + y >= 0 ? (x = -x) > y ? ANG180-1-tantoangle[SlopeDiv(y,x)] : // octant 3 + ANG90 + tantoangle[SlopeDiv(x,y)] : // octant 2 + (x = -x) > (y = -y) ? ANG180+tantoangle[ SlopeDiv(y,x)] : // octant 4 + ANG270-1-tantoangle[SlopeDiv(x,y)] : // octant 5 + 0; + } + + // R_PointToAngleEx merged into R_PointToAngle + // e6y: The precision of the code above is abysmal so use the CRT atan2 function instead! + if (oldx != x || oldy != y) + { + oldx = x; + oldy = y; + oldresult = (int)(atan2(y, x) * ANG180/M_PI); + } + return oldresult; +} + +angle_t R_PointToAngle2(fixed_t viewx, fixed_t viewy, fixed_t x, fixed_t y) +{ + return (y -= viewy, (x -= viewx) || y) ? + x >= 0 ? + y >= 0 ? + (x > y) ? tantoangle[SlopeDiv(y,x)] : // octant 0 + ANG90-1-tantoangle[SlopeDiv(x,y)] : // octant 1 + x > (y = -y) ? 0-tantoangle[SlopeDiv(y,x)] : // octant 8 + ANG270+tantoangle[SlopeDiv(x,y)] : // octant 7 + y >= 0 ? (x = -x) > y ? ANG180-1-tantoangle[SlopeDiv(y,x)] : // octant 3 + ANG90 + tantoangle[SlopeDiv(x,y)] : // octant 2 + (x = -x) > (y = -y) ? ANG180+tantoangle[ SlopeDiv(y,x)] : // octant 4 + ANG270-1-tantoangle[SlopeDiv(x,y)] : // octant 5 + 0; +} + +// +// R_InitTextureMapping +// +// killough 5/2/98: reformatted + +static void R_InitTextureMapping (void) +{ + register int i,x; + fixed_t focallength; + + // Use tangent table to generate viewangletox: + // viewangletox will give the next greatest x + // after the view angle. + // + // Calc focallength + // so FIELDOFVIEW angles covers SCREENWIDTH. + + focallength = FixedDiv(centerxfrac, finetangent[FINEANGLES/4+FIELDOFVIEW/2]); + + for (i=0 ; i FRACUNIT*2) + t = -1; + else + if (finetangent[i] < -FRACUNIT*2) + t = viewwidth+1; + else + { + t = FixedMul(finetangent[i], focallength); + t = (centerxfrac - t + FRACUNIT-1) >> FRACBITS; + if (t < -1) + t = -1; + else + if (t > viewwidth+1) + t = viewwidth+1; + } + viewangletox[i] = t; + } + + // Scan viewangletox[] to generate xtoviewangle[]: + // xtoviewangle will give the smallest view angle + // that maps to x. + + for (x=0; x<=viewwidth; x++) + { + for (i=0; viewangletox[i] > x; i++) + ; + xtoviewangle[x] = (i<>= LIGHTSCALESHIFT)/DISTMAP; + + if (level < 0) + level = 0; + else + if (level >= NUMCOLORMAPS) + level = NUMCOLORMAPS-1; + + // killough 3/20/98: Initialize multiple colormaps + level *= 256; + for (t=0; t>ANGLETOFINESHIFT]); + distscale[i] = FixedDiv(FRACUNIT,cosadj); + } + +} + +// +// R_Init +// + +extern int screenblocks; + +void R_Init (void) +{ + // CPhipps - R_DrawColumn isn't constant anymore, so must + // initialise in code + // current column draw function + lprintf(LO_INFO, "\nR_LoadTrigTables: "); + R_LoadTrigTables(); + lprintf(LO_INFO, "\nR_InitData: "); + R_InitData(); + R_SetViewSize(screenblocks); + lprintf(LO_INFO, "\nR_Init: R_InitPlanes "); + R_InitPlanes(); + lprintf(LO_INFO, "R_InitLightTables "); + R_InitLightTables(); + lprintf(LO_INFO, "R_InitSkyMap "); + R_InitSkyMap(); + lprintf(LO_INFO, "R_InitTranslationsTables "); + R_InitTranslationTables(); + lprintf(LO_INFO, "R_InitPatches "); + R_InitPatches(); +} + +// +// R_PointInSubsector +// +// killough 5/2/98: reformatted, cleaned up + +subsector_t *R_PointInSubsector(fixed_t x, fixed_t y) +{ + int nodenum = numnodes-1; + + // special case for trivial maps (single subsector, no nodes) + if (numnodes == 0) + return subsectors; + + while (!(nodenum & NF_SUBSECTOR)) + nodenum = nodes[nodenum].children[R_PointOnSide(x, y, nodes+nodenum)]; + return &subsectors[nodenum & ~NF_SUBSECTOR]; +} + +// +// R_SetupFrame +// + +static void R_SetupFrame (player_t *player) +{ + int cm; + boolean NoInterpolate = paused || (menuactive && !demoplayback); + + viewplayer = player; + + if (player->mo != oviewer || NoInterpolate) + { + R_ResetViewInterpolation (); + oviewer = player->mo; + } + tic_vars.frac = I_GetTimeFrac (); + if (NoInterpolate) + tic_vars.frac = FRACUNIT; + R_InterpolateView (player, tic_vars.frac); + + extralight = player->extralight; + + viewsin = finesine[viewangle>>ANGLETOFINESHIFT]; + viewcos = finecosine[viewangle>>ANGLETOFINESHIFT]; + + R_DoInterpolations(tic_vars.frac); + + // killough 3/20/98, 4/4/98: select colormap based on player status + + if (player->mo->subsector->sector->heightsec != -1) + { + const sector_t *s = player->mo->subsector->sector->heightsec + sectors; + cm = viewz < s->floorheight ? s->bottommap : viewz > s->ceilingheight ? + s->topmap : s->midmap; + if (cm < 0 || cm > numcolormaps) + cm = 0; + } + else + cm = 0; + + fullcolormap = colormaps[cm]; + zlight = c_zlight[cm]; + + if (player->fixedcolormap) + { + fixedcolormap = fullcolormap // killough 3/20/98: use fullcolormap + + player->fixedcolormap*256*sizeof(lighttable_t); + } + else + fixedcolormap = 0; + + validcount++; +} + +int autodetect_hom = 0; // killough 2/7/98: HOM autodetection flag + +// +// R_ShowStats +// +int rendered_visplanes, rendered_segs, rendered_vissprites; +boolean rendering_stats; + +static void R_ShowStats(void) +{ +//e6y +#if USE_SDL + static unsigned int FPS_SavedTick = 0, FPS_FrameCount = 0; + unsigned int tick = SDL_GetTicks(); + FPS_FrameCount++; + if(tick >= FPS_SavedTick + 1000) + { + doom_printf((V_GetMode() == VID_MODEGL) + ?"Frame rate %d fps\nWalls %d, Flats %d, Sprites %d" + :"Frame rate %d fps\nSegs %d, Visplanes %d, Sprites %d", + 1000 * FPS_FrameCount / (tick - FPS_SavedTick), rendered_segs, + rendered_visplanes, rendered_vissprites); + FPS_SavedTick = tick; + FPS_FrameCount = 0; + } +#else + +#define KEEPTIMES 10 + static int keeptime[KEEPTIMES], showtime; + int now = I_GetTime(); + + if (now - showtime > 35) { + doom_printf((V_GetMode() == VID_MODEGL) + ?"Frame rate %d fps\nWalls %d, Flats %d, Sprites %d" + :"Frame rate %d fps\nSegs %d, Visplanes %d, Sprites %d", + (35*KEEPTIMES)/(now - keeptime[0]), rendered_segs, + rendered_visplanes, rendered_vissprites); + showtime = now; + } + memmove(keeptime, keeptime+1, sizeof(keeptime[0]) * (KEEPTIMES-1)); + keeptime[KEEPTIMES-1] = now; + +#endif //e6y +} + +// +// R_RenderView +// +void R_RenderPlayerView (player_t* player) +{ + R_SetupFrame (player); + + // Clear buffers. + R_ClearClipSegs (); + R_ClearDrawSegs (); + R_ClearPlanes (); + R_ClearSprites (); + + rendered_segs = rendered_visplanes = 0; + if (V_GetMode() == VID_MODEGL) + { +#ifdef GL_DOOM + // proff 11/99: clear buffers + gld_InitDrawScene(); + // proff 11/99: switch to perspective mode + gld_StartDrawScene(); +#endif + } else { + if (autodetect_hom) + { // killough 2/10/98: add flashing red HOM indicators + unsigned char color=(gametic % 20) < 9 ? 0xb0 : 0; + V_FillRect(0, viewwindowx, viewwindowy, viewwidth, viewheight, color); + R_DrawViewBorder(); + } + } + + // check for new console commands. +#ifdef HAVE_NET + NetUpdate (); +#endif + + // The head node is the last node output. + R_RenderBSPNode (numnodes-1); + R_ResetColumnBuffer(); + + // Check for new console commands. +#ifdef HAVE_NET + NetUpdate (); +#endif + + if (V_GetMode() != VID_MODEGL) + R_DrawPlanes (); + + // Check for new console commands. +#ifdef HAVE_NET + NetUpdate (); +#endif + + if (V_GetMode() != VID_MODEGL) { + R_DrawMasked (); + R_ResetColumnBuffer(); + } + + // Check for new console commands. +#ifdef HAVE_NET + NetUpdate (); +#endif + + if (V_GetMode() == VID_MODEGL) { +#ifdef GL_DOOM + // proff 11/99: draw the scene + gld_DrawScene(player); + // proff 11/99: finishing off + gld_EndDrawScene(); +#endif + } + + if (rendering_stats) R_ShowStats(); + + R_RestoreInterpolations(); +} diff --git a/src/r_main.h b/src/r_main.h new file mode 100644 index 0000000..89a36ee --- /dev/null +++ b/src/r_main.h @@ -0,0 +1,120 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Renderer main interface. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_MAIN__ +#define __R_MAIN__ + +#include "d_player.h" +#include "r_data.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +// +// POV related. +// + +extern fixed_t viewcos; +extern fixed_t viewsin; +extern int viewwidth; +extern int viewheight; +extern int viewwindowx; +extern int viewwindowy; +extern int centerx; +extern int centery; +extern fixed_t centerxfrac; +extern fixed_t centeryfrac; +extern fixed_t viewheightfrac; //e6y: for correct clipping of things +extern fixed_t projection; +// proff 11/06/98: Added for high-res +extern fixed_t projectiony; +extern int validcount; + +// +// Rendering stats +// + +extern int rendered_visplanes, rendered_segs, rendered_vissprites; +extern boolean rendering_stats; + +// +// Lighting LUT. +// Used for z-depth cuing per column/row, +// and other lighting effects (sector ambient, flash). +// + +// Lighting constants. + +#define LIGHTLEVELS 16 +#define LIGHTSEGSHIFT 4 +#define MAXLIGHTSCALE 48 +#define LIGHTSCALESHIFT 12 +#define MAXLIGHTZ 128 +#define LIGHTZSHIFT 20 + +// killough 3/20/98: Allow colormaps to be dynamic (e.g. underwater) +extern const lighttable_t *(*zlight)[MAXLIGHTZ]; +extern const lighttable_t *fullcolormap; +extern int numcolormaps; // killough 4/4/98: dynamic number of maps +extern const lighttable_t **colormaps; +// killough 3/20/98, 4/4/98: end dynamic colormaps + +extern int extralight; +extern const lighttable_t *fixedcolormap; + +// Number of diminishing brightness levels. +// There a 0-31, i.e. 32 LUT in the COLORMAP lump. + +#define NUMCOLORMAPS 32 + +// +// Utility functions. +// + +PUREFUNC int R_PointOnSide(fixed_t x, fixed_t y, const node_t *node); +PUREFUNC int R_PointOnSegSide(fixed_t x, fixed_t y, const seg_t *line); +angle_t R_PointToAngle(fixed_t x, fixed_t y); +angle_t R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); +subsector_t *R_PointInSubsector(fixed_t x, fixed_t y); + +// +// REFRESH - the actual rendering functions. +// + +void R_RenderPlayerView(player_t *player); // Called by G_Drawer. +void R_Init(void); // Called by startup code. +void R_SetViewSize(int blocks); // Called by M_Responder. +void R_ExecuteSetViewSize(void); // cph - called by D_Display to complete a view resize + +#endif diff --git a/src/r_patch.c b/src/r_patch.c new file mode 100644 index 0000000..e466fb2 --- /dev/null +++ b/src/r_patch.c @@ -0,0 +1,786 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2002 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + *-----------------------------------------------------------------------------*/ + +#include "z_zone.h" +#include "doomstat.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_sky.h" +#include "r_bsp.h" +#include "r_things.h" +#include "p_tick.h" +#include "i_system.h" +#include "r_draw.h" +#include "lprintf.h" +#include "r_patch.h" +#include + +// 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; + +// +// 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, height; // bounding box size + short leftoffset; // pixels to the left of origin + short topoffset; // pixels below the origin + int columnofs[8]; // only [width] used +} patch_t; + +//--------------------------------------------------------------------------- +// Re-engineered patch support +//--------------------------------------------------------------------------- +static rpatch_t *patches = 0; + +static rpatch_t *texture_composites = 0; + +//--------------------------------------------------------------------------- +void R_InitPatches(void) { + if (!patches) + { + patches = (rpatch_t*)malloc(numlumps * sizeof(rpatch_t)); + // clear out new patches to signal they're uninitialized + memset(patches, 0, sizeof(rpatch_t)*numlumps); + } + if (!texture_composites) + { + texture_composites = (rpatch_t*)malloc(numtextures * sizeof(rpatch_t)); + // clear out new patches to signal they're uninitialized + memset(texture_composites, 0, sizeof(rpatch_t)*numtextures); + } +} + +//--------------------------------------------------------------------------- +void R_FlushAllPatches(void) { + int i; + + if (patches) + { + for (i=0; i < numlumps; i++) + if (patches[i].locks > 0) + I_Error("R_FlushAllPatches: patch number %i still locked",i); + free(patches); + patches = NULL; + } + if (texture_composites) + { + for (i=0; iwidth; + R_UnlockPatchNum(lump); + return width; +} + +//--------------------------------------------------------------------------- +int R_NumPatchHeight(int lump) +{ + const rpatch_t *patch = R_CachePatchNum(lump); + int height = patch->height; + R_UnlockPatchNum(lump); + return height; +} + +//--------------------------------------------------------------------------- +static int getPatchIsNotTileable(const patch_t *patch) { + int x=0, numPosts, lastColumnDelta = 0; + const column_t *column; + int cornerCount = 0; + int hasAHole = 0; + + for (x=0; xwidth); x++) { + column = (const column_t *)((const byte *)patch + LONG(patch->columnofs[x])); + if (!x) lastColumnDelta = column->topdelta; + else if (lastColumnDelta != column->topdelta) hasAHole = 1; + + numPosts = 0; + while (column->topdelta != 0xff) { + // check to see if a corner pixel filled + if (x == 0 && column->topdelta == 0) cornerCount++; + else if (x == 0 && column->topdelta + column->length >= SHORT(patch->height)) cornerCount++; + else if (x == SHORT(patch->width)-1 && column->topdelta == 0) cornerCount++; + else if (x == SHORT(patch->width)-1 && column->topdelta + column->length >= SHORT(patch->height)) cornerCount++; + + if (numPosts++) hasAHole = 1; + column = (const column_t *)((const byte *)column + column->length + 4); + } + } + + if (cornerCount == 4) return 0; + return hasAHole; +} + +//--------------------------------------------------------------------------- +static int getIsSolidAtSpot(const column_t *column, int spot) { + if (!column) return 0; + while (column->topdelta != 0xff) { + if (spot < column->topdelta) return 0; + if ((spot >= column->topdelta) && (spot <= column->topdelta + column->length)) return 1; + column = (const column_t*)((const byte*)column + 3 + column->length + 1); + } + return 0; +} + +//--------------------------------------------------------------------------- +// Used to determine whether a column edge (top or bottom) should slope +// up or down for smoothed masked edges - POPE +//--------------------------------------------------------------------------- +static int getColumnEdgeSlope(const column_t *prevcolumn, const column_t *nextcolumn, int spot) { + int holeToLeft = !getIsSolidAtSpot(prevcolumn, spot); + int holeToRight = !getIsSolidAtSpot(nextcolumn, spot); + + if (holeToLeft && !holeToRight) return 1; + if (!holeToLeft && holeToRight) return -1; + return 0; +} + +//--------------------------------------------------------------------------- +static void createPatch(int id) { + rpatch_t *patch; + const int patchNum = id; + const patch_t *oldPatch = (const patch_t*)W_CacheLumpNum(patchNum); + const column_t *oldColumn, *oldPrevColumn, *oldNextColumn; + int x, y; + int pixelDataSize; + int columnsDataSize; + int postsDataSize; + int dataSize; + int *numPostsInColumn; + int numPostsTotal; + const unsigned char *oldColumnPixelData; + int numPostsUsedSoFar; + int edgeSlope; + +#ifdef RANGECHECK + if (id >= numlumps) + I_Error("createPatch: %i >= numlumps", id); +#endif + + patch = &patches[id]; + // proff - 2003-02-16 What about endianess? + patch->width = SHORT(oldPatch->width); + patch->widthmask = 0; + patch->height = SHORT(oldPatch->height); + patch->leftoffset = SHORT(oldPatch->leftoffset); + patch->topoffset = SHORT(oldPatch->topoffset); + patch->isNotTileable = getPatchIsNotTileable(oldPatch); + + // work out how much memory we need to allocate for this patch's data + pixelDataSize = (patch->width * patch->height + 4) & ~3; + columnsDataSize = sizeof(rcolumn_t) * patch->width; + + // count the number of posts in each column + numPostsInColumn = (int*)malloc(sizeof(int) * patch->width); + numPostsTotal = 0; + + for (x=0; xwidth; x++) { + oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); + numPostsInColumn[x] = 0; + while (oldColumn->topdelta != 0xff) { + numPostsInColumn[x]++; + numPostsTotal++; + oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); + } + } + + postsDataSize = numPostsTotal * sizeof(rpost_t); + + // allocate our data chunk + dataSize = pixelDataSize + columnsDataSize + postsDataSize; + patch->data = (unsigned char*)Z_Malloc(dataSize, PU_CACHE, (void **)&patch->data); + memset(patch->data, 0, dataSize); + + // set out pixel, column, and post pointers into our data array + patch->pixels = patch->data; + patch->columns = (rcolumn_t*)((unsigned char*)patch->pixels + pixelDataSize); + patch->posts = (rpost_t*)((unsigned char*)patch->columns + columnsDataSize); + + // sanity check that we've got all the memory allocated we need + assert((((byte*)patch->posts + numPostsTotal*sizeof(rpost_t)) - (byte*)patch->data) == dataSize); + + memset(patch->pixels, 0xff, (patch->width*patch->height)); + + // fill in the pixels, posts, and columns + numPostsUsedSoFar = 0; + for (x=0; xwidth; x++) { + + oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); + + if (patch->isNotTileable) { + // non-tiling + if (x == 0) oldPrevColumn = 0; + else oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x-1])); + if (x == patch->width-1) oldNextColumn = 0; + else oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x+1])); + } + else { + // tiling + int prevColumnIndex = x-1; + int nextColumnIndex = x+1; + while (prevColumnIndex < 0) prevColumnIndex += patch->width; + while (nextColumnIndex >= patch->width) nextColumnIndex -= patch->width; + oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[prevColumnIndex])); + oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[nextColumnIndex])); + } + + // setup the column's data + patch->columns[x].pixels = patch->pixels + (x*patch->height) + 0; + patch->columns[x].numPosts = numPostsInColumn[x]; + patch->columns[x].posts = patch->posts + numPostsUsedSoFar; + + while (oldColumn->topdelta != 0xff) { + // set up the post's data + patch->posts[numPostsUsedSoFar].topdelta = oldColumn->topdelta; + patch->posts[numPostsUsedSoFar].length = oldColumn->length; + patch->posts[numPostsUsedSoFar].slope = 0; + + edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta); + if (edgeSlope == 1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_TOP_UP; + else if (edgeSlope == -1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_TOP_DOWN; + + edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta+oldColumn->length); + if (edgeSlope == 1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_BOT_UP; + else if (edgeSlope == -1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_BOT_DOWN; + + // fill in the post's pixels + oldColumnPixelData = (const byte *)oldColumn + 3; + for (y=0; ylength; y++) { + patch->pixels[x * patch->height + oldColumn->topdelta + y] = oldColumnPixelData[y]; + } + + oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); + numPostsUsedSoFar++; + } + } + + if (1 || patch->isNotTileable) { + const rcolumn_t *column, *prevColumn; + + // copy the patch image down and to the right where there are + // holes to eliminate the black halo from bilinear filtering + for (x=0; xwidth; x++) { + //oldColumn = (const column_t *)((const byte *)oldPatch + oldPatch->columnofs[x]); + + column = R_GetPatchColumnClamped(patch, x); + prevColumn = R_GetPatchColumnClamped(patch, x-1); + + if (column->pixels[0] == 0xff) { + // force the first pixel (which is a hole), to use + // the color from the next solid spot in the column + for (y=0; yheight; y++) { + if (column->pixels[y] != 0xff) { + column->pixels[0] = column->pixels[y]; + break; + } + } + } + + // copy from above or to the left + for (y=1; yheight; y++) { + //if (getIsSolidAtSpot(oldColumn, y)) continue; + if (column->pixels[y] != 0xff) continue; + + // this pixel is a hole + + if (x && prevColumn->pixels[y-1] != 0xff) { + // copy the color from the left + column->pixels[y] = prevColumn->pixels[y]; + } + else { + // copy the color from above + column->pixels[y] = column->pixels[y-1]; + } + } + } + + // verify that the patch truly is non-rectangular since + // this determines tiling later on + } + + W_UnlockLumpNum(patchNum); + free(numPostsInColumn); +} + +typedef struct { + unsigned short patches; + unsigned short posts; + unsigned short posts_used; +} count_t; + +static void switchPosts(rpost_t *post1, rpost_t *post2) { + rpost_t dummy; + + dummy.topdelta = post1->topdelta; + dummy.length = post1->length; + dummy.slope = post1->slope; + post1->topdelta = post2->topdelta; + post1->length = post2->length; + post1->slope = post2->slope; + post2->topdelta = dummy.topdelta; + post2->length = dummy.length; + post2->slope = dummy.slope; +} + +static void removePostFromColumn(rcolumn_t *column, int post) { + int i; +#ifdef RANGECHECK + if (post >= column->numPosts) + I_Error("removePostFromColumn: invalid post index"); +#endif + if (post < column->numPosts) + for (i=post; i<(column->numPosts-1); i++) { + rpost_t *post1 = &column->posts[i]; + rpost_t *post2 = &column->posts[i+1]; + post1->topdelta = post2->topdelta; + post1->length = post2->length; + post1->slope = post2->slope; + } + column->numPosts--; +} + +//--------------------------------------------------------------------------- +static void createTextureCompositePatch(int id) { + rpatch_t *composite_patch; + texture_t *texture; + texpatch_t *texpatch; + int patchNum; + const patch_t *oldPatch; + const column_t *oldColumn, *oldPrevColumn, *oldNextColumn; + int i, x, y; + int oy, count; + int pixelDataSize; + int columnsDataSize; + int postsDataSize; + int dataSize; + int numPostsTotal; + const unsigned char *oldColumnPixelData; + int numPostsUsedSoFar; + int edgeSlope; + count_t *countsInColumn; + +#ifdef RANGECHECK + if (id >= numtextures) + I_Error("createTextureCompositePatch: %i >= numtextures", id); +#endif + + composite_patch = &texture_composites[id]; + + texture = textures[id]; + + composite_patch->width = texture->width; + composite_patch->height = texture->height; + composite_patch->widthmask = texture->widthmask; + composite_patch->leftoffset = 0; + composite_patch->topoffset = 0; + composite_patch->isNotTileable = 0; + + // work out how much memory we need to allocate for this patch's data + pixelDataSize = (composite_patch->width * composite_patch->height + 4) & ~3; + columnsDataSize = sizeof(rcolumn_t) * composite_patch->width; + + // count the number of posts in each column + countsInColumn = (count_t *)calloc(sizeof(count_t), composite_patch->width); + numPostsTotal = 0; + + for (i=0; ipatchcount; i++) { + texpatch = &texture->patches[i]; + patchNum = texpatch->patch; + oldPatch = (const patch_t*)W_CacheLumpNum(patchNum); + + for (x=0; xwidth); x++) { + int tx = texpatch->originx + x; + + if (tx < 0) + continue; + if (tx >= composite_patch->width) + break; + + countsInColumn[tx].patches++; + + oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); + while (oldColumn->topdelta != 0xff) { + countsInColumn[tx].posts++; + numPostsTotal++; + oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); + } + } + + W_UnlockLumpNum(patchNum); + } + + postsDataSize = numPostsTotal * sizeof(rpost_t); + + // allocate our data chunk + dataSize = pixelDataSize + columnsDataSize + postsDataSize; + composite_patch->data = (unsigned char*)Z_Malloc(dataSize, PU_STATIC, (void **)&composite_patch->data); + memset(composite_patch->data, 0, dataSize); + + // set out pixel, column, and post pointers into our data array + composite_patch->pixels = composite_patch->data; + composite_patch->columns = (rcolumn_t*)((unsigned char*)composite_patch->pixels + pixelDataSize); + composite_patch->posts = (rpost_t*)((unsigned char*)composite_patch->columns + columnsDataSize); + + // sanity check that we've got all the memory allocated we need + assert((((byte*)composite_patch->posts + numPostsTotal*sizeof(rpost_t)) - (byte*)composite_patch->data) == dataSize); + + memset(composite_patch->pixels, 0xff, (composite_patch->width*composite_patch->height)); + + numPostsUsedSoFar = 0; + + for (x=0; xwidth; x++) { + // setup the column's data + composite_patch->columns[x].pixels = composite_patch->pixels + (x*composite_patch->height); + composite_patch->columns[x].numPosts = countsInColumn[x].posts; + composite_patch->columns[x].posts = composite_patch->posts + numPostsUsedSoFar; + numPostsUsedSoFar += countsInColumn[x].posts; + } + + // fill in the pixels, posts, and columns + for (i=0; ipatchcount; i++) { + texpatch = &texture->patches[i]; + patchNum = texpatch->patch; + oldPatch = (const patch_t*)W_CacheLumpNum(patchNum); + + for (x=0; xwidth); x++) { + int tx = texpatch->originx + x; + + if (tx < 0) + continue; + if (tx >= composite_patch->width) + break; + + oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); + + { + // tiling + int prevColumnIndex = x-1; + int nextColumnIndex = x+1; + while (prevColumnIndex < 0) prevColumnIndex += SHORT(oldPatch->width); + while (nextColumnIndex >= SHORT(oldPatch->width)) nextColumnIndex -= SHORT(oldPatch->width); + oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[prevColumnIndex])); + oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[nextColumnIndex])); + } + + while (oldColumn->topdelta != 0xff) { + rpost_t *post = &composite_patch->columns[tx].posts[countsInColumn[tx].posts_used]; + oldColumnPixelData = (const byte *)oldColumn + 3; + oy = texpatch->originy; + count = oldColumn->length; + // the original renderer had several bugs which we reproduce here + if (countsInColumn[tx].patches > 1) { + // when there are multiple patches, then we need to handle the + // column differently + if (i == 0) { + // draw first patch at original position, it will be partly + // overdrawn below + for (y=0; ytopdelta + y; + if (ty < 0) + continue; + if (ty >= composite_patch->height) + break; + composite_patch->pixels[tx * composite_patch->height + ty] = oldColumnPixelData[y]; + } + } + // do the buggy clipping + if ((oy + oldColumn->topdelta) < 0) { + count += oy; + oy = 0; + } + } else { + // with a single patch only negative y origins are wrong + oy = 0; + } + // set up the post's data + post->topdelta = oldColumn->topdelta + oy; + post->length = count; + if ((post->topdelta + post->length) > composite_patch->height) { + if (post->topdelta > composite_patch->height) + post->length = 0; + else + post->length = composite_patch->height - post->topdelta; + } + if (post->topdelta < 0) { + if ((post->topdelta + post->length) <= 0) + post->length = 0; + else + post->length -= post->topdelta; + post->topdelta = 0; + } + post->slope = 0; + + edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta); + if (edgeSlope == 1) post->slope |= RDRAW_EDGESLOPE_TOP_UP; + else if (edgeSlope == -1) post->slope |= RDRAW_EDGESLOPE_TOP_DOWN; + + edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta+count); + if (edgeSlope == 1) post->slope |= RDRAW_EDGESLOPE_BOT_UP; + else if (edgeSlope == -1) post->slope |= RDRAW_EDGESLOPE_BOT_DOWN; + + // fill in the post's pixels + for (y=0; ytopdelta + y; + if (ty < 0) + continue; + if (ty >= composite_patch->height) + break; + composite_patch->pixels[tx * composite_patch->height + ty] = oldColumnPixelData[y]; + } + + oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); + countsInColumn[tx].posts_used++; + assert(countsInColumn[tx].posts_used <= countsInColumn[tx].posts); + } + } + + W_UnlockLumpNum(patchNum); + } + + for (x=0; xwidth; x++) { + rcolumn_t *column; + + if (countsInColumn[x].patches <= 1) + continue; + + // cleanup posts on multipatch columns + column = &composite_patch->columns[x]; + + i = 0; + while (i<(column->numPosts-1)) { + rpost_t *post1 = &column->posts[i]; + rpost_t *post2 = &column->posts[i+1]; + int length; + + if ((post2->topdelta - post1->topdelta) < 0) + switchPosts(post1, post2); + + if ((post1->topdelta + post1->length) >= post2->topdelta) { + length = (post1->length + post2->length) - ((post1->topdelta + post1->length) - post2->topdelta); + if (post1->length < length) { + post1->slope = post2->slope; + post1->length = length; + } + removePostFromColumn(column, i+1); + i = 0; + continue; + } + i++; + } + } + + if (1 || composite_patch->isNotTileable) { + const rcolumn_t *column, *prevColumn; + + // copy the patch image down and to the right where there are + // holes to eliminate the black halo from bilinear filtering + for (x=0; xwidth; x++) { + //oldColumn = (const column_t *)((const byte *)oldPatch + oldPatch->columnofs[x]); + + column = R_GetPatchColumnClamped(composite_patch, x); + prevColumn = R_GetPatchColumnClamped(composite_patch, x-1); + + if (column->pixels[0] == 0xff) { + // force the first pixel (which is a hole), to use + // the color from the next solid spot in the column + for (y=0; yheight; y++) { + if (column->pixels[y] != 0xff) { + column->pixels[0] = column->pixels[y]; + break; + } + } + } + + // copy from above or to the left + for (y=1; yheight; y++) { + //if (getIsSolidAtSpot(oldColumn, y)) continue; + if (column->pixels[y] != 0xff) continue; + + // this pixel is a hole + + if (x && prevColumn->pixels[y-1] != 0xff) { + // copy the color from the left + column->pixels[y] = prevColumn->pixels[y]; + } + else { + // copy the color from above + column->pixels[y] = column->pixels[y-1]; + } + } + } + + // verify that the patch truly is non-rectangular since + // this determines tiling later on + } + + free(countsInColumn); +} + +//--------------------------------------------------------------------------- +const rpatch_t *R_CachePatchNum(int id) { + const int locks = 1; + + if (!patches) + I_Error("R_CachePatchNum: Patches not initialized"); + +#ifdef RANGECHECK + if (id >= numlumps) + I_Error("createPatch: %i >= numlumps", id); +#endif + + if (!patches[id].data) + createPatch(id); + + /* cph - if wasn't locked but now is, tell z_zone to hold it */ + if (!patches[id].locks && locks) { + Z_ChangeTag(patches[id].data,PU_STATIC); +#ifdef TIMEDIAG + patches[id].locktic = gametic; +#endif + } + patches[id].locks += locks; + +#ifdef SIMPLECHECKS + if (!((patches[id].locks+1) & 0xf)) + lprintf(LO_DEBUG, "R_CachePatchNum: High lock on %8s (%d)\n", + lumpinfo[id].name, patches[id].locks); +#endif + + return &patches[id]; +} + +void R_UnlockPatchNum(int id) +{ + const int unlocks = 1; +#ifdef SIMPLECHECKS + if ((signed short)patches[id].locks < unlocks) + lprintf(LO_DEBUG, "R_UnlockPatchNum: Excess unlocks on %8s (%d-%d)\n", + lumpinfo[id].name, patches[id].locks, unlocks); +#endif + patches[id].locks -= unlocks; + /* cph - Note: must only tell z_zone to make purgeable if currently locked, + * else it might already have been purged + */ + if (unlocks && !patches[id].locks) + Z_ChangeTag(patches[id].data, PU_CACHE); +} + +//--------------------------------------------------------------------------- +const rpatch_t *R_CacheTextureCompositePatchNum(int id) { + const int locks = 1; + + if (!texture_composites) + I_Error("R_CacheTextureCompositePatchNum: Composite patches not initialized"); + +#ifdef RANGECHECK + if (id >= numtextures) + I_Error("createTextureCompositePatch: %i >= numtextures", id); +#endif + + if (!texture_composites[id].data) + createTextureCompositePatch(id); + + /* cph - if wasn't locked but now is, tell z_zone to hold it */ + if (!texture_composites[id].locks && locks) { + Z_ChangeTag(texture_composites[id].data,PU_STATIC); +#ifdef TIMEDIAG + texture_composites[id].locktic = gametic; +#endif + } + texture_composites[id].locks += locks; + +#ifdef SIMPLECHECKS + if (!((texture_composites[id].locks+1) & 0xf)) + lprintf(LO_DEBUG, "R_CacheTextureCompositePatchNum: High lock on %8s (%d)\n", + textures[id]->name, texture_composites[id].locks); +#endif + + return &texture_composites[id]; + +} + +void R_UnlockTextureCompositePatchNum(int id) +{ + const int unlocks = 1; +#ifdef SIMPLECHECKS + if ((signed short)texture_composites[id].locks < unlocks) + lprintf(LO_DEBUG, "R_UnlockTextureCompositePatchNum: Excess unlocks on %8s (%d-%d)\n", + textures[id]->name, texture_composites[id].locks, unlocks); +#endif + texture_composites[id].locks -= unlocks; + /* cph - Note: must only tell z_zone to make purgeable if currently locked, + * else it might already have been purged + */ + if (unlocks && !texture_composites[id].locks) + Z_ChangeTag(texture_composites[id].data, PU_CACHE); +} + +//--------------------------------------------------------------------------- +const rcolumn_t *R_GetPatchColumnWrapped(const rpatch_t *patch, int columnIndex) { + while (columnIndex < 0) columnIndex += patch->width; + columnIndex %= patch->width; + return &patch->columns[columnIndex]; +} + +//--------------------------------------------------------------------------- +const rcolumn_t *R_GetPatchColumnClamped(const rpatch_t *patch, int columnIndex) { + if (columnIndex < 0) columnIndex = 0; + if (columnIndex >= patch->width) columnIndex = patch->width-1; + return &patch->columns[columnIndex]; +} + +//--------------------------------------------------------------------------- +const rcolumn_t *R_GetPatchColumn(const rpatch_t *patch, int columnIndex) { + if (patch->isNotTileable) return R_GetPatchColumnClamped(patch, columnIndex); + else return R_GetPatchColumnWrapped(patch, columnIndex); +} + diff --git a/src/r_patch.h b/src/r_patch.h new file mode 100644 index 0000000..b0d1387 --- /dev/null +++ b/src/r_patch.h @@ -0,0 +1,111 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef R_PATCH_H +#define R_PATCH_H + +// Used to specify the sloping of the top and bottom of a column post +typedef enum { + RDRAW_EDGESLOPE_TOP_UP = (1<<0), + RDRAW_EDGESLOPE_TOP_DOWN = (1<<1), + RDRAW_EDGESLOPE_BOT_UP = (1<<2), + RDRAW_EDGESLOPE_BOT_DOWN = (1<<3), + RDRAW_EDGESLOPE_TOP_MASK = 0x3, + RDRAW_EDGESLOPE_BOT_MASK = 0xc, +} edgeslope_t; + +typedef struct { + int topdelta; + int length; + edgeslope_t slope; +} rpost_t; + +typedef struct { + int numPosts; + rpost_t *posts; + unsigned char *pixels; +} rcolumn_t; + +typedef struct { + int width; + int height; + unsigned widthmask; + + unsigned char isNotTileable; + + int leftoffset; + int topoffset; + + // this is the single malloc'ed/free'd array + // for this patch + unsigned char *data; + + // these are pointers into the data array + unsigned char *pixels; + rcolumn_t *columns; + rpost_t *posts; + +#ifdef TIMEDIAG + int locktic; +#endif + unsigned int locks; +} rpatch_t; + + +const rpatch_t *R_CachePatchNum(int id); +void R_UnlockPatchNum(int id); +#define R_CachePatchName(name) R_CachePatchNum(W_GetNumForName(name)) +#define R_UnlockPatchName(name) R_UnlockPatchNum(W_GetNumForName(name)) + +const rpatch_t *R_CacheTextureCompositePatchNum(int id); +void R_UnlockTextureCompositePatchNum(int id); + + +// Size query funcs +int R_NumPatchWidth(int lump) ; +int R_NumPatchHeight(int lump); +#define R_NamePatchWidth(name) R_NumPatchWidth(W_GetNumForName(name)) +#define R_NamePatchHeight(name) R_NumPatchHeight(W_GetNumForName(name)) + + +const rcolumn_t *R_GetPatchColumnWrapped(const rpatch_t *patch, int columnIndex); +const rcolumn_t *R_GetPatchColumnClamped(const rpatch_t *patch, int columnIndex); + + +// returns R_GetPatchColumnWrapped for square, non-holed textures +// and R_GetPatchColumnClamped otherwise +const rcolumn_t *R_GetPatchColumn(const rpatch_t *patch, int columnIndex); + + +void R_InitPatches(); +void R_FlushAllPatches(); + +#endif diff --git a/src/r_plane.c b/src/r_plane.c new file mode 100644 index 0000000..8eaa1e1 --- /dev/null +++ b/src/r_plane.c @@ -0,0 +1,468 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * 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. + * + * MAXVISPLANES is no longer a limit on the number of visplanes, + * but a limit on the number of hash slots; larger numbers mean + * better performance usually but after a point they are wasted, + * and memory and time overheads creep in. + * + * For more information on visplanes, see: + * + * http://classicgaming.com/doom/editing/ + * + * Lee Killough + * + *-----------------------------------------------------------------------------*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "z_zone.h" /* memory allocation wrappers -- killough */ + +#include "doomstat.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_draw.h" +#include "r_things.h" +#include "r_sky.h" +#include "r_plane.h" +#include "v_video.h" +#include "lprintf.h" + +#define MAXVISPLANES 128 /* must be a power of 2 */ + +static visplane_t *visplanes[MAXVISPLANES]; // killough +static visplane_t *freetail; // killough +static visplane_t **freehead = &freetail; // killough +visplane_t *floorplane, *ceilingplane; + +// killough -- hash function for visplanes +// Empirically verified to be fairly uniform: + +#define visplane_hash(picnum,lightlevel,height) \ + ((unsigned)((picnum)*3+(lightlevel)+(height)*7) & (MAXVISPLANES-1)) + +size_t maxopenings; +int *openings,*lastopening; // dropoff overflow + +// Clip values are the solid pixel bounding the range. +// floorclip starts out SCREENHEIGHT +// ceilingclip starts out -1 + +int floorclip[MAX_SCREENWIDTH], ceilingclip[MAX_SCREENWIDTH]; // dropoff overflow + +// spanstart holds the start of a plane span; initialized to 0 at start + +static int spanstart[MAX_SCREENHEIGHT]; // killough 2/8/98 + +// +// texture mapping +// + +static const lighttable_t **planezlight; +static fixed_t planeheight; + +// killough 2/8/98: make variables static + +static fixed_t basexscale, baseyscale; +static fixed_t cachedheight[MAX_SCREENHEIGHT]; +static fixed_t cacheddistance[MAX_SCREENHEIGHT]; +static fixed_t cachedxstep[MAX_SCREENHEIGHT]; +static fixed_t cachedystep[MAX_SCREENHEIGHT]; +static fixed_t xoffs,yoffs; // killough 2/28/98: flat offsets + +fixed_t yslope[MAX_SCREENHEIGHT], distscale[MAX_SCREENWIDTH]; + +// +// R_InitPlanes +// Only at game startup. +// +void R_InitPlanes (void) +{ +} + +// +// R_MapPlane +// +// Uses global vars: +// planeheight +// dsvars.source +// basexscale +// baseyscale +// viewx +// viewy +// xoffs +// yoffs +// +// BASIC PRIMITIVE +// + +static void R_MapPlane(int y, int x1, int x2, draw_span_vars_t *dsvars) +{ + angle_t angle; + fixed_t distance, length; + unsigned index; + +#ifdef RANGECHECK + if (x2 < x1 || x1<0 || x2>=viewwidth || (unsigned)y>(unsigned)viewheight) + I_Error ("R_MapPlane: %i, %i at %i",x1,x2,y); +#endif + + if (planeheight != cachedheight[y]) + { + cachedheight[y] = planeheight; + distance = cacheddistance[y] = FixedMul (planeheight, yslope[y]); + dsvars->xstep = cachedxstep[y] = FixedMul (distance,basexscale); + dsvars->ystep = cachedystep[y] = FixedMul (distance,baseyscale); + } + else + { + distance = cacheddistance[y]; + dsvars->xstep = cachedxstep[y]; + dsvars->ystep = cachedystep[y]; + } + + length = FixedMul (distance,distscale[x1]); + angle = (viewangle + xtoviewangle[x1])>>ANGLETOFINESHIFT; + + // killough 2/28/98: Add offsets + dsvars->xfrac = viewx + FixedMul(finecosine[angle], length) + xoffs; + dsvars->yfrac = -viewy - FixedMul(finesine[angle], length) + yoffs; + + if (drawvars.filterfloor == RDRAW_FILTER_LINEAR) { + dsvars->xfrac -= (FRACUNIT>>1); + dsvars->yfrac -= (FRACUNIT>>1); + } + + if (!(dsvars->colormap = fixedcolormap)) + { + dsvars->z = distance; + index = distance >> LIGHTZSHIFT; + if (index >= MAXLIGHTZ ) + index = MAXLIGHTZ-1; + dsvars->colormap = planezlight[index]; + dsvars->nextcolormap = planezlight[index+1 >= MAXLIGHTZ ? MAXLIGHTZ-1 : index+1]; + } + else + { + dsvars->z = 0; + } + + dsvars->y = y; + dsvars->x1 = x1; + dsvars->x2 = x2; + + if (V_GetMode() != VID_MODEGL) + R_DrawSpan(dsvars); +} + +// +// R_ClearPlanes +// At begining of frame. +// + +void R_ClearPlanes(void) +{ + int i; + + // opening / clipping determination + for (i=0 ; inext; + + lastopening = openings; + + // texture calculation + memset (cachedheight, 0, sizeof(cachedheight)); + + // scale will be unit scale at SCREENWIDTH/2 distance + basexscale = FixedDiv (viewsin,projection); + baseyscale = FixedDiv (viewcos,projection); +} + +// New function, by Lee Killough + +static visplane_t *new_visplane(unsigned hash) +{ + visplane_t *check = freetail; + if (!check) + check = calloc(1, sizeof *check); + else + if (!(freetail = freetail->next)) + freehead = &freetail; + check->next = visplanes[hash]; + visplanes[hash] = check; + return check; +} + +/* + * R_DupPlane + * + * cph 2003/04/18 - create duplicate of existing visplane and set initial range + */ +visplane_t *R_DupPlane(const visplane_t *pl, int start, int stop) +{ + unsigned hash = visplane_hash(pl->picnum, pl->lightlevel, pl->height); + visplane_t *new_pl = new_visplane(hash); + + new_pl->height = pl->height; + new_pl->picnum = pl->picnum; + new_pl->lightlevel = pl->lightlevel; + new_pl->xoffs = pl->xoffs; // killough 2/28/98 + new_pl->yoffs = pl->yoffs; + new_pl->minx = start; + new_pl->maxx = stop; + memset(new_pl->top, 0xff, sizeof new_pl->top); + return new_pl; +} +// +// R_FindPlane +// +// killough 2/28/98: Add offsets + +visplane_t *R_FindPlane(fixed_t height, int picnum, int lightlevel, + fixed_t xoffs, fixed_t yoffs) +{ + visplane_t *check; + unsigned hash; // killough + + if (picnum == skyflatnum || picnum & PL_SKYFLAT) + height = lightlevel = 0; // killough 7/19/98: most skies map together + + // New visplane algorithm uses hash table -- killough + hash = visplane_hash(picnum,lightlevel,height); + + for (check=visplanes[hash]; check; check=check->next) // killough + if (height == check->height && + picnum == check->picnum && + lightlevel == check->lightlevel && + xoffs == check->xoffs && // killough 2/28/98: Add offset checks + yoffs == check->yoffs) + return check; + + check = new_visplane(hash); // killough + + check->height = height; + check->picnum = picnum; + check->lightlevel = lightlevel; + check->minx = viewwidth; // Was SCREENWIDTH -- killough 11/98 + check->maxx = -1; + check->xoffs = xoffs; // killough 2/28/98: Save offsets + check->yoffs = yoffs; + + memset (check->top, 0xff, sizeof check->top); + + return check; +} + +// +// R_CheckPlane +// +visplane_t *R_CheckPlane(visplane_t *pl, int start, int stop) +{ + int intrl, intrh, unionl, unionh, x; + + if (start < pl->minx) + intrl = pl->minx, unionl = start; + else + unionl = pl->minx, intrl = start; + + if (stop > pl->maxx) + intrh = pl->maxx, unionh = stop; + else + unionh = pl->maxx, intrh = stop; + + for (x=intrl ; x <= intrh && pl->top[x] == 0xffffffffu; x++) // dropoff overflow + ; + + if (x > intrh) { /* Can use existing plane; extend range */ + pl->minx = unionl; pl->maxx = unionh; + return pl; + } else /* Cannot use existing plane; create a new one */ + return R_DupPlane(pl,start,stop); +} + +// +// R_MakeSpans +// + +static void R_MakeSpans(int x, unsigned int t1, unsigned int b1, + unsigned int t2, unsigned int b2, + draw_span_vars_t *dsvars) +{ + for (; t1 < t2 && t1 <= b1; t1++) + R_MapPlane(t1, spanstart[t1], x-1, dsvars); + for (; b1 > b2 && b1 >= t1; b1--) + R_MapPlane(b1, spanstart[b1] ,x-1, dsvars); + while (t2 < t1 && t2 <= b2) + spanstart[t2++] = x; + while (b2 > b1 && b2 >= t2) + spanstart[b2--] = x; +} + +// New function, by Lee Killough + +static void R_DoDrawPlane(visplane_t *pl) +{ + register int x; + draw_column_vars_t dcvars; + R_DrawColumn_f colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, drawvars.filterwall, drawvars.filterz); + + R_SetDefaultDrawColumnVars(&dcvars); + + if (pl->minx <= pl->maxx) { + if (pl->picnum == skyflatnum || pl->picnum & PL_SKYFLAT) { // sky flat + int texture; + const rpatch_t *tex_patch; + angle_t an, flip; + + // killough 10/98: allow skies to come from sidedefs. + // Allows scrolling and/or animated skies, as well as + // arbitrary multiple skies per level without having + // to use info lumps. + + an = viewangle; + + if (pl->picnum & PL_SKYFLAT) + { + // Sky Linedef + const line_t *l = &lines[pl->picnum & ~PL_SKYFLAT]; + + // Sky transferred from first sidedef + const side_t *s = *l->sidenum + sides; + + // Texture comes from upper texture of reference sidedef + texture = texturetranslation[s->toptexture]; + + // Horizontal offset is turned into an angle offset, + // to allow sky rotation as well as careful positioning. + // However, the offset is scaled very small, so that it + // allows a long-period of sky rotation. + + an += s->textureoffset; + + // Vertical offset allows careful sky positioning. + + dcvars.texturemid = s->rowoffset - 28*FRACUNIT; + + // We sometimes flip the picture horizontally. + // + // Doom always flipped the picture, so we make it optional, + // to make it easier to use the new feature, while to still + // allow old sky textures to be used. + + flip = l->special==272 ? 0u : ~0u; + } + else + { // Normal Doom sky, only one allowed per level + dcvars.texturemid = skytexturemid; // Default y-offset + texture = skytexture; // Default texture + flip = 0; // Doom flips it + } + + /* Sky is always drawn full bright, i.e. colormaps[0] is used. + * Because of this hack, sky is not affected by INVUL inverse mapping. + * Until Boom fixed this. Compat option added in MBF. */ + + if (comp[comp_skymap] || !(dcvars.colormap = fixedcolormap)) + dcvars.colormap = fullcolormap; // killough 3/20/98 + + dcvars.nextcolormap = dcvars.colormap; // for filtering -- POPE + + //dcvars.texturemid = skytexturemid; + dcvars.texheight = textureheight[skytexture]>>FRACBITS; // killough + // proff 09/21/98: Changed for high-res + dcvars.iscale = FRACUNIT*200/viewheight; + + tex_patch = R_CacheTextureCompositePatchNum(texture); + + // killough 10/98: Use sky scrolling offset, and possibly flip picture + for (x = pl->minx; (dcvars.x = x) <= pl->maxx; x++) + if ((dcvars.yl = pl->top[x]) != -1 && dcvars.yl <= (dcvars.yh = pl->bottom[x])) // dropoff overflow + { + dcvars.source = R_GetTextureColumn(tex_patch, ((an + xtoviewangle[x])^flip) >> ANGLETOSKYSHIFT); + dcvars.prevsource = R_GetTextureColumn(tex_patch, ((an + xtoviewangle[x-1])^flip) >> ANGLETOSKYSHIFT); + dcvars.nextsource = R_GetTextureColumn(tex_patch, ((an + xtoviewangle[x+1])^flip) >> ANGLETOSKYSHIFT); + colfunc(&dcvars); + } + + R_UnlockTextureCompositePatchNum(texture); + + } else { // regular flat + + int stop, light; + draw_span_vars_t dsvars; + + dsvars.source = W_CacheLumpNum(firstflat + flattranslation[pl->picnum]); + + xoffs = pl->xoffs; // killough 2/28/98: Add offsets + yoffs = pl->yoffs; + planeheight = D_abs(pl->height-viewz); + light = (pl->lightlevel >> LIGHTSEGSHIFT) + extralight; + + if (light >= LIGHTLEVELS) + light = LIGHTLEVELS-1; + + if (light < 0) + light = 0; + + stop = pl->maxx + 1; + planezlight = zlight[light]; + pl->top[pl->minx-1] = pl->top[stop] = 0xffffffffu; // dropoff overflow + + for (x = pl->minx ; x <= stop ; x++) + R_MakeSpans(x,pl->top[x-1],pl->bottom[x-1], + pl->top[x],pl->bottom[x], &dsvars); + + W_UnlockLumpNum(firstflat + flattranslation[pl->picnum]); + } + } +} + +// +// RDrawPlanes +// At the end of each frame. +// + +void R_DrawPlanes (void) +{ + visplane_t *pl; + int i; + for (i=0;inext, rendered_visplanes++) + R_DoDrawPlane(pl); +} diff --git a/src/r_plane.h b/src/r_plane.h new file mode 100644 index 0000000..7a2a515 --- /dev/null +++ b/src/r_plane.h @@ -0,0 +1,67 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Refresh, visplane stuff (floor, ceilings). + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_PLANE__ +#define __R_PLANE__ + +#include "r_data.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +/* killough 10/98: special mask indicates sky flat comes from sidedef */ +#define PL_SKYFLAT (0x80000000) + +/* Visplane related. */ +extern int *lastopening; // dropoff overflow + +extern int floorclip[], ceilingclip[]; // dropoff overflow +extern fixed_t yslope[], distscale[]; + +void R_InitPlanes(void); +void R_ClearPlanes(void); +void R_DrawPlanes (void); + +visplane_t *R_FindPlane( + fixed_t height, + int picnum, + int lightlevel, + fixed_t xoffs, /* killough 2/28/98: add x-y offsets */ + fixed_t yoffs + ); + +visplane_t *R_CheckPlane(visplane_t *pl, int start, int stop); +visplane_t *R_DupPlane(const visplane_t *pl, int start, int stop); + +#endif diff --git a/src/r_segs.c b/src/r_segs.c new file mode 100644 index 0000000..cb30b75 --- /dev/null +++ b/src/r_segs.c @@ -0,0 +1,854 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2004 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * All the clipping: columns, horizontal spans, sky columns. + * + *-----------------------------------------------------------------------------*/ +// +// 4/25/98, 5/2/98 killough: reformatted, beautified + +#include "doomstat.h" +#include "r_main.h" +#include "r_bsp.h" +#include "r_segs.h" +#include "r_plane.h" +#include "r_things.h" +#include "r_draw.h" +#include "w_wad.h" +#include "v_video.h" +#include "lprintf.h" + +// OPTIMIZE: closed two sided lines as single sided + +// killough 1/6/98: replaced globals with statics where appropriate + +// True if any of the segs textures might be visible. +static boolean segtextured; +static boolean markfloor; // False if the back side is the same plane. +static boolean markceiling; +static boolean maskedtexture; +static int toptexture; +static int bottomtexture; +static int midtexture; + +static fixed_t toptexheight, midtexheight, bottomtexheight; // cph + +angle_t rw_normalangle; // angle to line origin +int rw_angle1; +fixed_t rw_distance; + +// +// regular wall +// +static int rw_x; +static int rw_stopx; +static angle_t rw_centerangle; +static fixed_t rw_offset; +static fixed_t rw_scale; +static fixed_t rw_scalestep; +static fixed_t rw_midtexturemid; +static fixed_t rw_toptexturemid; +static fixed_t rw_bottomtexturemid; +static int rw_lightlevel; +static int worldtop; +static int worldbottom; +static int worldhigh; +static int worldlow; +static fixed_t pixhigh; +static fixed_t pixlow; +static fixed_t pixhighstep; +static fixed_t pixlowstep; +static fixed_t topfrac; +static fixed_t topstep; +static fixed_t bottomfrac; +static fixed_t bottomstep; +static int *maskedtexturecol; // dropoff overflow + +// +// R_ScaleFromGlobalAngle +// Returns the texture mapping scale +// for the current line (horizontal span) +// at the given angle. +// rw_distance must be calculated first. +// +// killough 5/2/98: reformatted, cleaned up +// CPhipps - moved here from r_main.c + +static fixed_t R_ScaleFromGlobalAngle(angle_t visangle) +{ + int anglea = ANG90 + (visangle-viewangle); + int angleb = ANG90 + (visangle-rw_normalangle); + int den = FixedMul(rw_distance, finesine[anglea>>ANGLETOFINESHIFT]); +// proff 11/06/98: Changed for high-res + fixed_t num = FixedMul(projectiony, finesine[angleb>>ANGLETOFINESHIFT]); + return den > num>>16 ? (num = FixedDiv(num, den)) > 64*FRACUNIT ? + 64*FRACUNIT : num < 256 ? 256 : num : 64*FRACUNIT; +} + +// +// R_RenderMaskedSegRange +// + +void R_RenderMaskedSegRange(drawseg_t *ds, int x1, int x2) +{ + int texnum; + sector_t tempsec; // killough 4/13/98 + const rpatch_t *patch; + R_DrawColumn_f colfunc; + draw_column_vars_t dcvars; + angle_t angle; + + R_SetDefaultDrawColumnVars(&dcvars); + + // Calculate light table. + // Use different light tables + // for horizontal / vertical / diagonal. Diagonal? + + curline = ds->curline; // OPTIMIZE: get rid of LIGHTSEGSHIFT globally + + // killough 4/11/98: draw translucent 2s normal textures + + colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, drawvars.filterwall, drawvars.filterz); + if (curline->linedef->tranlump >= 0 && general_translucency) + { + colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLUCENT, drawvars.filterwall, drawvars.filterz); + tranmap = main_tranmap; + if (curline->linedef->tranlump > 0) + tranmap = W_CacheLumpNum(curline->linedef->tranlump-1); + } + // killough 4/11/98: end translucent 2s normal code + + frontsector = curline->frontsector; + backsector = curline->backsector; + + // cph 2001/11/25 - middle textures did not animate in v1.2 + texnum = curline->sidedef->midtexture; + if (!comp[comp_maskedanim]) + texnum = texturetranslation[texnum]; + + // killough 4/13/98: get correct lightlevel for 2s normal textures + rw_lightlevel = R_FakeFlat(frontsector, &tempsec, NULL, NULL, false) ->lightlevel; + + maskedtexturecol = ds->maskedtexturecol; + + rw_scalestep = ds->scalestep; + spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; + mfloorclip = ds->sprbottomclip; + mceilingclip = ds->sprtopclip; + + // find positioning + if (curline->linedef->flags & ML_DONTPEGBOTTOM) + { + dcvars.texturemid = frontsector->floorheight > backsector->floorheight + ? frontsector->floorheight : backsector->floorheight; + dcvars.texturemid = dcvars.texturemid + textureheight[texnum] - viewz; + } + else + { + dcvars.texturemid =frontsector->ceilingheightceilingheight + ? frontsector->ceilingheight : backsector->ceilingheight; + dcvars.texturemid = dcvars.texturemid - viewz; + } + + dcvars.texturemid += curline->sidedef->rowoffset; + + if (fixedcolormap) { + dcvars.colormap = fixedcolormap; + dcvars.nextcolormap = dcvars.colormap; // for filtering -- POPE + } + + patch = R_CacheTextureCompositePatchNum(texnum); + + // draw the columns + for (dcvars.x = x1 ; dcvars.x <= x2 ; dcvars.x++, spryscale += rw_scalestep) + if (maskedtexturecol[dcvars.x] != INT_MAX) // dropoff overflow + { + // calculate texture offset - POPE + angle = (ds->rw_centerangle + xtoviewangle[dcvars.x]) >> ANGLETOFINESHIFT; + dcvars.texu = ds->rw_offset - FixedMul(finetangent[angle], ds->rw_distance); + if (drawvars.filterwall == RDRAW_FILTER_LINEAR) + dcvars.texu -= (FRACUNIT>>1); + + if (!fixedcolormap) + dcvars.z = spryscale; // for filtering -- POPE + dcvars.colormap = R_ColourMap(rw_lightlevel,spryscale); + dcvars.nextcolormap = R_ColourMap(rw_lightlevel+1,spryscale); // for filtering -- POPE + + // killough 3/2/98: + // + // This calculation used to overflow and cause crashes in Doom: + // + // sprtopscreen = centeryfrac - FixedMul(dcvars.texturemid, spryscale); + // + // This code fixes it, by using double-precision intermediate + // arithmetic and by skipping the drawing of 2s normals whose + // mapping to screen coordinates is totally out of range: + + { + int_64_t t = ((int_64_t) centeryfrac << FRACBITS) - + (int_64_t) dcvars.texturemid * spryscale; + if (t + (int_64_t) textureheight[texnum] * spryscale < 0 || + t > (int_64_t) MAX_SCREENHEIGHT << FRACBITS*2) + continue; // skip if the texture is out of screen's range + sprtopscreen = (long)(t >> FRACBITS); + } + + dcvars.iscale = 0xffffffffu / (unsigned) spryscale; + + // killough 1/25/98: here's where Medusa came in, because + // it implicitly assumed that the column was all one patch. + // Originally, Doom did not construct complete columns for + // multipatched textures, so there were no header or trailer + // bytes in the column referred to below, which explains + // the Medusa effect. The fix is to construct true columns + // when forming multipatched textures (see r_data.c). + + // draw the texture + R_DrawMaskedColumn( + patch, + colfunc, + &dcvars, + R_GetPatchColumnWrapped(patch, maskedtexturecol[dcvars.x]), + R_GetPatchColumnWrapped(patch, maskedtexturecol[dcvars.x]-1), + R_GetPatchColumnWrapped(patch, maskedtexturecol[dcvars.x]+1) + ); + + maskedtexturecol[dcvars.x] = INT_MAX; // dropoff overflow + } + + // Except for main_tranmap, mark others purgable at this point + if (curline->linedef->tranlump > 0 && general_translucency) + W_UnlockLumpNum(curline->linedef->tranlump-1); // cph - unlock it + + R_UnlockTextureCompositePatchNum(texnum); + + curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so R_ColourMap doesn't try using it for other things */ +} + +// +// R_RenderSegLoop +// Draws zero, one, or two textures (and possibly a masked texture) for walls. +// Can draw or mark the starting pixel of floor and ceiling textures. +// CALLED: CORE LOOPING ROUTINE. +// + +#define HEIGHTBITS 12 +#define HEIGHTUNIT (1<>HEIGHTBITS; + int yl = (topfrac+HEIGHTUNIT-1)>>HEIGHTBITS; + + // no space above wall? + int bottom,top = ceilingclip[rw_x]+1; + + if (yl < top) + yl = top; + + if (markceiling) + { + bottom = yl-1; + + if (bottom >= floorclip[rw_x]) + bottom = floorclip[rw_x]-1; + + if (top <= bottom) + { + ceilingplane->top[rw_x] = top; + ceilingplane->bottom[rw_x] = bottom; + } + // SoM: this should be set here + ceilingclip[rw_x] = bottom; + } + +// yh = bottomfrac>>HEIGHTBITS; + + bottom = floorclip[rw_x]-1; + if (yh > bottom) + yh = bottom; + + if (markfloor) + { + + top = yh < ceilingclip[rw_x] ? ceilingclip[rw_x] : yh; + + if (++top <= bottom) + { + floorplane->top[rw_x] = top; + floorplane->bottom[rw_x] = bottom; + } + // SoM: This should be set here to prevent overdraw + floorclip[rw_x] = top; + } + + // texturecolumn and lighting are independent of wall tiers + if (segtextured) + { + // calculate texture offset + angle_t angle =(rw_centerangle+xtoviewangle[rw_x])>>ANGLETOFINESHIFT; + + texturecolumn = rw_offset-FixedMul(finetangent[angle],rw_distance); + if (drawvars.filterwall == RDRAW_FILTER_LINEAR) + texturecolumn -= (FRACUNIT>>1); + dcvars.texu = texturecolumn; // for filtering -- POPE + texturecolumn >>= FRACBITS; + + dcvars.colormap = R_ColourMap(rw_lightlevel,rw_scale); + dcvars.nextcolormap = R_ColourMap(rw_lightlevel+1,rw_scale); // for filtering -- POPE + dcvars.z = rw_scale; // for filtering -- POPE + + dcvars.x = rw_x; + dcvars.iscale = 0xffffffffu / (unsigned)rw_scale; + } + + // draw the wall tiers + if (midtexture) + { + + dcvars.yl = yl; // single sided line + dcvars.yh = yh; + dcvars.texturemid = rw_midtexturemid; + tex_patch = R_CacheTextureCompositePatchNum(midtexture); + dcvars.source = R_GetTextureColumn(tex_patch, texturecolumn); + dcvars.prevsource = R_GetTextureColumn(tex_patch, texturecolumn-1); + dcvars.nextsource = R_GetTextureColumn(tex_patch, texturecolumn+1); + dcvars.texheight = midtexheight; + colfunc (&dcvars); + R_UnlockTextureCompositePatchNum(midtexture); + tex_patch = NULL; + ceilingclip[rw_x] = viewheight; + floorclip[rw_x] = -1; + } + else + { + + // two sided line + if (toptexture) + { + // top wall + int mid = pixhigh>>HEIGHTBITS; + pixhigh += pixhighstep; + + if (mid >= floorclip[rw_x]) + mid = floorclip[rw_x]-1; + + if (mid >= yl) + { + dcvars.yl = yl; + dcvars.yh = mid; + dcvars.texturemid = rw_toptexturemid; + tex_patch = R_CacheTextureCompositePatchNum(toptexture); + dcvars.source = R_GetTextureColumn(tex_patch,texturecolumn); + dcvars.prevsource = R_GetTextureColumn(tex_patch,texturecolumn-1); + dcvars.nextsource = R_GetTextureColumn(tex_patch,texturecolumn+1); + dcvars.texheight = toptexheight; + colfunc (&dcvars); + R_UnlockTextureCompositePatchNum(toptexture); + tex_patch = NULL; + ceilingclip[rw_x] = mid; + } + else + ceilingclip[rw_x] = yl-1; + } + else // no top wall + { + + if (markceiling) + ceilingclip[rw_x] = yl-1; + } + + if (bottomtexture) // bottom wall + { + int mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS; + pixlow += pixlowstep; + + // no space above wall? + if (mid <= ceilingclip[rw_x]) + mid = ceilingclip[rw_x]+1; + + if (mid <= yh) + { + dcvars.yl = mid; + dcvars.yh = yh; + dcvars.texturemid = rw_bottomtexturemid; + tex_patch = R_CacheTextureCompositePatchNum(bottomtexture); + dcvars.source = R_GetTextureColumn(tex_patch, texturecolumn); + dcvars.prevsource = R_GetTextureColumn(tex_patch, texturecolumn-1); + dcvars.nextsource = R_GetTextureColumn(tex_patch, texturecolumn+1); + dcvars.texheight = bottomtexheight; + colfunc (&dcvars); + R_UnlockTextureCompositePatchNum(bottomtexture); + tex_patch = NULL; + floorclip[rw_x] = mid; + } + else + floorclip[rw_x] = yh+1; + } + else // no bottom wall + { + if (markfloor) + floorclip[rw_x] = yh+1; + } + + // cph - if we completely blocked further sight through this column, + // add this info to the solid columns array for r_bsp.c + if ((markceiling || markfloor) && + (floorclip[rw_x] <= ceilingclip[rw_x] + 1)) { + solidcol[rw_x] = 1; didsolidcol = 1; + } + + // save texturecol for backdrawing of masked mid texture + if (maskedtexture) + maskedtexturecol[rw_x] = texturecolumn; + } + + rw_scale += rw_scalestep; + topfrac += topstep; + bottomfrac += bottomstep; + } +} + +// killough 5/2/98: move from r_main.c, made static, simplified + +static fixed_t R_PointToDist(fixed_t x, fixed_t y) +{ + fixed_t dx = D_abs(x - viewx); + fixed_t dy = D_abs(y - viewy); + + if (dy > dx) + { + fixed_t t = dx; + dx = dy; + dy = t; + } + + return FixedDiv(dx, finesine[(tantoangle[FixedDiv(dy,dx) >> DBITS] + + ANG90) >> ANGLETOFINESHIFT]); +} + +// +// R_StoreWallRange +// A wall segment will be drawn +// between start and stop pixels (inclusive). +// +void R_StoreWallRange(const int start, const int stop) +{ + fixed_t hyp; + angle_t offsetangle; + + if (ds_p == drawsegs+maxdrawsegs) // killough 1/98 -- fix 2s line HOM + { + unsigned pos = ds_p - drawsegs; // jff 8/9/98 fix from ZDOOM1.14a + unsigned newmax = maxdrawsegs ? maxdrawsegs*2 : 128; // killough + drawsegs = realloc(drawsegs,newmax*sizeof(*drawsegs)); + ds_p = drawsegs + pos; // jff 8/9/98 fix from ZDOOM1.14a + maxdrawsegs = newmax; + } + + if(curline->miniseg == false) // figgi -- skip minisegs + curline->linedef->flags |= ML_MAPPED; + +#ifdef GL_DOOM + if (V_GetMode() == VID_MODEGL) + { + // proff 11/99: the rest of the calculations is not needed for OpenGL + ds_p++->curline = curline; + gld_AddWall(curline); + + return; + } +#endif + + +#ifdef RANGECHECK + if (start >=viewwidth || start > stop) + I_Error ("Bad R_RenderWallRange: %i to %i", start , stop); +#endif + + sidedef = curline->sidedef; + linedef = curline->linedef; + + // mark the segment as visible for auto map + linedef->flags |= ML_MAPPED; + + // calculate rw_distance for scale calculation + rw_normalangle = curline->angle + ANG90; + + offsetangle = rw_normalangle-rw_angle1; + + if (D_abs(offsetangle) > ANG90) + offsetangle = ANG90; + + hyp = (viewx==curline->v1->x && viewy==curline->v1->y)? + 0 : R_PointToDist (curline->v1->x, curline->v1->y); + rw_distance = FixedMul(hyp, finecosine[offsetangle>>ANGLETOFINESHIFT]); + + ds_p->x1 = rw_x = start; + ds_p->x2 = stop; + ds_p->curline = curline; + rw_stopx = stop+1; + + { // killough 1/6/98, 2/1/98: remove limit on openings + extern int *openings; // dropoff overflow + extern size_t maxopenings; + size_t pos = lastopening - openings; + size_t need = (rw_stopx - start)*4 + pos; + if (need > maxopenings) + { + drawseg_t *ds; //jff 8/9/98 needed for fix from ZDoom + int *oldopenings = openings; // dropoff overflow + int *oldlast = lastopening; // dropoff overflow + + do + maxopenings = maxopenings ? maxopenings*2 : 16384; + while (need > maxopenings); + openings = realloc(openings, maxopenings * sizeof(*openings)); + lastopening = openings + pos; + + // jff 8/9/98 borrowed fix for openings from ZDOOM1.14 + // [RH] We also need to adjust the openings pointers that + // were already stored in drawsegs. + for (ds = drawsegs; ds < ds_p; ds++) + { +#define ADJUST(p) if (ds->p + ds->x1 >= oldopenings && ds->p + ds->x1 <= oldlast)\ + ds->p = ds->p - oldopenings + openings; + ADJUST (maskedtexturecol); + ADJUST (sprtopclip); + ADJUST (sprbottomclip); + } +#undef ADJUST + } + } // killough: end of code to remove limits on openings + + // calculate scale at both ends and step + + ds_p->scale1 = rw_scale = + R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]); + + if (stop > start) + { + ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]); + ds_p->scalestep = rw_scalestep = (ds_p->scale2-rw_scale) / (stop-start); + } + else + ds_p->scale2 = ds_p->scale1; + + // calculate texture boundaries + // and decide if floor / ceiling marks are needed + + worldtop = frontsector->ceilingheight - viewz; + worldbottom = frontsector->floorheight - viewz; + + midtexture = toptexture = bottomtexture = maskedtexture = 0; + ds_p->maskedtexturecol = NULL; + + if (!backsector) + { + // single sided line + midtexture = texturetranslation[sidedef->midtexture]; + midtexheight = (linedef->r_flags & RF_MID_TILE) ? 0 : textureheight[midtexture] >> FRACBITS; + + // a single sided line is terminal, so it must mark ends + markfloor = markceiling = true; + + if (linedef->flags & ML_DONTPEGBOTTOM) + { // bottom of texture at bottom + fixed_t vtop = frontsector->floorheight + + textureheight[sidedef->midtexture]; + rw_midtexturemid = vtop - viewz; + } + else // top of texture at top + rw_midtexturemid = worldtop; + + rw_midtexturemid += FixedMod(sidedef->rowoffset, textureheight[midtexture]); + + ds_p->silhouette = SIL_BOTH; + ds_p->sprtopclip = screenheightarray; + ds_p->sprbottomclip = negonearray; + ds_p->bsilheight = INT_MAX; + ds_p->tsilheight = INT_MIN; + } + else // two sided line + { + ds_p->sprtopclip = ds_p->sprbottomclip = NULL; + ds_p->silhouette = 0; + + if (linedef->r_flags & RF_CLOSED) { /* cph - closed 2S line e.g. door */ + // cph - killough's (outdated) comment follows - this deals with both + // "automap fixes", his and mine + // killough 1/17/98: this test is required if the fix + // for the automap bug (r_bsp.c) is used, or else some + // sprites will be displayed behind closed doors. That + // fix prevents lines behind closed doors with dropoffs + // from being displayed on the automap. + + ds_p->silhouette = SIL_BOTH; + ds_p->sprbottomclip = negonearray; + ds_p->bsilheight = INT_MAX; + ds_p->sprtopclip = screenheightarray; + ds_p->tsilheight = INT_MIN; + + } else { /* not solid - old code */ + + if (frontsector->floorheight > backsector->floorheight) + { + ds_p->silhouette = SIL_BOTTOM; + ds_p->bsilheight = frontsector->floorheight; + } + else + if (backsector->floorheight > viewz) + { + ds_p->silhouette = SIL_BOTTOM; + ds_p->bsilheight = INT_MAX; + } + + if (frontsector->ceilingheight < backsector->ceilingheight) + { + ds_p->silhouette |= SIL_TOP; + ds_p->tsilheight = frontsector->ceilingheight; + } + else + if (backsector->ceilingheight < viewz) + { + ds_p->silhouette |= SIL_TOP; + ds_p->tsilheight = INT_MIN; + } + } + + worldhigh = backsector->ceilingheight - viewz; + worldlow = backsector->floorheight - viewz; + + // hack to allow height changes in outdoor areas + if (frontsector->ceilingpic == skyflatnum + && backsector->ceilingpic == skyflatnum) + worldtop = worldhigh; + + markfloor = worldlow != worldbottom + || backsector->floorpic != frontsector->floorpic + || backsector->lightlevel != frontsector->lightlevel + + // killough 3/7/98: Add checks for (x,y) offsets + || backsector->floor_xoffs != frontsector->floor_xoffs + || backsector->floor_yoffs != frontsector->floor_yoffs + + // killough 4/15/98: prevent 2s normals + // from bleeding through deep water + || frontsector->heightsec != -1 + + // killough 4/17/98: draw floors if different light levels + || backsector->floorlightsec != frontsector->floorlightsec + ; + + markceiling = worldhigh != worldtop + || backsector->ceilingpic != frontsector->ceilingpic + || backsector->lightlevel != frontsector->lightlevel + + // killough 3/7/98: Add checks for (x,y) offsets + || backsector->ceiling_xoffs != frontsector->ceiling_xoffs + || backsector->ceiling_yoffs != frontsector->ceiling_yoffs + + // killough 4/15/98: prevent 2s normals + // from bleeding through fake ceilings + || (frontsector->heightsec != -1 && + frontsector->ceilingpic!=skyflatnum) + + // killough 4/17/98: draw ceilings if different light levels + || backsector->ceilinglightsec != frontsector->ceilinglightsec + ; + + if (backsector->ceilingheight <= frontsector->floorheight + || backsector->floorheight >= frontsector->ceilingheight) + markceiling = markfloor = true; // closed door + + if (worldhigh < worldtop) // top texture + { + toptexture = texturetranslation[sidedef->toptexture]; + toptexheight = (linedef->r_flags & RF_TOP_TILE) ? 0 : textureheight[toptexture] >> FRACBITS; + rw_toptexturemid = linedef->flags & ML_DONTPEGTOP ? worldtop : + backsector->ceilingheight+textureheight[sidedef->toptexture]-viewz; + rw_toptexturemid += FixedMod(sidedef->rowoffset, textureheight[toptexture]); + } + + if (worldlow > worldbottom) // bottom texture + { + bottomtexture = texturetranslation[sidedef->bottomtexture]; + bottomtexheight = (linedef->r_flags & RF_BOT_TILE) ? 0 : textureheight[bottomtexture] >> FRACBITS; + rw_bottomtexturemid = linedef->flags & ML_DONTPEGBOTTOM ? worldtop : + worldlow; + rw_bottomtexturemid += FixedMod(sidedef->rowoffset, textureheight[bottomtexture]); + } + + // allocate space for masked texture tables + if (sidedef->midtexture) // masked midtexture + { + maskedtexture = true; + ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x; + lastopening += rw_stopx - rw_x; + } + } + + // calculate rw_offset (only needed for textured lines) + segtextured = midtexture | toptexture | bottomtexture | maskedtexture; + + if (segtextured) + { + rw_offset = FixedMul (hyp, -finesine[offsetangle >>ANGLETOFINESHIFT]); + + rw_offset += sidedef->textureoffset + curline->offset; + + rw_centerangle = ANG90 + viewangle - rw_normalangle; + + rw_lightlevel = frontsector->lightlevel; + } + + // Remember the vars used to determine fractional U texture + // coords for later - POPE + ds_p->rw_offset = rw_offset; + ds_p->rw_distance = rw_distance; + ds_p->rw_centerangle = rw_centerangle; + + // if a floor / ceiling plane is on the wrong side of the view + // plane, it is definitely invisible and doesn't need to be marked. + + // killough 3/7/98: add deep water check + if (frontsector->heightsec == -1) + { + if (frontsector->floorheight >= viewz) // above view plane + markfloor = false; + if (frontsector->ceilingheight <= viewz && + frontsector->ceilingpic != skyflatnum) // below view plane + markceiling = false; + } + + // calculate incremental stepping values for texture edges + worldtop >>= 4; + worldbottom >>= 4; + + topstep = -FixedMul (rw_scalestep, worldtop); + topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale); + + bottomstep = -FixedMul (rw_scalestep,worldbottom); + bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale); + + if (backsector) + { + worldhigh >>= 4; + worldlow >>= 4; + + if (worldhigh < worldtop) + { + pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale); + pixhighstep = -FixedMul (rw_scalestep,worldhigh); + } + if (worldlow > worldbottom) + { + pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale); + pixlowstep = -FixedMul (rw_scalestep,worldlow); + } + } + + // render it + if (markceiling) { + if (ceilingplane) // killough 4/11/98: add NULL ptr checks + ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1); + else + markceiling = 0; + } + + if (markfloor) { + if (floorplane) // killough 4/11/98: add NULL ptr checks + /* cph 2003/04/18 - ceilingplane and floorplane might be the same + * visplane (e.g. if both skies); R_CheckPlane doesn't know about + * modifications to the plane that might happen in parallel with the check + * being made, so we have to override it and split them anyway if that is + * a possibility, otherwise the floor marking would overwrite the ceiling + * marking, resulting in HOM. */ + if (markceiling && ceilingplane == floorplane) + floorplane = R_DupPlane (floorplane, rw_x, rw_stopx-1); + else + floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1); + else + markfloor = 0; + } + + didsolidcol = 0; + R_RenderSegLoop(); + + /* cph - if a column was made solid by this wall, we _must_ save full clipping info */ + if (backsector && didsolidcol) { + if (!(ds_p->silhouette & SIL_BOTTOM)) { + ds_p->silhouette |= SIL_BOTTOM; + ds_p->bsilheight = backsector->floorheight; + } + if (!(ds_p->silhouette & SIL_TOP)) { + ds_p->silhouette |= SIL_TOP; + ds_p->tsilheight = backsector->ceilingheight; + } + } + + // save sprite clipping info + if ((ds_p->silhouette & SIL_TOP || maskedtexture) && !ds_p->sprtopclip) + { + memcpy (lastopening, ceilingclip+start, sizeof(int)*(rw_stopx-start)); // dropoff overflow + ds_p->sprtopclip = lastopening - start; + lastopening += rw_stopx - start; + } + if ((ds_p->silhouette & SIL_BOTTOM || maskedtexture) && !ds_p->sprbottomclip) + { + memcpy (lastopening, floorclip+start, sizeof(int)*(rw_stopx-start)); // dropoff overflow + ds_p->sprbottomclip = lastopening - start; + lastopening += rw_stopx - start; + } + if (maskedtexture && !(ds_p->silhouette & SIL_TOP)) + { + ds_p->silhouette |= SIL_TOP; + ds_p->tsilheight = INT_MIN; + } + if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM)) + { + ds_p->silhouette |= SIL_BOTTOM; + ds_p->bsilheight = INT_MAX; + } + ds_p++; +} diff --git a/src/r_segs.h b/src/r_segs.h new file mode 100644 index 0000000..c5b29a6 --- /dev/null +++ b/src/r_segs.h @@ -0,0 +1,44 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Refresh module, drawing LineSegs from BSP. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_SEGS__ +#define __R_SEGS__ + +#ifdef __GNUG__ +#pragma interface +#endif + +void R_RenderMaskedSegRange(drawseg_t *ds, int x1, int x2); +void R_StoreWallRange(const int start, const int stop); + +#endif diff --git a/src/r_sky.c b/src/r_sky.c new file mode 100644 index 0000000..bc33c63 --- /dev/null +++ b/src/r_sky.c @@ -0,0 +1,56 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Sky rendering. The DOOM sky is a texture map like any + * wall, wrapping around. A 1024 columns equal 360 degrees. + * The default sky map is 256 columns and repeats 4 times + * on a 320 screen? + * + *-----------------------------------------------------------------------------*/ + +#ifdef __GNUG__ +#pragma implementation "r_sky.h" +#endif +#include "r_sky.h" + +// +// sky mapping +// +int skyflatnum; +int skytexture; +int skytexturemid; + +// +// R_InitSkyMap +// Called whenever the view size changes. +// +void R_InitSkyMap (void) +{ + skytexturemid = 100*FRACUNIT; +} diff --git a/src/r_sky.h b/src/r_sky.h new file mode 100644 index 0000000..1a69ae4 --- /dev/null +++ b/src/r_sky.h @@ -0,0 +1,55 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Sky rendering. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_SKY__ +#define __R_SKY__ + +#include "m_fixed.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +/* SKY, store the number for name. */ +#define SKYFLATNAME "F_SKY1" + +/* The sky map is 256*128*4 maps. */ +#define ANGLETOSKYSHIFT 22 + +extern int skytexture; +extern int skytexturemid; + +/* Called whenever the view size changes. */ +void R_InitSkyMap(void); + +#endif diff --git a/src/r_state.h b/src/r_state.h new file mode 100644 index 0000000..44784f2 --- /dev/null +++ b/src/r_state.h @@ -0,0 +1,116 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Refresh/render internal state variables (global). + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __R_STATE__ +#define __R_STATE__ + +// Need data structure definitions. +#include "d_player.h" +#include "r_data.h" + +#ifdef __GNUG__ +#pragma interface +#endif + + +// +// Refresh internal data structures, +// for rendering. +// + +// needed for texture pegging +extern fixed_t *textureheight; + +extern int scaledviewwidth; + +extern int firstflat, numflats; + +// for global animation +extern int *flattranslation; +extern int *texturetranslation; + +// Sprite.... +extern int firstspritelump; +extern int lastspritelump; +extern int numspritelumps; + +// +// Lookup tables for map data. +// +extern int numsprites; +extern spritedef_t *sprites; + +extern int numvertexes; +extern vertex_t *vertexes; + +extern int numsegs; +extern seg_t *segs; + +extern int numsectors; +extern sector_t *sectors; + +extern int numsubsectors; +extern subsector_t *subsectors; + +extern int numnodes; +extern node_t *nodes; + +extern int numlines; +extern line_t *lines; + +extern int numsides; +extern side_t *sides; + + +// +// POV data. +// +extern fixed_t viewx; +extern fixed_t viewy; +extern fixed_t viewz; +extern angle_t viewangle; +extern player_t *viewplayer; +extern angle_t clipangle; +extern int viewangletox[FINEANGLES/2]; +extern angle_t xtoviewangle[MAX_SCREENWIDTH+1]; // killough 2/8/98 +extern fixed_t rw_distance; +extern angle_t rw_normalangle; + +// angle to line origin +extern int rw_angle1; + +extern visplane_t *floorplane; +extern visplane_t *ceilingplane; + +#endif diff --git a/src/r_things.c b/src/r_things.c new file mode 100644 index 0000000..68b1011 --- /dev/null +++ b/src/r_things.c @@ -0,0 +1,1077 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Refresh of things, i.e. objects represented by sprites. + * + *-----------------------------------------------------------------------------*/ + +#include "doomstat.h" +#include "w_wad.h" +#include "r_main.h" +#include "r_bsp.h" +#include "r_segs.h" +#include "r_draw.h" +#include "r_things.h" +#include "r_fps.h" +#include "v_video.h" +#include "lprintf.h" + +#define MINZ (FRACUNIT*4) +#define BASEYCENTER 100 + +typedef struct { + int x1; + int x2; + int column; + int topclip; + int bottomclip; +} maskdraw_t; + +// +// Sprite rotation 0 is facing the viewer, +// rotation 1 is one angle turn CLOCKWISE around the axis. +// This is not the same as the angle, +// which increases counter clockwise (protractor). +// There was a lot of stuff grabbed wrong, so I changed it... +// + +fixed_t pspritescale; +fixed_t pspriteiscale; +// proff 11/06/98: Added for high-res +fixed_t pspriteyscale; + +// constant arrays +// used for psprite clipping and initializing clipping + +int negonearray[MAX_SCREENWIDTH]; // killough 2/8/98: // dropoff overflow +int screenheightarray[MAX_SCREENWIDTH]; // change to MAX_* // dropoff overflow + +// +// INITIALIZATION FUNCTIONS +// + +// variables used to look up and range check thing_t sprites patches + +spritedef_t *sprites; +int numsprites; + +#define MAX_SPRITE_FRAMES 29 /* Macroized -- killough 1/25/98 */ + +static spriteframe_t sprtemp[MAX_SPRITE_FRAMES]; +static int maxframe; + +// +// R_InstallSpriteLump +// Local function for R_InitSprites. +// + +static void R_InstallSpriteLump(int lump, unsigned frame, + unsigned rotation, boolean flipped) +{ + if (frame >= MAX_SPRITE_FRAMES || rotation > 8) + I_Error("R_InstallSpriteLump: Bad frame characters in lump %i", lump); + + if ((int) frame > maxframe) + maxframe = frame; + + if (rotation == 0) + { // the lump should be used for all rotations + int r; + for (r=0 ; r<8 ; r++) + if (sprtemp[frame].lump[r]==-1) + { + sprtemp[frame].lump[r] = lump - firstspritelump; + sprtemp[frame].flip[r] = (byte) flipped; + sprtemp[frame].rotate = false; //jff 4/24/98 if any subbed, rotless + } + return; + } + + // the lump is only used for one rotation + + if (sprtemp[frame].lump[--rotation] == -1) + { + sprtemp[frame].lump[rotation] = lump - firstspritelump; + sprtemp[frame].flip[rotation] = (byte) flipped; + sprtemp[frame].rotate = true; //jff 4/24/98 only change if rot used + } +} + +// +// R_InitSpriteDefs +// Pass a null terminated list of sprite names +// (4 chars exactly) to be used. +// +// Builds the sprite rotation matrixes to account +// for horizontally flipped sprites. +// +// Will report an error if the lumps are inconsistent. +// Only called at startup. +// +// Sprite lump names are 4 characters for the actor, +// a letter for the frame, and a number for the rotation. +// +// A sprite that is flippable will have an additional +// letter/number appended. +// +// The rotation character can be 0 to signify no rotations. +// +// 1/25/98, 1/31/98 killough : Rewritten for performance +// +// Empirically verified to have excellent hash +// properties across standard Doom sprites: + +#define R_SpriteNameHash(s) ((unsigned)((s)[0]-((s)[1]*3-(s)[3]*2-(s)[2])*2)) + +static void R_InitSpriteDefs(const char * const * namelist) +{ + size_t numentries = lastspritelump-firstspritelump+1; + struct { int index, next; } *hash; + int i; + + if (!numentries || !*namelist) + return; + + // count the number of sprite names + for (i=0; namelist[i]; i++) + ; + + numsprites = i; + + sprites = Z_Malloc(numsprites *sizeof(*sprites), PU_STATIC, NULL); + + // Create hash table based on just the first four letters of each sprite + // killough 1/31/98 + + hash = malloc(sizeof(*hash)*numentries); // allocate hash table + + for (i=0; (size_t)i= 0) + { + memset(sprtemp, -1, sizeof(sprtemp)); + maxframe = -1; + do + { + register lumpinfo_t *lump = lumpinfo + j + firstspritelump; + + // Fast portable comparison -- killough + // (using int pointer cast is nonportable): + + if (!((lump->name[0] ^ spritename[0]) | + (lump->name[1] ^ spritename[1]) | + (lump->name[2] ^ spritename[2]) | + (lump->name[3] ^ spritename[3]))) + { + R_InstallSpriteLump(j+firstspritelump, + lump->name[4] - 'A', + lump->name[5] - '0', + false); + if (lump->name[6]) + R_InstallSpriteLump(j+firstspritelump, + lump->name[6] - 'A', + lump->name[7] - '0', + true); + } + } + while ((j = hash[j].next) >= 0); + + // check the frames that were found for completeness + if ((sprites[i].numframes = ++maxframe)) // killough 1/31/98 + { + int frame; + for (frame = 0; frame < maxframe; frame++) + switch ((int) sprtemp[frame].rotate) + { + case -1: + // no rotations were found for that frame at all + I_Error ("R_InitSprites: No patches found " + "for %.8s frame %c", namelist[i], frame+'A'); + break; + + case 0: + // only the first rotation is needed + break; + + case 1: + // must have all 8 frames + { + int rotation; + for (rotation=0 ; rotation<8 ; rotation++) + if (sprtemp[frame].lump[rotation] == -1) + I_Error ("R_InitSprites: Sprite %.8s frame %c " + "is missing rotations", + namelist[i], frame+'A'); + break; + } + } + // allocate space for the frames present and copy sprtemp to it + sprites[i].spriteframes = + Z_Malloc (maxframe * sizeof(spriteframe_t), PU_STATIC, NULL); + memcpy (sprites[i].spriteframes, sprtemp, + maxframe*sizeof(spriteframe_t)); + } + } + } + free(hash); // free hash table +} + +// +// GAME FUNCTIONS +// + +static vissprite_t *vissprites, **vissprite_ptrs; // killough +static size_t num_vissprite, num_vissprite_alloc, num_vissprite_ptrs; + +// +// R_InitSprites +// Called at program start. +// + +void R_InitSprites(const char * const *namelist) +{ + int i; + for (i=0; i= num_vissprite_alloc) // killough + { + size_t num_vissprite_alloc_prev = num_vissprite_alloc; + + num_vissprite_alloc = num_vissprite_alloc ? num_vissprite_alloc*2 : 128; + vissprites = realloc(vissprites,num_vissprite_alloc*sizeof(*vissprites)); + + //e6y: set all fields to zero + memset(vissprites + num_vissprite_alloc_prev, 0, + (num_vissprite_alloc - num_vissprite_alloc_prev)*sizeof(*vissprites)); + } + return vissprites + num_vissprite++; +} + +// +// R_DrawMaskedColumn +// Used for sprites and masked mid textures. +// Masked means: partly transparent, i.e. stored +// in posts/runs of opaque pixels. +// + +int *mfloorclip; // dropoff overflow +int *mceilingclip; // dropoff overflow +fixed_t spryscale; +fixed_t sprtopscreen; + +void R_DrawMaskedColumn( + const rpatch_t *patch, + R_DrawColumn_f colfunc, + draw_column_vars_t *dcvars, + const rcolumn_t *column, + const rcolumn_t *prevcolumn, + const rcolumn_t *nextcolumn +) +{ + int i; + int topscreen; + int bottomscreen; + fixed_t basetexturemid = dcvars->texturemid; + + dcvars->texheight = patch->height; // killough 11/98 + for (i=0; inumPosts; i++) { + const rpost_t *post = &column->posts[i]; + + // calculate unclipped screen coordinates for post + topscreen = sprtopscreen + spryscale*post->topdelta; + bottomscreen = topscreen + spryscale*post->length; + + dcvars->yl = (topscreen+FRACUNIT-1)>>FRACBITS; + dcvars->yh = (bottomscreen-1)>>FRACBITS; + + if (dcvars->yh >= mfloorclip[dcvars->x]) + dcvars->yh = mfloorclip[dcvars->x]-1; + + if (dcvars->yl <= mceilingclip[dcvars->x]) + dcvars->yl = mceilingclip[dcvars->x]+1; + + // killough 3/2/98, 3/27/98: Failsafe against overflow/crash: + if (dcvars->yl <= dcvars->yh && dcvars->yh < viewheight) + { + dcvars->source = column->pixels + post->topdelta; + dcvars->prevsource = prevcolumn->pixels + post->topdelta; + dcvars->nextsource = nextcolumn->pixels + post->topdelta; + + dcvars->texturemid = basetexturemid - (post->topdelta<edgeslope = post->slope; + // Drawn by either R_DrawColumn + // or (SHADOW) R_DrawFuzzColumn. + dcvars->drawingmasked = 1; // POPE + colfunc (dcvars); + dcvars->drawingmasked = 0; // POPE + } + } + dcvars->texturemid = basetexturemid; +} + +// +// R_DrawVisSprite +// mfloorclip and mceilingclip should also be set. +// +// CPhipps - new wad lump handling, *'s to const*'s +static void R_DrawVisSprite(vissprite_t *vis, int x1, int x2) +{ + int texturecolumn; + fixed_t frac; + const rpatch_t *patch = R_CachePatchNum(vis->patch+firstspritelump); + R_DrawColumn_f colfunc; + draw_column_vars_t dcvars; + enum draw_filter_type_e filter; + enum draw_filter_type_e filterz; + + R_SetDefaultDrawColumnVars(&dcvars); + if (vis->isplayersprite) { + dcvars.edgetype = drawvars.patch_edges; + filter = drawvars.filterpatch; + filterz = RDRAW_FILTER_POINT; + } else { + dcvars.edgetype = drawvars.sprite_edges; + filter = drawvars.filtersprite; + filterz = drawvars.filterz; + } + + dcvars.colormap = vis->colormap; + dcvars.nextcolormap = dcvars.colormap; // for filtering -- POPE + + // killough 4/11/98: rearrange and handle translucent sprites + // mixed with translucent/non-translucenct 2s normals + + if (!dcvars.colormap) // NULL colormap = shadow draw + colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_FUZZ, filter, filterz); // killough 3/14/98 + else + if (vis->mobjflags & MF_TRANSLATION) + { + colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLATED, filter, filterz); + dcvars.translation = translationtables - 256 + + ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT-8) ); + } + else + if (vis->mobjflags & MF_TRANSLUCENT && general_translucency) // phares + { + colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLUCENT, filter, filterz); + tranmap = main_tranmap; // killough 4/11/98 + } + else + colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, filter, filterz); // killough 3/14/98, 4/11/98 + +// proff 11/06/98: Changed for high-res + dcvars.iscale = FixedDiv (FRACUNIT, vis->scale); + dcvars.texturemid = vis->texturemid; + frac = vis->startfrac; + if (filter == RDRAW_FILTER_LINEAR) + frac -= (FRACUNIT>>1); + spryscale = vis->scale; + sprtopscreen = centeryfrac - FixedMul(dcvars.texturemid,spryscale); + + for (dcvars.x=vis->x1 ; dcvars.x<=vis->x2 ; dcvars.x++, frac += vis->xiscale) + { + texturecolumn = frac>>FRACBITS; + dcvars.texu = frac; + + R_DrawMaskedColumn( + patch, + colfunc, + &dcvars, + R_GetPatchColumnClamped(patch, texturecolumn), + R_GetPatchColumnClamped(patch, texturecolumn-1), + R_GetPatchColumnClamped(patch, texturecolumn+1) + ); + } + R_UnlockPatchNum(vis->patch+firstspritelump); // cph - release lump +} + +// +// R_ProjectSprite +// Generates a vissprite for a thing if it might be visible. +// + +static void R_ProjectSprite (mobj_t* thing, int lightlevel) +{ + fixed_t gzt; // killough 3/27/98 + fixed_t tx; + fixed_t xscale; + int x1; + int x2; + spritedef_t *sprdef; + spriteframe_t *sprframe; + int lump; + boolean flip; + vissprite_t *vis; + fixed_t iscale; + int heightsec; // killough 3/27/98 + + // transform the origin point + fixed_t tr_x, tr_y; + fixed_t fx, fy, fz; + fixed_t gxt, gyt; + fixed_t tz; + int width; + + if (movement_smooth) + { + fx = thing->PrevX + FixedMul (tic_vars.frac, thing->x - thing->PrevX); + fy = thing->PrevY + FixedMul (tic_vars.frac, thing->y - thing->PrevY); + fz = thing->PrevZ + FixedMul (tic_vars.frac, thing->z - thing->PrevZ); + } + else + { + fx = thing->x; + fy = thing->y; + fz = thing->z; + } + tr_x = fx - viewx; + tr_y = fy - viewy; + + gxt = FixedMul(tr_x,viewcos); + gyt = -FixedMul(tr_y,viewsin); + + tz = gxt-gyt; + + // thing is behind view plane? + if (tz < MINZ) + return; + + xscale = FixedDiv(projection, tz); + + gxt = -FixedMul(tr_x,viewsin); + gyt = FixedMul(tr_y,viewcos); + tx = -(gyt+gxt); + + // too far off the side? + if (D_abs(tx)>(tz<<2)) + return; + + // decide which patch to use for sprite relative to player +#ifdef RANGECHECK + if ((unsigned) thing->sprite >= (unsigned)numsprites) + I_Error ("R_ProjectSprite: Invalid sprite number %i", thing->sprite); +#endif + + sprdef = &sprites[thing->sprite]; + +#ifdef RANGECHECK + if ((thing->frame&FF_FRAMEMASK) >= sprdef->numframes) + I_Error ("R_ProjectSprite: Invalid sprite frame %i : %i", thing->sprite, + thing->frame); +#endif + + if (!sprdef->spriteframes) + I_Error ("R_ProjectSprite: Missing spriteframes %i : %i", thing->sprite, + thing->frame); + + sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK]; + + if (sprframe->rotate) + { + // choose a different rotation based on player view + angle_t ang = R_PointToAngle(fx, fy); + unsigned rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29; + lump = sprframe->lump[rot]; + flip = (boolean) sprframe->flip[rot]; + } + else + { + // use single rotation for all views + lump = sprframe->lump[0]; + flip = (boolean) sprframe->flip[0]; + } + + { + const rpatch_t* patch = R_CachePatchNum(lump+firstspritelump); + + /* calculate edges of the shape + * cph 2003/08/1 - fraggle points out that this offset must be flipped + * if the sprite is flipped; e.g. FreeDoom imp is messed up by this. */ + if (flip) { + tx -= (patch->width - patch->leftoffset) << FRACBITS; + } else { + tx -= patch->leftoffset << FRACBITS; + } + x1 = (centerxfrac + FixedMul(tx,xscale)) >> FRACBITS; + + tx += patch->width<> FRACBITS) - 1; + + gzt = fz + (patch->topoffset << FRACBITS); + width = patch->width; + R_UnlockPatchNum(lump+firstspritelump); + } + + // off the side? + if (x1 > viewwidth || x2 < 0) + return; + + // killough 4/9/98: clip things which are out of view due to height + // e6y: fix of hanging decoration disappearing in Batman Doom MAP02 + // centeryfrac -> viewheightfrac + if (fz > viewz + FixedDiv(viewheightfrac, xscale) || + gzt < viewz - FixedDiv(viewheightfrac-viewheight, xscale)) + return; + + // killough 3/27/98: exclude things totally separated + // from the viewer, by either water or fake ceilings + // killough 4/11/98: improve sprite clipping for underwater/fake ceilings + + heightsec = thing->subsector->sector->heightsec; + + if (heightsec != -1) // only clip things which are in special sectors + { + int phs = viewplayer->mo->subsector->sector->heightsec; + if (phs != -1 && viewz < sectors[phs].floorheight ? + fz >= sectors[heightsec].floorheight : + gzt < sectors[heightsec].floorheight) + return; + if (phs != -1 && viewz > sectors[phs].ceilingheight ? + gzt < sectors[heightsec].ceilingheight && + viewz >= sectors[heightsec].ceilingheight : + fz >= sectors[heightsec].ceilingheight) + return; + } + + // store information in a vissprite + vis = R_NewVisSprite (); + +#ifdef GL_DOOM + if (V_GetMode() == VID_MODEGL) + { + // proff 11/99: add sprite for OpenGL + vis->thing = thing; + vis->flip = flip; + vis->scale = FixedDiv(projectiony, tz); + vis->patch = lump; + gld_AddSprite(vis); + + return; + } +#endif + // killough 3/27/98: save sector for special clipping later + vis->heightsec = heightsec; + + vis->mobjflags = thing->flags; +// proff 11/06/98: Changed for high-res + vis->scale = FixedDiv(projectiony, tz); + vis->gx = fx; + vis->gy = fy; + vis->gz = fz; + vis->gzt = gzt; // killough 3/27/98 + vis->texturemid = vis->gzt - viewz; + vis->x1 = x1 < 0 ? 0 : x1; + vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; + iscale = FixedDiv (FRACUNIT, xscale); + + if (flip) + { + vis->startfrac = (width<xiscale = -iscale; + } + else + { + vis->startfrac = 0; + vis->xiscale = iscale; + } + + if (vis->x1 > x1) + vis->startfrac += vis->xiscale*(vis->x1-x1); + vis->patch = lump; + + // get light level + if (thing->flags & MF_SHADOW) + vis->colormap = NULL; // shadow draw + else if (fixedcolormap) + vis->colormap = fixedcolormap; // fixed map + else if (thing->frame & FF_FULLBRIGHT) + vis->colormap = fullcolormap; // full bright // killough 3/20/98 + else + { // diminished light + vis->colormap = R_ColourMap(lightlevel,xscale); + } +} + +// +// R_AddSprites +// During BSP traversal, this adds sprites by sector. +// +// killough 9/18/98: add lightlevel as parameter, fixing underwater lighting +void R_AddSprites(subsector_t* subsec, int lightlevel) +{ + sector_t* sec=subsec->sector; + mobj_t *thing; + + // BSP is traversed by subsector. + // A sector might have been split into several + // subsectors during BSP building. + // Thus we check whether its already added. + + if (sec->validcount == validcount) + return; + + // Well, now it will be done. + sec->validcount = validcount; + + // Handle all things in sector. + + for (thing = sec->thinglist; thing; thing = thing->snext) + R_ProjectSprite(thing, lightlevel); +} + +// +// R_DrawPSprite +// + +static void R_DrawPSprite (pspdef_t *psp, int lightlevel) +{ + int x1, x2; + spritedef_t *sprdef; + spriteframe_t *sprframe; + int lump; + boolean flip; + vissprite_t *vis; + vissprite_t avis; + int width; + fixed_t topoffset; + + avis.isplayersprite = true; + + // decide which patch to use + +#ifdef RANGECHECK + if ( (unsigned)psp->state->sprite >= (unsigned)numsprites) + I_Error ("R_ProjectSprite: Invalid sprite number %i", psp->state->sprite); +#endif + + sprdef = &sprites[psp->state->sprite]; + +#ifdef RANGECHECK + if ( (psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes) + I_Error ("R_ProjectSprite: Invalid sprite frame %i : %li", + psp->state->sprite, psp->state->frame); +#endif + + sprframe = &sprdef->spriteframes[psp->state->frame & FF_FRAMEMASK]; + + lump = sprframe->lump[0]; + flip = (boolean) sprframe->flip[0]; + + { + const rpatch_t* patch = R_CachePatchNum(lump+firstspritelump); + // calculate edges of the shape + fixed_t tx; + tx = psp->sx-160*FRACUNIT; + + tx -= patch->leftoffset<>FRACBITS; + + tx += patch->width<>FRACBITS) - 1; + + width = patch->width; + topoffset = patch->topoffset< viewwidth) + return; + + // store information in a vissprite + vis = &avis; + vis->mobjflags = 0; + // killough 12/98: fix psprite positioning problem + vis->texturemid = (BASEYCENTER<sy-topoffset); + vis->x1 = x1 < 0 ? 0 : x1; + vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; +// proff 11/06/98: Added for high-res + vis->scale = pspriteyscale; + + if (flip) + { + vis->xiscale = -pspriteiscale; + vis->startfrac = (width<xiscale = pspriteiscale; + vis->startfrac = 0; + } + + if (vis->x1 > x1) + vis->startfrac += vis->xiscale*(vis->x1-x1); + + vis->patch = lump; + + if (viewplayer->powers[pw_invisibility] > 4*32 + || viewplayer->powers[pw_invisibility] & 8) + vis->colormap = NULL; // shadow draw + else if (fixedcolormap) + vis->colormap = fixedcolormap; // fixed color + else if (psp->state->frame & FF_FULLBRIGHT) + vis->colormap = fullcolormap; // full bright // killough 3/20/98 + else + // add a fudge factor to better match the original game + vis->colormap = R_ColourMap(lightlevel, + FixedMul(pspritescale, 0x2b000)); // local light + + // proff 11/99: don't use software stuff in OpenGL + if (V_GetMode() != VID_MODEGL) + { + R_DrawVisSprite(vis, vis->x1, vis->x2); + } +#ifdef GL_DOOM + else + { + int lightlevel; + sector_t tmpsec; + int floorlightlevel, ceilinglightlevel; + + if ((vis->colormap==fixedcolormap) || (vis->colormap==fullcolormap)) + lightlevel=255; + else + { +// lightlevel = (viewplayer->mo->subsector->sector->lightlevel) + (extralight << LIGHTSEGSHIFT); + R_FakeFlat( viewplayer->mo->subsector->sector, &tmpsec, + &floorlightlevel, &ceilinglightlevel, false); + lightlevel = ((floorlightlevel+ceilinglightlevel) >> 1) + (extralight << LIGHTSEGSHIFT); + + if (lightlevel < 0) + lightlevel = 0; + else if (lightlevel >= 255) + lightlevel = 255; + } + gld_DrawWeapon(lump,vis,lightlevel); + } +#endif +} + +// +// R_DrawPlayerSprites +// + +void R_DrawPlayerSprites(void) +{ + int i, lightlevel = viewplayer->mo->subsector->sector->lightlevel; + pspdef_t *psp; + + // clip to screen bounds + mfloorclip = screenheightarray; + mceilingclip = negonearray; + + // add all active psprites + for (i=0, psp=viewplayer->psprites; istate) + R_DrawPSprite (psp, lightlevel); +} + +// +// R_SortVisSprites +// +// Rewritten by Lee Killough to avoid using unnecessary +// linked lists, and to use faster sorting algorithm. +// + +#ifdef DJGPP + +// killough 9/22/98: inlined memcpy of pointer arrays +// CPhipps - added memory as modified +#define bcopyp(d, s, n) asm(" cld; rep; movsl;" :: "D"(d), "S"(s), "c"(n) : "%cc", "%esi", "%edi", "%ecx", "memory") + +#else + +#define bcopyp(d, s, n) memcpy(d, s, (n) * sizeof(void *)) + +#endif + +// killough 9/2/98: merge sort + +static void msort(vissprite_t **s, vissprite_t **t, int n) +{ + if (n >= 16) + { + int n1 = n/2, n2 = n - n1; + vissprite_t **s1 = s, **s2 = s + n1, **d = t; + + msort(s1, t, n1); + msort(s2, t, n2); + + while ((*s1)->scale > (*s2)->scale ? + (*d++ = *s1++, --n1) : (*d++ = *s2++, --n2)); + + if (n2) + bcopyp(d, s2, n2); + else + bcopyp(d, s1, n1); + + bcopyp(s, t, n); + } + else + { + int i; + for (i = 1; i < n; i++) + { + vissprite_t *temp = s[i]; + if (s[i-1]->scale < temp->scale) + { + int j = i; + while ((s[j] = s[j-1])->scale < temp->scale && --j); + s[j] = temp; + } + } + } +} + +void R_SortVisSprites (void) +{ + if (num_vissprite) + { + int i = num_vissprite; + + // If we need to allocate more pointers for the vissprites, + // allocate as many as were allocated for sprites -- killough + // killough 9/22/98: allocate twice as many + + if (num_vissprite_ptrs < num_vissprite*2) + { + free(vissprite_ptrs); // better than realloc -- no preserving needed + vissprite_ptrs = malloc((num_vissprite_ptrs = num_vissprite_alloc*2) + * sizeof *vissprite_ptrs); + } + + while (--i>=0) + vissprite_ptrs[i] = vissprites+i; + + // killough 9/22/98: replace qsort with merge sort, since the keys + // are roughly in order to begin with, due to BSP rendering. + + msort(vissprite_ptrs, vissprite_ptrs + num_vissprite, num_vissprite); + } +} + +// +// R_DrawSprite +// + +static void R_DrawSprite (vissprite_t* spr) +{ + drawseg_t *ds; + int clipbot[MAX_SCREENWIDTH]; // killough 2/8/98: // dropoff overflow + int cliptop[MAX_SCREENWIDTH]; // change to MAX_* // dropoff overflow + int x; + int r1; + int r2; + fixed_t scale; + fixed_t lowscale; + + for (x = spr->x1 ; x<=spr->x2 ; x++) + clipbot[x] = cliptop[x] = -2; + + // Scan drawsegs from end to start for obscuring segs. + // The first drawseg that has a greater scale is the clip seg. + + // Modified by Lee Killough: + // (pointer check was originally nonportable + // and buggy, by going past LEFT end of array): + + // for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code + + for (ds=ds_p ; ds-- > drawsegs ; ) // new -- killough + { // determine if the drawseg obscures the sprite + if (ds->x1 > spr->x2 || ds->x2 < spr->x1 || + (!ds->silhouette && !ds->maskedtexturecol)) + continue; // does not cover sprite + + r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1; + r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2; + + if (ds->scale1 > ds->scale2) + { + lowscale = ds->scale2; + scale = ds->scale1; + } + else + { + lowscale = ds->scale1; + scale = ds->scale2; + } + + if (scale < spr->scale || (lowscale < spr->scale && + !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) + { + if (ds->maskedtexturecol) // masked mid texture? + R_RenderMaskedSegRange(ds, r1, r2); + continue; // seg is behind sprite + } + + // clip this piece of the sprite + // killough 3/27/98: optimized and made much shorter + + if (ds->silhouette&SIL_BOTTOM && spr->gz < ds->bsilheight) //bottom sil + for (x=r1 ; x<=r2 ; x++) + if (clipbot[x] == -2) + clipbot[x] = ds->sprbottomclip[x]; + + if (ds->silhouette&SIL_TOP && spr->gzt > ds->tsilheight) // top sil + for (x=r1 ; x<=r2 ; x++) + if (cliptop[x] == -2) + cliptop[x] = ds->sprtopclip[x]; + } + + // killough 3/27/98: + // Clip the sprite against deep water and/or fake ceilings. + // killough 4/9/98: optimize by adding mh + // killough 4/11/98: improve sprite clipping for underwater/fake ceilings + // killough 11/98: fix disappearing sprites + + if (spr->heightsec != -1) // only things in specially marked sectors + { + fixed_t h,mh; + int phs = viewplayer->mo->subsector->sector->heightsec; + if ((mh = sectors[spr->heightsec].floorheight) > spr->gz && + (h = centeryfrac - FixedMul(mh-=viewz, spr->scale)) >= 0 && + (h >>= FRACBITS) < viewheight) { + if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight)) + { // clip bottom + for (x=spr->x1 ; x<=spr->x2 ; x++) + if (clipbot[x] == -2 || h < clipbot[x]) + clipbot[x] = h; + } + else // clip top + if (phs != -1 && viewz <= sectors[phs].floorheight) // killough 11/98 + for (x=spr->x1 ; x<=spr->x2 ; x++) + if (cliptop[x] == -2 || h > cliptop[x]) + cliptop[x] = h; + } + + if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt && + (h = centeryfrac - FixedMul(mh-viewz, spr->scale)) >= 0 && + (h >>= FRACBITS) < viewheight) { + if (phs != -1 && viewz >= sectors[phs].ceilingheight) + { // clip bottom + for (x=spr->x1 ; x<=spr->x2 ; x++) + if (clipbot[x] == -2 || h < clipbot[x]) + clipbot[x] = h; + } + else // clip top + for (x=spr->x1 ; x<=spr->x2 ; x++) + if (cliptop[x] == -2 || h > cliptop[x]) + cliptop[x] = h; + } + } + // killough 3/27/98: end special clipping for deep water / fake ceilings + + // all clipping has been performed, so draw the sprite + // check for unclipped columns + + for (x = spr->x1 ; x<=spr->x2 ; x++) { + if (clipbot[x] == -2) + clipbot[x] = viewheight; + + if (cliptop[x] == -2) + cliptop[x] = -1; + } + + mfloorclip = clipbot; + mceilingclip = cliptop; + R_DrawVisSprite (spr, spr->x1, spr->x2); +} + +// +// R_DrawMasked +// + +void R_DrawMasked(void) +{ + int i; + drawseg_t *ds; + + R_SortVisSprites(); + + // draw all vissprites back to front + + rendered_vissprites = num_vissprite; + for (i = num_vissprite ;--i>=0; ) + R_DrawSprite(vissprite_ptrs[i]); // killough + + // render any remaining masked mid textures + + // Modified by Lee Killough: + // (pointer check was originally nonportable + // and buggy, by going past LEFT end of array): + + // for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code + + for (ds=ds_p ; ds-- > drawsegs ; ) // new -- killough + if (ds->maskedtexturecol) + R_RenderMaskedSegRange(ds, ds->x1, ds->x2); + + // draw the psprites on top of everything + // but does not draw on side views + if (!viewangleoffset) + R_DrawPlayerSprites (); +} diff --git a/src/r_things.h b/src/r_things.h new file mode 100644 index 0000000..a6c504e --- /dev/null +++ b/src/r_things.h @@ -0,0 +1,72 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Rendering of moving objects, sprites. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __R_THINGS__ +#define __R_THINGS__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "r_draw.h" + +/* Constant arrays used for psprite clipping and initializing clipping. */ + +extern int negonearray[MAX_SCREENWIDTH]; /* killough 2/8/98: */ // dropoff overflow +extern int screenheightarray[MAX_SCREENWIDTH]; /* change to MAX_* */ // dropoff overflow + +/* Vars for R_DrawMaskedColumn */ + +extern int *mfloorclip; // dropoff overflow +extern int *mceilingclip; // dropoff overflow +extern fixed_t spryscale; +extern fixed_t sprtopscreen; +extern fixed_t pspritescale; +extern fixed_t pspriteiscale; +/* proff 11/06/98: Added for high-res */ +extern fixed_t pspriteyscale; + +void R_DrawMaskedColumn(const rpatch_t *patch, + R_DrawColumn_f colfunc, + draw_column_vars_t *dcvars, + const rcolumn_t *column, + const rcolumn_t *prevcolumn, + const rcolumn_t *nextcolumn); +void R_SortVisSprites(void); +void R_AddSprites(subsector_t* subsec, int lightlevel); +void R_DrawPlayerSprites(void); +void R_InitSprites(const char * const * namelist); +void R_ClearSprites(void); +void R_DrawMasked(void); + +#endif diff --git a/src/s_sound.c b/src/s_sound.c new file mode 100644 index 0000000..fa28e9a --- /dev/null +++ b/src/s_sound.c @@ -0,0 +1,688 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: Platform-independent sound code + * + *-----------------------------------------------------------------------------*/ + +// killough 3/7/98: modified to allow arbitrary listeners in spy mode +// killough 5/2/98: reindented, removed useless code, beautified + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "doomstat.h" +#include "s_sound.h" +#include "i_sound.h" +#include "i_system.h" +#include "d_main.h" +#include "r_main.h" +#include "m_random.h" +#include "w_wad.h" +#include "lprintf.h" + +// when to clip out sounds +// Does not fit the large outdoor areas. +#define S_CLIPPING_DIST (1200<>FRACBITS) + +// Adjustable by menu. +#define NORM_PITCH 128 +#define NORM_PRIORITY 64 +#define NORM_SEP 128 +#define S_STEREO_SWING (96<= prboom_2_compatibility && sfx_id == sfx_noway); // killough 4/25/98 + sfx_id &= ~PICKUP_SOUND; + + // check for bogus sound # + if (sfx_id < 1 || sfx_id > NUMSFX) + I_Error("S_StartSoundAtVolume: 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, modify the params + // killough 3/7/98, 4/25/98: code rearranged slightly + + if (!origin || origin == players[displayplayer].mo) { + sep = NORM_SEP; + volume *= 8; + } else + if (!S_AdjustSoundParams(players[displayplayer].mo, origin, &volume, + &sep, &pitch)) + return; + else + if ( origin->x == players[displayplayer].mo->x && + origin->y == players[displayplayer].mo->y) + sep = NORM_SEP; + + // hacks to vary the sfx pitches + if (sfx_id >= sfx_sawup && sfx_id <= sfx_sawhit) + pitch += 8 - (M_Random()&15); + else + if (sfx_id != sfx_itemup && sfx_id != sfx_tink) + pitch += 16 - (M_Random()&31); + + if (pitch<0) + pitch = 0; + + if (pitch>255) + pitch = 255; + + // kill old sound + for (cnum=0 ; cnumlumpnum < 0 && (sfx->lumpnum = I_GetSfxLumpNum(sfx)) < 0) + return; + + // increase the usefulness + if (sfx->usefulness++ < 0) + sfx->usefulness = 1; + + // Assigns the handle to one of the channels in the mix/output buffer. + { // e6y: [Fix] Crash with zero-length sounds. + int h = I_StartSound(sfx_id, cnum, volume, sep, pitch, priority); + if (h != -1) channels[cnum].handle = h; + } +} + +void S_StartSound(void *origin, int sfx_id) +{ + S_StartSoundAtVolume(origin, sfx_id, snd_SfxVolume); +} + +void S_StopSound(void *origin) +{ + int cnum; + + //jff 1/22/98 return if sound is not enabled + if (!snd_card || nosfxparm) + return; + + for (cnum=0 ; cnumhandle); + mus_paused = true; + } +} + +void S_ResumeSound(void) +{ + //jff 1/22/98 return if music is not enabled + if (!mus_card || nomusicparm) + return; + + if (mus_playing && mus_paused) + { + I_ResumeSong(mus_playing->handle); + mus_paused = false; + } +} + + +// +// Updates music & sounds +// +void S_UpdateSounds(void* listener_p) +{ + mobj_t *listener = (mobj_t*) listener_p; + int cnum; + + //jff 1/22/98 return if sound is not enabled + if (!snd_card || nosfxparm) + return; + +#ifdef UPDATE_MUSIC + I_UpdateMusic(); +#endif + + for (cnum=0 ; cnumsfxinfo)) + { + if (I_SoundIsPlaying(c->handle)) + { + // initialize parameters + int volume = snd_SfxVolume; + int pitch = NORM_PITCH; + int 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) { // killough 3/20/98 + if (!S_AdjustSoundParams(listener, c->origin, + &volume, &sep, &pitch)) + 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); + } + } +} + + + +void S_SetMusicVolume(int volume) +{ + //jff 1/22/98 return if music is not enabled + if (!mus_card || nomusicparm) + return; + if (volume < 0 || volume > 15) + I_Error("S_SetMusicVolume: Attempt to set music volume at %d", volume); + I_SetMusicVolume(volume); + snd_MusicVolume = volume; +} + + + +void S_SetSfxVolume(int volume) +{ + //jff 1/22/98 return if sound is not enabled + if (!snd_card || nosfxparm) + return; + if (volume < 0 || volume > 127) + I_Error("S_SetSfxVolume: 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) +{ + //jff 1/22/98 return if music is not enabled + if (!mus_card || nomusicparm) + return; + S_ChangeMusic(m_id, false); +} + + + +void S_ChangeMusic(int musicnum, int looping) +{ + musicinfo_t *music; + int music_file_failed; // cournia - if true load the default MIDI music + char* music_filename; // cournia + + //jff 1/22/98 return if music is not enabled + if (!mus_card || nomusicparm) + return; + + if (musicnum <= mus_None || musicnum >= NUMMUSIC) + I_Error("S_ChangeMusic: Bad music number %d", musicnum); + + music = &S_music[musicnum]; + + if (mus_playing == music) + return; + + // shutdown old music + S_StopMusic(); + + // get lumpnum if neccessary + if (!music->lumpnum) + { + char namebuf[9]; + sprintf(namebuf, "d_%s", music->name); + music->lumpnum = W_GetNumForName(namebuf); + } + + music_file_failed = 1; + + // proff_fs - only load when from IWAD + if (lumpinfo[music->lumpnum].source == source_iwad) + { + // cournia - check to see if we can play a higher quality music file + // rather than the default MIDI + music_filename = I_FindFile(S_music_files[musicnum], ""); + if (music_filename) + { + music_file_failed = I_RegisterMusic(music_filename, music); + free(music_filename); + } + } + + if (music_file_failed) + { + //cournia - could not load music file, play default MIDI music + + // load & register it + music->data = W_CacheLumpNum(music->lumpnum); + music->handle = I_RegisterSong(music->data, W_LumpLength(music->lumpnum)); + } + + // play it + I_PlaySong(music->handle, looping); + + mus_playing = music; +} + + +void S_StopMusic(void) +{ + //jff 1/22/98 return if music is not enabled + if (!mus_card || nomusicparm) + return; + + if (mus_playing) + { + if (mus_paused) + I_ResumeSong(mus_playing->handle); + + I_StopSong(mus_playing->handle); + I_UnRegisterSong(mus_playing->handle); + if (mus_playing->lumpnum >= 0) + W_UnlockLumpNum(mus_playing->lumpnum); // cph - release the music data + + mus_playing->data = 0; + mus_playing = 0; + } +} + + + +void S_StopChannel(int cnum) +{ + int i; + channel_t *c = &channels[cnum]; + + //jff 1/22/98 return if sound is not enabled + if (!snd_card || nosfxparm) + return; + + if (c->sfxinfo) + { + // stop the sound playing + if (I_SoundIsPlaying(c->handle)) + I_StopSound(c->handle); + + // check to see + // if other channels are playing the sound + for (i=0 ; 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 adx, ady,approx_dist; + angle_t angle; + + //jff 1/22/98 return if sound is not enabled + if (!snd_card || nosfxparm) + return 0; + + // e6y + // Fix crash when the program wants to S_AdjustSoundParams() for player + // which is not displayplayer and displayplayer was not spawned at the moment. + // It happens in multiplayer demos only. + // + // Stack trace is: + // P_SetupLevel() \ P_LoadThings() \ P_SpawnMapThing() \ P_SpawnPlayer(players[0]) \ + // P_SetupPsprites() \ P_BringUpWeapon() \ S_StartSound(players[0]->mo, sfx_sawup) \ + // S_StartSoundAtVolume() \ S_AdjustSoundParams(players[displayplayer]->mo, ...); + // players[displayplayer]->mo is NULL + // + // There is no more crash on e1cmnet3.lmp between e1m2 and e1m3 + // http://competn.doom2.net/pub/compet-n/doom/coop/movies/e1cmnet3.zip + if (!listener) + return 0; + + // calculate the distance to sound origin + // and clip it if necessary + adx = D_abs(listener->x - source->x); + ady = D_abs(listener->y - source->y); + + // From _GG1_ p.428. Appox. eucledian distance fast. + approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1); + + if (!approx_dist) // killough 11/98: handle zero-distance as special case + { + *sep = NORM_SEP; + *vol = snd_SfxVolume; + return *vol > 0; + } + + if (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 += 0xffffffff; + angle -= 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*8; + else + // distance effect + *vol = (snd_SfxVolume * ((S_CLIPPING_DIST-approx_dist)>>FRACBITS) * 8) + / S_ATTENUATOR; + + return (*vol > 0); +} + +// +// S_getChannel : +// If none available, return -1. Otherwise channel #. +// +// killough 4/25/98: made static, added is_pickup argument + +static int S_getChannel(void *origin, sfxinfo_t *sfxinfo, int is_pickup) +{ + // channel number to use + int cnum; + channel_t *c; + + //jff 1/22/98 return if sound is not enabled + if (!snd_card || nosfxparm) + return -1; + + // Find an open channel + for (cnum=0; cnumpriority >= sfxinfo->priority) + break; + if (cnum == numChannels) + return -1; // No lower priority. Sorry, Charlie. + else + S_StopChannel(cnum); // Otherwise, kick out lower priority. + } + + c = &channels[cnum]; // channel is decided to be cnum. + c->sfxinfo = sfxinfo; + c->origin = origin; + c->is_pickup = is_pickup; // killough 4/25/98 + return cnum; +} diff --git a/src/s_sound.h b/src/s_sound.h new file mode 100644 index 0000000..29d3219 --- /dev/null +++ b/src/s_sound.h @@ -0,0 +1,100 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * The not so system specific sound interface. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __S_SOUND__ +#define __S_SOUND__ + +#ifdef __GNUG__ +#pragma interface +#endif + +// +// 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); + +// Kills all sounds +void S_Stop(void); + +// +// Per level startup code. +// Kills playing sounds at start of level, +// determines music if any, changes music. +// +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); + +// killough 4/25/98: mask used to indicate sound origin is player item pickup +#define PICKUP_SOUND (0x8000) + +// Stop sound for thing at +void S_StopSound(void* origin); + +// Start music using from sounds.h +void S_StartMusic(int music_id); + +// Start music using from sounds.h, and set whether looping +void S_ChangeMusic(int music_id, int looping); + +// Stops the music fer sure. +void S_StopMusic(void); + +// Stop and resume music, during game PAUSE. +void S_PauseSound(void); +void S_ResumeSound(void); + +// +// Updates music & sounds +// +void S_UpdateSounds(void* listener); +void S_SetMusicVolume(int volume); +void S_SetSfxVolume(int volume); + +// machine-independent sound params +extern int default_numChannels; +extern int numChannels; + +//jff 3/17/98 holds last IDMUS number, or -1 +extern int idmusnum; + +#endif diff --git a/src/sounds.c b/src/sounds.c new file mode 100644 index 0000000..cc68a3c --- /dev/null +++ b/src/sounds.c @@ -0,0 +1,245 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Created by a sound utility. + * Kept as a sample, DOOM2 sounds. + * + *-----------------------------------------------------------------------------*/ + +// killough 5/3/98: reformatted + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "doomtype.h" +#include "sounds.h" + +// +// Information about all the music +// + +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 }, +}; + + +// +// Information about all the sfx +// + +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 }, + +#ifdef DOGS + // killough 11/98: dog sounds + { "dgsit", false, 98, 0, -1, -1, 0 }, + { "dgatk", false, 70, 0, -1, -1, 0 }, + { "dgact", false, 120, 0, -1, -1, 0 }, + { "dgdth", false, 70, 0, -1, -1, 0 }, + { "dgpain", false, 96, 0, -1, -1, 0 }, +#endif +}; diff --git a/src/sounds.h b/src/sounds.h new file mode 100644 index 0000000..0f82333 --- /dev/null +++ b/src/sounds.h @@ -0,0 +1,305 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Created by the sound utility written by Dave Taylor. + * Kept as a sample, DOOM2 sounds. Frozen. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __SOUNDS__ +#define __SOUNDS__ + +// +// SoundFX struct. +// + +struct sfxinfo_struct; + +typedef struct sfxinfo_struct sfxinfo_t; + +struct sfxinfo_struct { + + // up to 6-character name + const char *name; // CPhipps - const + + // 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 + const char *name; // CPhipps - const + + // lump number of music + int lumpnum; + + /* music data - cphipps 4/11 made const void* */ + const void *data; + + // music handle once registered + int handle; +} musicinfo_t; + +// the complete set of sound effects +extern sfxinfo_t S_sfx[]; + +// the complete set of music +extern musicinfo_t S_music[]; + +// +// Identifiers for all music in game. +// + +typedef enum { + mus_None, + mus_e1m1, + mus_e1m2, + mus_e1m3, + mus_e1m4, + mus_e1m5, + mus_e1m6, + mus_e1m7, + mus_e1m8, + mus_e1m9, + mus_e2m1, + mus_e2m2, + mus_e2m3, + mus_e2m4, + mus_e2m5, + mus_e2m6, + mus_e2m7, + mus_e2m8, + mus_e2m9, + mus_e3m1, + mus_e3m2, + mus_e3m3, + mus_e3m4, + mus_e3m5, + mus_e3m6, + mus_e3m7, + mus_e3m8, + mus_e3m9, + mus_inter, + mus_intro, + mus_bunny, + mus_victor, + mus_introa, + mus_runnin, + mus_stalks, + mus_countd, + mus_betwee, + mus_doom, + mus_the_da, + mus_shawn, + mus_ddtblu, + mus_in_cit, + mus_dead, + mus_stlks2, + mus_theda2, + mus_doom2, + mus_ddtbl2, + mus_runni2, + mus_dead2, + mus_stlks3, + mus_romero, + mus_shawn2, + mus_messag, + mus_count2, + mus_ddtbl3, + mus_ampie, + mus_theda3, + mus_adrian, + mus_messg2, + mus_romer2, + mus_tense, + mus_shawn3, + mus_openin, + mus_evil, + mus_ultima, + mus_read_m, + mus_dm2ttl, + mus_dm2int, + NUMMUSIC +} musicenum_t; + +// +// Identifiers for all sfx in game. +// + +typedef enum { + sfx_None, + sfx_pistol, + sfx_shotgn, + sfx_sgcock, + sfx_dshtgn, + sfx_dbopn, + sfx_dbcls, + sfx_dbload, + sfx_plasma, + sfx_bfg, + sfx_sawup, + sfx_sawidl, + sfx_sawful, + sfx_sawhit, + sfx_rlaunc, + sfx_rxplod, + sfx_firsht, + sfx_firxpl, + sfx_pstart, + sfx_pstop, + sfx_doropn, + sfx_dorcls, + sfx_stnmov, + sfx_swtchn, + sfx_swtchx, + sfx_plpain, + sfx_dmpain, + sfx_popain, + sfx_vipain, + sfx_mnpain, + sfx_pepain, + sfx_slop, + sfx_itemup, + sfx_wpnup, + sfx_oof, + sfx_telept, + sfx_posit1, + sfx_posit2, + sfx_posit3, + sfx_bgsit1, + sfx_bgsit2, + sfx_sgtsit, + sfx_cacsit, + sfx_brssit, + sfx_cybsit, + sfx_spisit, + sfx_bspsit, + sfx_kntsit, + sfx_vilsit, + sfx_mansit, + sfx_pesit, + sfx_sklatk, + sfx_sgtatk, + sfx_skepch, + sfx_vilatk, + sfx_claw, + sfx_skeswg, + sfx_pldeth, + sfx_pdiehi, + sfx_podth1, + sfx_podth2, + sfx_podth3, + sfx_bgdth1, + sfx_bgdth2, + sfx_sgtdth, + sfx_cacdth, + sfx_skldth, + sfx_brsdth, + sfx_cybdth, + sfx_spidth, + sfx_bspdth, + sfx_vildth, + sfx_kntdth, + sfx_pedth, + sfx_skedth, + sfx_posact, + sfx_bgact, + sfx_dmact, + sfx_bspact, + sfx_bspwlk, + sfx_vilact, + sfx_noway, + sfx_barexp, + sfx_punch, + sfx_hoof, + sfx_metal, + sfx_chgun, + sfx_tink, + sfx_bdopn, + sfx_bdcls, + sfx_itmbk, + sfx_flame, + sfx_flamst, + sfx_getpow, + sfx_bospit, + sfx_boscub, + sfx_bossit, + sfx_bospn, + sfx_bosdth, + sfx_manatk, + sfx_mandth, + sfx_sssit, + sfx_ssdth, + sfx_keenpn, + sfx_keendt, + sfx_skeact, + sfx_skesit, + sfx_skeatk, + sfx_radio, + +#ifdef DOGS + /* killough 11/98: dog sounds */ + sfx_dgsit, + sfx_dgatk, + sfx_dgact, + sfx_dgdth, + sfx_dgpain, +#endif + + NUMSFX +} sfxenum_t; + +#endif diff --git a/src/st_lib.c b/src/st_lib.c new file mode 100644 index 0000000..87504d4 --- /dev/null +++ b/src/st_lib.c @@ -0,0 +1,374 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * The status bar widget code. + * + *-----------------------------------------------------------------------------*/ + +#include "doomdef.h" +#include "doomstat.h" +#include "v_video.h" +#include "w_wad.h" +#include "st_stuff.h" +#include "st_lib.h" +#include "r_main.h" +#include "lprintf.h" + +int sts_always_red; //jff 2/18/98 control to disable status color changes +int sts_pct_always_gray; // killough 2/21/98: always gray %'s? bug or feature? + +// +// STlib_init() +// +void STlib_init(void) +{ + // cph - no longer hold STMINUS pointer +} + +// +// STlib_initNum() +// +// Initializes an st_number_t widget +// +// Passed the widget, its position, the patches for the digits, a pointer +// to the value displayed, a pointer to the on/off control, and the width +// Returns nothing +// +void STlib_initNum +( st_number_t* n, + int x, + int y, + const patchnum_t* pl, + int* num, + boolean* on, + int width ) +{ + n->x = x; + n->y = y; + n->oldnum = 0; + n->width = width; + n->num = num; + n->on = on; + n->p = pl; +} + +/* + * STlib_drawNum() + * + * A fairly efficient way to draw a number based on differences from the + * old number. + * + * Passed a st_number_t widget, a color range for output, and a flag + * indicating whether refresh is needed. + * Returns nothing + * + * jff 2/16/98 add color translation to digit output + * cphipps 10/99 - const pointer to colour trans table, made function static + */ +static void STlib_drawNum +( st_number_t* n, + int cm, + boolean refresh ) +{ + + int numdigits = n->width; + int num = *n->num; + + int w = n->p[0].width; + int h = n->p[0].height; + int x = n->x; + + int neg; + + // leban 1/20/99: + // strange that somebody went through all the work to draw only the + // differences, and then went and constantly redrew all the numbers. + // return without drawing if the number didn't change and the bar + // isn't refreshing. + if(n->oldnum == num && !refresh) + return; + + // CPhipps - compact some code, use num instead of *n->num + if ((neg = (n->oldnum = num) < 0)) + { + if (numdigits == 2 && num < -9) + num = -9; + else if (numdigits == 3 && num < -99) + num = -99; + + num = -num; + } + + // clear the area + x = n->x - numdigits*w; + +#ifdef RANGECHECK + if (n->y - ST_Y < 0) + I_Error("STlib_drawNum: n->y - ST_Y < 0"); +#endif + + V_CopyRect(x, n->y - ST_Y, BG, w*numdigits, h, x, n->y, FG, VPT_STRETCH); + + // if non-number, do not draw it + if (num == 1994) + return; + + x = n->x; + + //jff 2/16/98 add color translation to digit output + // in the special case of 0, you draw 0 + if (!num) + // CPhipps - patch drawing updated, reformatted + V_DrawNumPatch(x - w, n->y, FG, n->p[0].lumpnum, cm, + (((cm!=CR_DEFAULT) && !sts_always_red) ? VPT_TRANS : VPT_NONE) | VPT_STRETCH); + + // draw the new number + //jff 2/16/98 add color translation to digit output + while (num && numdigits--) { + // CPhipps - patch drawing updated, reformatted + x -= w; + V_DrawNumPatch(x, n->y, FG, n->p[num % 10].lumpnum, cm, + (((cm!=CR_DEFAULT) && !sts_always_red) ? VPT_TRANS : VPT_NONE) | VPT_STRETCH); + num /= 10; + } + + // draw a minus sign if necessary + //jff 2/16/98 add color translation to digit output + // cph - patch drawing updated, load by name instead of acquiring pointer earlier + if (neg) + V_DrawNamePatch(x - w, n->y, FG, "STTMINUS", cm, + (((cm!=CR_DEFAULT) && !sts_always_red) ? VPT_TRANS : VPT_NONE) | VPT_STRETCH); +} + +/* + * STlib_updateNum() + * + * Draws a number conditionally based on the widget's enable + * + * Passed a number widget, the output color range, and a refresh flag + * Returns nothing + * + * jff 2/16/98 add color translation to digit output + * cphipps 10/99 - make that pointer const + */ +void STlib_updateNum +( st_number_t* n, + int cm, + boolean refresh ) +{ + if (*n->on) STlib_drawNum(n, cm, refresh); +} + +// +// STlib_initPercent() +// +// Initialize a st_percent_t number with percent sign widget +// +// Passed a st_percent_t widget, the position, the digit patches, a pointer +// to the number to display, a pointer to the enable flag, and patch +// for the percent sign. +// Returns nothing. +// +void STlib_initPercent +( st_percent_t* p, + int x, + int y, + const patchnum_t* pl, + int* num, + boolean* on, + const patchnum_t* percent ) +{ + STlib_initNum(&p->n, x, y, pl, num, on, 3); + p->p = percent; +} + +/* + * STlib_updatePercent() + * + * Draws a number/percent conditionally based on the widget's enable + * + * Passed a precent widget, the output color range, and a refresh flag + * Returns nothing + * + * jff 2/16/98 add color translation to digit output + * cphipps - const for pointer to the colour translation table + */ + +void STlib_updatePercent +( st_percent_t* per, + int cm, + int refresh ) +{ + if (*per->n.on && (refresh || (per->n.oldnum != *per->n.num))) { + // killough 2/21/98: fix percents not updated; + /* CPhipps - make %'s only be updated if number changed */ + // CPhipps - patch drawing updated + V_DrawNumPatch(per->n.x, per->n.y, FG, per->p->lumpnum, + sts_pct_always_gray ? CR_GRAY : cm, + (sts_always_red ? VPT_NONE : VPT_TRANS) | VPT_STRETCH); + } + + STlib_updateNum(&per->n, cm, refresh); +} + +// +// STlib_initMultIcon() +// +// Initialize a st_multicon_t widget, used for a multigraphic display +// like the status bar's keys. +// +// Passed a st_multicon_t widget, the position, the graphic patches, a pointer +// to the numbers representing what to display, and pointer to the enable flag +// Returns nothing. +// +void STlib_initMultIcon +( st_multicon_t* i, + int x, + int y, + const patchnum_t* il, + int* inum, + boolean* on ) +{ + i->x = x; + i->y = y; + i->oldinum = -1; + i->inum = inum; + i->on = on; + i->p = il; +} + +// +// STlib_updateMultIcon() +// +// Draw a st_multicon_t widget, used for a multigraphic display +// like the status bar's keys. Displays each when the control +// numbers change or refresh is true +// +// Passed a st_multicon_t widget, and a refresh flag +// Returns nothing. +// +void STlib_updateMultIcon +( st_multicon_t* mi, + boolean refresh ) +{ + int w; + int h; + int x; + int y; + + if (*mi->on && (mi->oldinum != *mi->inum || refresh)) + { + if (mi->oldinum != -1) + { + x = mi->x - mi->p[mi->oldinum].leftoffset; + y = mi->y - mi->p[mi->oldinum].topoffset; + w = mi->p[mi->oldinum].width; + h = mi->p[mi->oldinum].height; + +#ifdef RANGECHECK + if (y - ST_Y < 0) + I_Error("STlib_updateMultIcon: y - ST_Y < 0"); +#endif + + V_CopyRect(x, y-ST_Y, BG, w, h, x, y, FG, VPT_STRETCH); + } + if (*mi->inum != -1) // killough 2/16/98: redraw only if != -1 + V_DrawNumPatch(mi->x, mi->y, FG, mi->p[*mi->inum].lumpnum, CR_DEFAULT, VPT_STRETCH); + mi->oldinum = *mi->inum; + } +} + +// +// STlib_initBinIcon() +// +// Initialize a st_binicon_t widget, used for a multinumber display +// like the status bar's weapons, that are present or not. +// +// Passed a st_binicon_t widget, the position, the digit patches, a pointer +// to the flags representing what is displayed, and pointer to the enable flag +// Returns nothing. +// +void STlib_initBinIcon +( st_binicon_t* b, + int x, + int y, + const patchnum_t* i, + boolean* val, + boolean* on ) +{ + b->x = x; + b->y = y; + b->oldval = 0; + b->val = val; + b->on = on; + b->p = i; +} + +// +// STlib_updateBinIcon() +// +// DInitialize a st_binicon_t widget, used for a multinumber display +// like the status bar's weapons, that are present or not. +// +// Draw a st_binicon_t widget, used for a multinumber display +// like the status bar's weapons that are present or not. Displays each +// when the control flag changes or refresh is true +// +// Passed a st_binicon_t widget, and a refresh flag +// Returns nothing. +// +void STlib_updateBinIcon +( st_binicon_t* bi, + boolean refresh ) +{ + int x; + int y; + int w; + int h; + + if (*bi->on && (bi->oldval != *bi->val || refresh)) + { + x = bi->x - bi->p->leftoffset; + y = bi->y - bi->p->topoffset; + w = bi->p->width; + h = bi->p->height; + +#ifdef RANGECHECK + if (y - ST_Y < 0) + I_Error("STlib_updateBinIcon: y - ST_Y < 0"); +#endif + + if (*bi->val) + V_DrawNumPatch(bi->x, bi->y, FG, bi->p->lumpnum, CR_DEFAULT, VPT_STRETCH); + else + V_CopyRect(x, y-ST_Y, BG, w, h, x, y, FG, VPT_STRETCH); + + bi->oldval = *bi->val; + } +} diff --git a/src/st_lib.h b/src/st_lib.h new file mode 100644 index 0000000..769a75e --- /dev/null +++ b/src/st_lib.h @@ -0,0 +1,209 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * The status bar widget definitions and prototypes + * + *-----------------------------------------------------------------------------*/ + +#ifndef __STLIB__ +#define __STLIB__ + +// We are referring to patches. +#include "r_defs.h" +#include "v_video.h" // color ranges + +// +// Background and foreground screen numbers +// +#define BG 4 +#define FG 0 + +// +// Typedefs of widgets +// + +// Number widget + +typedef struct +{ + // upper right-hand corner + // of the number (right-justified) + int x; + int y; + + // max # of digits in number + int width; + + // last number value + int oldnum; + + // pointer to current value + int* num; + + // pointer to boolean stating + // whether to update number + boolean* on; + + // list of patches for 0-9 + const patchnum_t* p; + + // user data + int data; +} st_number_t; + +// Percent widget ("child" of number widget, +// or, more precisely, contains a number widget.) +typedef struct +{ + // number information + st_number_t n; + + // percent sign graphic + const patchnum_t* p; +} st_percent_t; + +// Multiple Icon widget +typedef struct +{ + // center-justified location of icons + int x; + int y; + + // last icon number + int oldinum; + + // pointer to current icon + int* inum; + + // pointer to boolean stating + // whether to update icon + boolean* on; + + // list of icons + const patchnum_t* p; + + // user data + int data; + +} st_multicon_t; + +// Binary Icon widget + +typedef struct +{ + // center-justified location of icon + int x; + int y; + + // last icon value + boolean oldval; + + // pointer to current icon status + boolean* val; + + // pointer to boolean + // stating whether to update icon + boolean* on; + + const patchnum_t* p; // icon + int data; // user data +} st_binicon_t; + +// +// Widget creation, access, and update routines +// + +// Initializes widget library. +// More precisely, initialize STMINUS, +// everything else is done somewhere else. +// +void STlib_init(void); + +// Number widget routines +void STlib_initNum +( st_number_t* n, + int x, + int y, + const patchnum_t* pl, + int* num, + boolean* on, + int width ); + +void STlib_updateNum +( st_number_t* n, + int cm, + boolean refresh ); + + +// Percent widget routines +void STlib_initPercent +( st_percent_t* p, + int x, + int y, + const patchnum_t* pl, + int* num, + boolean* on, + const patchnum_t* percent ); + + +void STlib_updatePercent +( st_percent_t* per, + int cm, + int refresh ); + + +// Multiple Icon widget routines +void STlib_initMultIcon +( st_multicon_t* mi, + int x, + int y, + const patchnum_t* il, + int* inum, + boolean* on ); + + +void STlib_updateMultIcon +( st_multicon_t* mi, + boolean refresh ); + +// Binary Icon widget routines + +void STlib_initBinIcon +( st_binicon_t* b, + int x, + int y, + const patchnum_t* i, + boolean* val, + boolean* on ); + +void STlib_updateBinIcon +( st_binicon_t* bi, + boolean refresh ); + +#endif diff --git a/src/st_stuff.c b/src/st_stuff.c new file mode 100644 index 0000000..ac0391b --- /dev/null +++ b/src/st_stuff.c @@ -0,0 +1,1160 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Status bar code. + * Does the face/direction indicator animatin. + * Does palette indicators as well (red pain/berserk, bright pickup) + * + *-----------------------------------------------------------------------------*/ + +#include "doomdef.h" +#include "doomstat.h" +#include "m_random.h" +#include "i_video.h" +#include "w_wad.h" +#include "st_stuff.h" +#include "st_lib.h" +#include "r_main.h" +#include "am_map.h" +#include "m_cheat.h" +#include "s_sound.h" +#include "sounds.h" +#include "dstrings.h" +#include "r_draw.h" + +// +// STATUS BAR DATA +// + +// Palette indices. +// For damage/bonus red-/gold-shifts +#define STARTREDPALS 1 +#define STARTBONUSPALS 9 +#define NUMREDPALS 8 +#define NUMBONUSPALS 4 +// Radiation suit, green shift. +#define RADIATIONPAL 13 + +// Location of status bar +#define ST_X 0 +#define ST_X2 104 + +// proff 08/18/98: Changed for high-res +#define ST_FX (ST_X+143) +#define ST_FY (ST_Y+1) +//#define ST_FX 143 +//#define ST_FY 169 + +// Should be set to patch width +// for tall numbers later on +#define ST_TALLNUMWIDTH (tallnum[0]->width) + +// Number of status faces. +#define ST_NUMPAINFACES 5 +#define ST_NUMSTRAIGHTFACES 3 +#define ST_NUMTURNFACES 2 +#define ST_NUMSPECIALFACES 3 + +#define ST_FACESTRIDE \ + (ST_NUMSTRAIGHTFACES+ST_NUMTURNFACES+ST_NUMSPECIALFACES) + +#define ST_NUMEXTRAFACES 2 + +#define ST_NUMFACES \ + (ST_FACESTRIDE*ST_NUMPAINFACES+ST_NUMEXTRAFACES) + +#define ST_TURNOFFSET (ST_NUMSTRAIGHTFACES) +#define ST_OUCHOFFSET (ST_TURNOFFSET + ST_NUMTURNFACES) +#define ST_EVILGRINOFFSET (ST_OUCHOFFSET + 1) +#define ST_RAMPAGEOFFSET (ST_EVILGRINOFFSET + 1) +#define ST_GODFACE (ST_NUMPAINFACES*ST_FACESTRIDE) +#define ST_DEADFACE (ST_GODFACE+1) + +// proff 08/18/98: Changed for high-res +#define ST_FACESX (ST_X+143) +#define ST_FACESY (ST_Y) +//#define ST_FACESX 143 +//#define ST_FACESY 168 + +#define ST_EVILGRINCOUNT (2*TICRATE) +#define ST_STRAIGHTFACECOUNT (TICRATE/2) +#define ST_TURNCOUNT (1*TICRATE) +#define ST_OUCHCOUNT (1*TICRATE) +#define ST_RAMPAGEDELAY (2*TICRATE) + +#define ST_MUCHPAIN 20 + +// Location and size of statistics, +// justified according to widget type. +// Problem is, within which space? STbar? Screen? +// Note: this could be read in by a lump. +// Problem is, is the stuff rendered +// into a buffer, +// or into the frame buffer? +// I dunno, why don't you go and find out!!! killough + +// AMMO number pos. +#define ST_AMMOWIDTH 3 +// proff 08/18/98: Changed for high-res +#define ST_AMMOX (ST_X+44) +#define ST_AMMOY (ST_Y+3) +//#define ST_AMMOX 44 +//#define ST_AMMOY 171 + +// HEALTH number pos. +#define ST_HEALTHWIDTH 3 +// proff 08/18/98: Changed for high-res +#define ST_HEALTHX (ST_X+90) +#define ST_HEALTHY (ST_Y+3) +//#define ST_HEALTHX 90 +//#define ST_HEALTHY 171 + +// Weapon pos. +// proff 08/18/98: Changed for high-res +#define ST_ARMSX (ST_X+111) +#define ST_ARMSY (ST_Y+4) +#define ST_ARMSBGX (ST_X+104) +#define ST_ARMSBGY (ST_Y) +//#define ST_ARMSX 111 +//#define ST_ARMSY 172 +//#define ST_ARMSBGX 104 +//#define ST_ARMSBGY 168 +#define ST_ARMSXSPACE 12 +#define ST_ARMSYSPACE 10 + +// Frags pos. +// proff 08/18/98: Changed for high-res +#define ST_FRAGSX (ST_X+138) +#define ST_FRAGSY (ST_Y+3) +//#define ST_FRAGSX 138 +//#define ST_FRAGSY 171 +#define ST_FRAGSWIDTH 2 + +// ARMOR number pos. +#define ST_ARMORWIDTH 3 +// proff 08/18/98: Changed for high-res +#define ST_ARMORX (ST_X+221) +#define ST_ARMORY (ST_Y+3) +//#define ST_ARMORX 221 +//#define ST_ARMORY 171 + +// Key icon positions. +#define ST_KEY0WIDTH 8 +#define ST_KEY0HEIGHT 5 +// proff 08/18/98: Changed for high-res +#define ST_KEY0X (ST_X+239) +#define ST_KEY0Y (ST_Y+3) +//#define ST_KEY0X 239 +//#define ST_KEY0Y 171 +#define ST_KEY1WIDTH ST_KEY0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_KEY1X (ST_X+239) +#define ST_KEY1Y (ST_Y+13) +//#define ST_KEY1X 239 +//#define ST_KEY1Y 181 +#define ST_KEY2WIDTH ST_KEY0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_KEY2X (ST_X+239) +#define ST_KEY2Y (ST_Y+23) +//#define ST_KEY2X 239 +//#define ST_KEY2Y 191 + +// Ammunition counter. +#define ST_AMMO0WIDTH 3 +#define ST_AMMO0HEIGHT 6 +// proff 08/18/98: Changed for high-res +#define ST_AMMO0X (ST_X+288) +#define ST_AMMO0Y (ST_Y+5) +//#define ST_AMMO0X 288 +//#define ST_AMMO0Y 173 +#define ST_AMMO1WIDTH ST_AMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_AMMO1X (ST_X+288) +#define ST_AMMO1Y (ST_Y+11) +//#define ST_AMMO1X 288 +//#define ST_AMMO1Y 179 +#define ST_AMMO2WIDTH ST_AMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_AMMO2X (ST_X+288) +#define ST_AMMO2Y (ST_Y+23) +//#define ST_AMMO2X 288 +//#define ST_AMMO2Y 191 +#define ST_AMMO3WIDTH ST_AMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_AMMO3X (ST_X+288) +#define ST_AMMO3Y (ST_Y+17) +//#define ST_AMMO3X 288 +//#define ST_AMMO3Y 185 + +// Indicate maximum ammunition. +// Only needed because backpack exists. +#define ST_MAXAMMO0WIDTH 3 +#define ST_MAXAMMO0HEIGHT 5 +// proff 08/18/98: Changed for high-res +#define ST_MAXAMMO0X (ST_X+314) +#define ST_MAXAMMO0Y (ST_Y+5) +//#define ST_MAXAMMO0X 314 +//#define ST_MAXAMMO0Y 173 +#define ST_MAXAMMO1WIDTH ST_MAXAMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_MAXAMMO1X (ST_X+314) +#define ST_MAXAMMO1Y (ST_Y+11) +//#define ST_MAXAMMO1X 314 +//#define ST_MAXAMMO1Y 179 +#define ST_MAXAMMO2WIDTH ST_MAXAMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_MAXAMMO2X (ST_X+314) +#define ST_MAXAMMO2Y (ST_Y+23) +//#define ST_MAXAMMO2X 314 +//#define ST_MAXAMMO2Y 191 +#define ST_MAXAMMO3WIDTH ST_MAXAMMO0WIDTH +// proff 08/18/98: Changed for high-res +#define ST_MAXAMMO3X (ST_X+314) +#define ST_MAXAMMO3Y (ST_Y+17) +//#define ST_MAXAMMO3X 314 +//#define ST_MAXAMMO3Y 185 + +// killough 2/8/98: weapon info position macros UNUSED, removed here + +// main player in game +static player_t *plyr; + +// ST_Start() has just been called +static boolean st_firsttime; + +// used to execute ST_Init() only once +static int veryfirsttime = 1; + +// CPhipps - no longer do direct PLAYPAL handling here + +// used for timing +static unsigned int st_clock; + +// used for making messages go away +static int st_msgcounter=0; + +// used when in chat +static st_chatstateenum_t st_chatstate; + +// whether in automap or first-person +static st_stateenum_t st_gamestate; + +// whether left-side main status bar is active +static boolean st_statusbaron; + +// whether status bar chat is active +static boolean st_chat; + +// value of st_chat before message popped up +static boolean st_oldchat; + +// whether chat window has the cursor on +static boolean st_cursoron; + +// !deathmatch +static boolean st_notdeathmatch; + +// !deathmatch && st_statusbaron +static boolean st_armson; + +// !deathmatch +static boolean st_fragson; + +// 0-9, tall numbers +static patchnum_t tallnum[10]; + +// tall % sign +static patchnum_t tallpercent; + +// 0-9, short, yellow (,different!) numbers +static patchnum_t shortnum[10]; + +// 3 key-cards, 3 skulls, 3 card/skull combos +// jff 2/24/98 extend number of patches by three skull/card combos +static patchnum_t keys[NUMCARDS+3]; + +// face status patches +static patchnum_t faces[ST_NUMFACES]; + +// face background +static patchnum_t faceback; // CPhipps - single background, translated for different players + +//e6y: status bar background +static patchnum_t stbarbg; + +// main bar right +static patchnum_t armsbg; + +// weapon ownership patches +static patchnum_t arms[6][2]; + +// ready-weapon widget +static st_number_t w_ready; + +//jff 2/16/98 status color change levels +int ammo_red; // ammo percent less than which status is red +int ammo_yellow; // ammo percent less is yellow more green +int health_red; // health amount less than which status is red +int health_yellow; // health amount less than which status is yellow +int health_green; // health amount above is blue, below is green +int armor_red; // armor amount less than which status is red +int armor_yellow; // armor amount less than which status is yellow +int armor_green; // armor amount above is blue, below is green + + // in deathmatch only, summary of frags stats +static st_number_t w_frags; + +// health widget +static st_percent_t w_health; + +// arms background +static st_binicon_t w_armsbg; + +// weapon ownership widgets +static st_multicon_t w_arms[6]; + +// face status widget +static st_multicon_t w_faces; + +// keycard widgets +static st_multicon_t w_keyboxes[3]; + +// armor widget +static st_percent_t w_armor; + +// ammo widgets +static st_number_t w_ammo[4]; + +// max ammo widgets +static st_number_t w_maxammo[4]; + + // number of frags so far in deathmatch +static int st_fragscount; + +// used to use appopriately pained face +static int st_oldhealth = -1; + +// used for evil grin +static boolean oldweaponsowned[NUMWEAPONS]; + + // count until face changes +static int st_facecount = 0; + +// current face index, used by w_faces +static int st_faceindex = 0; + +// holds key-type for each key box on bar +static int keyboxes[3]; + +// a random number per tick +static int st_randomnumber; + +extern char *mapnames[]; + +// +// STATUS BAR CODE +// + +static void ST_Stop(void); + +static void ST_refreshBackground(void) +{ + int y=0; + + if (st_statusbaron) + { + // proff 05/17/2000: draw to the frontbuffer in OpenGL + if (V_GetMode() == VID_MODEGL) + y=ST_Y; + V_DrawNumPatch(ST_X, y, BG, stbarbg.lumpnum, CR_DEFAULT, VPT_STRETCH); + if (st_armson) + V_DrawNumPatch(ST_ARMSBGX, y, BG, armsbg.lumpnum, CR_DEFAULT, VPT_STRETCH); + + // killough 3/7/98: make face background change with displayplayer + if (netgame) + { + V_DrawNumPatch(ST_FX, y, BG, faceback.lumpnum, + displayplayer ? CR_LIMIT+displayplayer : CR_DEFAULT, + displayplayer ? (VPT_TRANS | VPT_STRETCH) : VPT_STRETCH); + } + V_CopyRect(ST_X, y, BG, ST_SCALED_WIDTH, ST_SCALED_HEIGHT, ST_X, ST_SCALED_Y, FG, VPT_NONE); + } +} + + +// Respond to keyboard input events, +// intercept cheats. +boolean ST_Responder(event_t *ev) +{ + // Filter automap on/off. + if (ev->type == ev_keyup && (ev->data1 & 0xffff0000) == AM_MSGHEADER) + { + switch(ev->data1) + { + case AM_MSGENTERED: + st_gamestate = AutomapState; + st_firsttime = true; + break; + + case AM_MSGEXITED: + st_gamestate = FirstPersonState; + break; + } + } + else // if a user keypress... + if (ev->type == ev_keydown) // Try cheat responder in m_cheat.c + return M_FindCheats(ev->data1); // killough 4/17/98, 5/2/98 + return false; +} + +static int ST_calcPainOffset(void) +{ + static int lastcalc; + static int oldhealth = -1; + int health = plyr->health > 100 ? 100 : plyr->health; + + if (health != oldhealth) + { + lastcalc = ST_FACESTRIDE * (((100 - health) * ST_NUMPAINFACES) / 101); + oldhealth = health; + } + return lastcalc; +} + +// +// This is a not-very-pretty routine which handles +// the face states and their timing. +// the precedence of expressions is: +// dead > evil grin > turned head > straight ahead +// + +static void ST_updateFaceWidget(void) +{ + int i; + angle_t badguyangle; + angle_t diffang; + static int lastattackdown = -1; + static int priority = 0; + boolean doevilgrin; + + if (priority < 10) + { + // dead + if (!plyr->health) + { + priority = 9; + st_faceindex = ST_DEADFACE; + st_facecount = 1; + } + } + + if (priority < 9) + { + if (plyr->bonuscount) + { + // picking up bonus + doevilgrin = false; + + for (i=0;iweaponowned[i]) + { + doevilgrin = true; + oldweaponsowned[i] = plyr->weaponowned[i]; + } + } + if (doevilgrin) + { + // evil grin if just picked up weapon + priority = 8; + st_facecount = ST_EVILGRINCOUNT; + st_faceindex = ST_calcPainOffset() + ST_EVILGRINOFFSET; + } + } + + } + + if (priority < 8) + { + if (plyr->damagecount && plyr->attacker && plyr->attacker != plyr->mo) + { + // being attacked + priority = 7; + + // haleyjd 10/12/03: classic DOOM problem of missing OUCH face + // was due to inversion of this test: + // if(plyr->health - st_oldhealth > ST_MUCHPAIN) + if(st_oldhealth - plyr->health > ST_MUCHPAIN) + { + st_facecount = ST_TURNCOUNT; + st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET; + } + else + { + badguyangle = R_PointToAngle2(plyr->mo->x, + plyr->mo->y, + plyr->attacker->x, + plyr->attacker->y); + + if (badguyangle > plyr->mo->angle) + { + // whether right or left + diffang = badguyangle - plyr->mo->angle; + i = diffang > ANG180; + } + else + { + // whether left or right + diffang = plyr->mo->angle - badguyangle; + i = diffang <= ANG180; + } // confusing, aint it? + + + st_facecount = ST_TURNCOUNT; + st_faceindex = ST_calcPainOffset(); + + if (diffang < ANG45) + { + // head-on + st_faceindex += ST_RAMPAGEOFFSET; + } + else if (i) + { + // turn face right + st_faceindex += ST_TURNOFFSET; + } + else + { + // turn face left + st_faceindex += ST_TURNOFFSET+1; + } + } + } + } + + if (priority < 7) + { + // getting hurt because of your own damn stupidity + if (plyr->damagecount) + { + // haleyjd 10/12/03: classic DOOM problem of missing OUCH face + // was due to inversion of this test: + // if(plyr->health - st_oldhealth > ST_MUCHPAIN) + if(st_oldhealth - plyr->health > ST_MUCHPAIN) + { + priority = 7; + st_facecount = ST_TURNCOUNT; + st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET; + } + else + { + priority = 6; + st_facecount = ST_TURNCOUNT; + st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET; + } + + } + + } + + if (priority < 6) + { + // rapid firing + if (plyr->attackdown) + { + if (lastattackdown==-1) + lastattackdown = ST_RAMPAGEDELAY; + else if (!--lastattackdown) + { + priority = 5; + st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET; + st_facecount = 1; + lastattackdown = 1; + } + } + else + lastattackdown = -1; + + } + + if (priority < 5) + { + // invulnerability + if ((plyr->cheats & CF_GODMODE) + || plyr->powers[pw_invulnerability]) + { + priority = 4; + + st_faceindex = ST_GODFACE; + st_facecount = 1; + + } + + } + + // look left or look right if the facecount has timed out + if (!st_facecount) + { + st_faceindex = ST_calcPainOffset() + (st_randomnumber % 3); + st_facecount = ST_STRAIGHTFACECOUNT; + priority = 0; + } + + st_facecount--; + +} + +int sts_traditional_keys; // killough 2/28/98: traditional status bar keys + +static void ST_updateWidgets(void) +{ + static int largeammo = 1994; // means "n/a" + int i; + + // must redirect the pointer if the ready weapon has changed. + // if (w_ready.data != plyr->readyweapon) + // { + if (weaponinfo[plyr->readyweapon].ammo == am_noammo) + w_ready.num = &largeammo; + else + w_ready.num = &plyr->ammo[weaponinfo[plyr->readyweapon].ammo]; + //{ + // static int tic=0; + // static int dir=-1; + // if (!(tic&15)) + // plyr->ammo[weaponinfo[plyr->readyweapon].ammo]+=dir; + // if (plyr->ammo[weaponinfo[plyr->readyweapon].ammo] == -100) + // dir = 1; + // tic++; + // } + w_ready.data = plyr->readyweapon; + + // if (*w_ready.on) + // STlib_updateNum(&w_ready, true); + // refresh weapon change + // } + + // update keycard multiple widgets + for (i=0;i<3;i++) + { + keyboxes[i] = plyr->cards[i] ? i : -1; + + //jff 2/24/98 select double key + //killough 2/28/98: preserve traditional keys by config option + + if (plyr->cards[i+3]) + keyboxes[i] = keyboxes[i]==-1 || sts_traditional_keys ? i+3 : i+6; + } + + // refresh everything if this is him coming back to life + ST_updateFaceWidget(); + + // used by the w_armsbg widget + st_notdeathmatch = !deathmatch; + + // used by w_arms[] widgets + st_armson = st_statusbaron && !deathmatch; + + // used by w_frags widget + st_fragson = deathmatch && st_statusbaron; + st_fragscount = 0; + + for (i=0 ; ifrags[i]; + else + st_fragscount -= plyr->frags[i]; + } + + // get rid of chat window if up because of message + if (!--st_msgcounter) + st_chat = st_oldchat; + +} + +void ST_Ticker(void) +{ + st_clock++; + st_randomnumber = M_Random(); + ST_updateWidgets(); + st_oldhealth = plyr->health; +} + +int st_palette = 0; + +static void ST_doPaletteStuff(void) +{ + int palette; + int cnt = plyr->damagecount; + + if (plyr->powers[pw_strength]) + { + // slowly fade the berzerk out + int bzc = 12 - (plyr->powers[pw_strength]>>6); + if (bzc > cnt) + cnt = bzc; + } + + if (cnt) + { + palette = (cnt+7)>>3; + if (palette >= NUMREDPALS) + palette = NUMREDPALS-1; + + /* cph 2006/08/06 - if in the menu, reduce the red tint - navigating to + * load a game can be tricky if the screen is all red */ + if (menuactive) palette >>=1; + + palette += STARTREDPALS; + } + else + if (plyr->bonuscount) + { + palette = (plyr->bonuscount+7)>>3; + if (palette >= NUMBONUSPALS) + palette = NUMBONUSPALS-1; + palette += STARTBONUSPALS; + } + else + if (plyr->powers[pw_ironfeet] > 4*32 || plyr->powers[pw_ironfeet] & 8) + palette = RADIATIONPAL; + else + palette = 0; + + if (palette != st_palette) { + V_SetPalette(st_palette = palette); // CPhipps - use new palette function + + // have to redraw the entire status bar when the palette changes + // in truecolor modes - POPE + if (V_GetMode() == VID_MODE15 || V_GetMode() == VID_MODE16 || V_GetMode() == VID_MODE32) + st_firsttime = true; + } +} + +static void ST_drawWidgets(boolean refresh) +{ + int i; + + // used by w_arms[] widgets + st_armson = st_statusbaron && !deathmatch; + + // used by w_frags widget + st_fragson = deathmatch && st_statusbaron; + + //jff 2/16/98 make color of ammo depend on amount + if (*w_ready.num*100 < ammo_red*plyr->maxammo[weaponinfo[w_ready.data].ammo]) + STlib_updateNum(&w_ready, CR_RED, refresh); + else + if (*w_ready.num*100 < + ammo_yellow*plyr->maxammo[weaponinfo[w_ready.data].ammo]) + STlib_updateNum(&w_ready, CR_GOLD, refresh); + else + STlib_updateNum(&w_ready, CR_GREEN, refresh); + + for (i=0;i<4;i++) + { + STlib_updateNum(&w_ammo[i], CR_DEFAULT, refresh); //jff 2/16/98 no xlation + STlib_updateNum(&w_maxammo[i], CR_DEFAULT, refresh); + } + + //jff 2/16/98 make color of health depend on amount + if (*w_health.n.numweaponowned[i]; + + for (i=0;i<3;i++) + keyboxes[i] = -1; + + STlib_init(); +} + +static void ST_createWidgets(void) +{ + int i; + + // ready weapon ammo + STlib_initNum(&w_ready, + ST_AMMOX, + ST_AMMOY, + tallnum, + &plyr->ammo[weaponinfo[plyr->readyweapon].ammo], + &st_statusbaron, + ST_AMMOWIDTH ); + + // the last weapon type + w_ready.data = plyr->readyweapon; + + // health percentage + STlib_initPercent(&w_health, + ST_HEALTHX, + ST_HEALTHY, + tallnum, + &plyr->health, + &st_statusbaron, + &tallpercent); + + // arms background + STlib_initBinIcon(&w_armsbg, + ST_ARMSBGX, + ST_ARMSBGY, + &armsbg, + &st_notdeathmatch, + &st_statusbaron); + + // weapons owned + for(i=0;i<6;i++) + { + STlib_initMultIcon(&w_arms[i], + ST_ARMSX+(i%3)*ST_ARMSXSPACE, + ST_ARMSY+(i/3)*ST_ARMSYSPACE, + arms[i], (int *) &plyr->weaponowned[i+1], + &st_armson); + } + + // frags sum + STlib_initNum(&w_frags, + ST_FRAGSX, + ST_FRAGSY, + tallnum, + &st_fragscount, + &st_fragson, + ST_FRAGSWIDTH); + + // faces + STlib_initMultIcon(&w_faces, + ST_FACESX, + ST_FACESY, + faces, + &st_faceindex, + &st_statusbaron); + + // armor percentage - should be colored later + STlib_initPercent(&w_armor, + ST_ARMORX, + ST_ARMORY, + tallnum, + &plyr->armorpoints, + &st_statusbaron, &tallpercent); + + // keyboxes 0-2 + STlib_initMultIcon(&w_keyboxes[0], + ST_KEY0X, + ST_KEY0Y, + keys, + &keyboxes[0], + &st_statusbaron); + + STlib_initMultIcon(&w_keyboxes[1], + ST_KEY1X, + ST_KEY1Y, + keys, + &keyboxes[1], + &st_statusbaron); + + STlib_initMultIcon(&w_keyboxes[2], + ST_KEY2X, + ST_KEY2Y, + keys, + &keyboxes[2], + &st_statusbaron); + + // ammo count (all four kinds) + STlib_initNum(&w_ammo[0], + ST_AMMO0X, + ST_AMMO0Y, + shortnum, + &plyr->ammo[0], + &st_statusbaron, + ST_AMMO0WIDTH); + + STlib_initNum(&w_ammo[1], + ST_AMMO1X, + ST_AMMO1Y, + shortnum, + &plyr->ammo[1], + &st_statusbaron, + ST_AMMO1WIDTH); + + STlib_initNum(&w_ammo[2], + ST_AMMO2X, + ST_AMMO2Y, + shortnum, + &plyr->ammo[2], + &st_statusbaron, + ST_AMMO2WIDTH); + + STlib_initNum(&w_ammo[3], + ST_AMMO3X, + ST_AMMO3Y, + shortnum, + &plyr->ammo[3], + &st_statusbaron, + ST_AMMO3WIDTH); + + // max ammo count (all four kinds) + STlib_initNum(&w_maxammo[0], + ST_MAXAMMO0X, + ST_MAXAMMO0Y, + shortnum, + &plyr->maxammo[0], + &st_statusbaron, + ST_MAXAMMO0WIDTH); + + STlib_initNum(&w_maxammo[1], + ST_MAXAMMO1X, + ST_MAXAMMO1Y, + shortnum, + &plyr->maxammo[1], + &st_statusbaron, + ST_MAXAMMO1WIDTH); + + STlib_initNum(&w_maxammo[2], + ST_MAXAMMO2X, + ST_MAXAMMO2Y, + shortnum, + &plyr->maxammo[2], + &st_statusbaron, + ST_MAXAMMO2WIDTH); + + STlib_initNum(&w_maxammo[3], + ST_MAXAMMO3X, + ST_MAXAMMO3Y, + shortnum, + &plyr->maxammo[3], + &st_statusbaron, + ST_MAXAMMO3WIDTH); +} + +static boolean st_stopped = true; + +void ST_Start(void) +{ + if (!st_stopped) + ST_Stop(); + ST_initData(); + ST_createWidgets(); + st_stopped = false; +} + +static void ST_Stop(void) +{ + if (st_stopped) + return; + V_SetPalette(0); + st_stopped = true; +} + +void ST_Init(void) +{ + veryfirsttime = 0; + ST_loadData(); +} diff --git a/src/st_stuff.h b/src/st_stuff.h new file mode 100644 index 0000000..83ba51e --- /dev/null +++ b/src/st_stuff.h @@ -0,0 +1,102 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Status bar code. + * Does the face/direction indicator animatin. + * Does palette indicators as well (red pain/berserk, bright pickup) + * + *-----------------------------------------------------------------------------*/ + +#ifndef __STSTUFF_H__ +#define __STSTUFF_H__ + +#include "doomtype.h" +#include "d_event.h" + +// Size of statusbar. +// Now sensitive for scaling. + +// proff 08/18/98: Changed for high-res +#define ST_HEIGHT 32 +#define ST_WIDTH 320 +#define ST_Y (200 - ST_HEIGHT) +#define ST_SCALED_HEIGHT (ST_HEIGHT*SCREENHEIGHT/200) +#define ST_SCALED_WIDTH SCREENWIDTH +#define ST_SCALED_Y (SCREENHEIGHT - ST_SCALED_HEIGHT) + +// +// STATUS BAR +// + +// Called by main loop. +boolean ST_Responder(event_t* ev); + +// Called by main loop. +void ST_Ticker(void); + +// Called by main loop. +void ST_Drawer(boolean st_statusbaron, boolean refresh); + +// Called when the console player is spawned on each level. +void ST_Start(void); + +// Called by startup code. +void ST_Init(void); + +// States for status bar code. +typedef enum +{ + AutomapState, + FirstPersonState +} st_stateenum_t; + +// States for the chat code. +typedef enum +{ + StartChatState, + WaitDestState, + GetChatState +} st_chatstateenum_t; + +// killough 5/2/98: moved from m_misc.c: + +extern int health_red; // health amount less than which status is red +extern int health_yellow; // health amount less than which status is yellow +extern int health_green; // health amount above is blue, below is green +extern int armor_red; // armor amount less than which status is red +extern int armor_yellow; // armor amount less than which status is yellow +extern int armor_green; // armor amount above is blue, below is green +extern int ammo_red; // ammo percent less than which status is red +extern int ammo_yellow; // ammo percent less is yellow more green +extern int sts_always_red;// status numbers do not change colors +extern int sts_pct_always_gray;// status percents do not change colors +extern int sts_traditional_keys; // display keys the traditional way + +extern int st_palette; // cph 2006/04/06 - make palette visible +#endif diff --git a/src/tables.c b/src/tables.c new file mode 100644 index 0000000..2cf59e1 --- /dev/null +++ b/src/tables.c @@ -0,0 +1,128 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Lookup tables. + * Do not try to look them up :-). + * In the order of appearance: + * + * int finetangent[4096] - Tangens LUT. + * Should work with BAM fairly well (12 of 16bit, + * effectively, by shifting). + * + * int finesine[10240] - Sine lookup. + * Guess what, serves as cosine, too. + * Remarkable thing is, how to use BAMs with this? + * + * int tantoangle[2049] - ArcTan LUT, + * maps tan(angle) to angle fast. Gotta search. + * + *----------------------------------------------------------------------------- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "w_wad.h" +#include "tables.h" + +// killough 5/3/98: reformatted + +int SlopeDiv(unsigned num, unsigned den) +{ + unsigned ans; + + if (den < 512) + return SLOPERANGE; + ans = (num<<3)/(den>>8); + return ans <= SLOPERANGE ? ans : SLOPERANGE; +} + +fixed_t finetangent[4096]; + +//const fixed_t *const finecosine = &finesine[FINEANGLES/4]; + +fixed_t finesine[10240]; + +angle_t tantoangle[2049]; + +#include "m_swap.h" +#include "lprintf.h" + +// R_LoadTrigTables +// Load trig tables from a wad file lump +// CPhipps 24/12/98 - fix endianness (!) +// +void R_LoadTrigTables(void) +{ + int lump; + { + lump = (W_CheckNumForName)("SINETABL",ns_prboom); + if (lump == -1) I_Error("Failed to locate trig tables"); + if (W_LumpLength(lump) != sizeof(finesine)) + I_Error("R_LoadTrigTables: Invalid SINETABL"); + W_ReadLump(lump,(unsigned char*)finesine); + } + { + lump = (W_CheckNumForName)("TANGTABL",ns_prboom); + if (lump == -1) I_Error("Failed to locate trig tables"); + if (W_LumpLength(lump) != sizeof(finetangent)) + I_Error("R_LoadTrigTables: Invalid TANGTABL"); + W_ReadLump(lump,(unsigned char*)finetangent); + } + { + lump = (W_CheckNumForName)("TANTOANG",ns_prboom); + if (lump == -1) I_Error("Failed to locate trig tables"); + if (W_LumpLength(lump) != sizeof(tantoangle)) + I_Error("R_LoadTrigTables: Invalid TANTOANG"); + W_ReadLump(lump,(unsigned char*)tantoangle); + } + // Endianness correction - might still be non-portable, but is fast where possible + { + size_t n; + lprintf(LO_INFO, "Endianness..."); + + // This test doesn't assume the endianness of the tables, but deduces them from + // en entry. I hope this is portable. + if ((10 < finesine[1]) && (finesine[1] < 100)) { + lprintf(LO_INFO, "ok."); + return; // Endianness is correct + } + + // Must correct endianness of every long loaded (!) +#define CORRECT_TABLE_ENDIAN(tbl) \ + for (n = 0; nname; p++) + *p->map = W_CacheLumpName(p->name); +} + +// +// V_CopyRect +// +// Copies a source rectangle in a screen buffer to a destination +// rectangle in another screen buffer. Source origin in srcx,srcy, +// destination origin in destx,desty, common size in width and height. +// Source buffer specfified by srcscrn, destination buffer by destscrn. +// +// Marks the destination rectangle on the screen dirty. +// +// No return. +// +static void FUNC_V_CopyRect(int srcx, int srcy, int srcscrn, int width, + int height, int destx, int desty, int destscrn, + enum patch_translation_e flags) +{ + byte *src; + byte *dest; + + if (flags & VPT_STRETCH) + { + srcx=srcx*SCREENWIDTH/320; + srcy=srcy*SCREENHEIGHT/200; + width=width*SCREENWIDTH/320; + height=height*SCREENHEIGHT/200; + destx=destx*SCREENWIDTH/320; + desty=desty*SCREENHEIGHT/200; + } + +#ifdef RANGECHECK + if (srcx<0 + ||srcx+width >SCREENWIDTH + || srcy<0 + || srcy+height>SCREENHEIGHT + ||destx<0||destx+width >SCREENWIDTH + || desty<0 + || desty+height>SCREENHEIGHT) + I_Error ("V_CopyRect: Bad arguments"); +#endif + + src = screens[srcscrn].data+screens[srcscrn].byte_pitch*srcy+srcx*V_GetPixelDepth(); + dest = screens[destscrn].data+screens[destscrn].byte_pitch*desty+destx*V_GetPixelDepth(); + + for ( ; height>0 ; height--) + { + memcpy (dest, src, width*V_GetPixelDepth()); + src += screens[srcscrn].byte_pitch; + dest += screens[destscrn].byte_pitch; + } +} + +/* + * V_DrawBackground tiles a 64x64 patch over the entire screen, providing the + * background for the Help and Setup screens, and plot text betwen levels. + * cphipps - used to have M_DrawBackground, but that was used the framebuffer + * directly, so this is my code from the equivalent function in f_finale.c + */ +static void FUNC_V_DrawBackground(const char* flatname, int scrn) +{ + /* erase the entire screen to a tiled background */ + const byte *src; + int x,y; + int width,height; + int lump; + + // killough 4/17/98: + src = W_CacheLumpNum(lump = firstflat + R_FlatNumForName(flatname)); + + /* V_DrawBlock(0, 0, scrn, 64, 64, src, 0); */ + width = height = 64; + if (V_GetMode() == VID_MODE8) { + byte *dest = screens[scrn].data; + + while (height--) { + memcpy (dest, src, width); + src += width; + dest += screens[scrn].byte_pitch; + } + } else if (V_GetMode() == VID_MODE15) { + unsigned short *dest = (unsigned short *)screens[scrn].data; + + while (height--) { + int i; + for (i=0; itopoffset; + x -= patch->leftoffset; + + // CPhipps - auto-no-stretch if not high-res + if (flags & VPT_STRETCH) + if ((SCREENWIDTH==320) && (SCREENHEIGHT==200)) + flags &= ~VPT_STRETCH; + + // CPhipps - null translation pointer => no translation + if (!trans) + flags &= ~VPT_TRANS; + + if (V_GetMode() == VID_MODE8 && !(flags & VPT_STRETCH)) { + int col; + byte *desttop = screens[scrn].data+y*screens[scrn].byte_pitch+x*V_GetPixelDepth(); + unsigned int w = patch->width; + + if (y<0 || y+patch->height > ((flags & VPT_STRETCH) ? 200 : SCREENHEIGHT)) { + // killough 1/19/98: improved error message: + lprintf(LO_WARN, "V_DrawMemPatch8: Patch (%d,%d)-(%d,%d) exceeds LFB in vertical direction (horizontal is clipped)\n" + "Bad V_DrawMemPatch8 (flags=%u)", x, y, x+patch->width, y+patch->height, flags); + return; + } + + w--; // CPhipps - note: w = width-1 now, speeds up flipping + + for (col=0 ; (unsigned int)col<=w ; desttop++, col++, x++) { + int i; + const int colindex = (flags & VPT_FLIP) ? (w - col) : (col); + const rcolumn_t *column = R_GetPatchColumn(patch, colindex); + + if (x < 0) + continue; + if (x >= SCREENWIDTH) + break; + + // step through the posts in a column + for (i=0; inumPosts; i++) { + const rpost_t *post = &column->posts[i]; + // killough 2/21/98: Unrolled and performance-tuned + + const byte *source = column->pixels + post->topdelta; + byte *dest = desttop + post->topdelta*screens[scrn].byte_pitch; + int count = post->length; + + if (!(flags & VPT_TRANS)) { + if ((count-=4)>=0) + do { + register byte s0,s1; + s0 = source[0]; + s1 = source[1]; + dest[0] = s0; + dest[screens[scrn].byte_pitch] = s1; + dest += screens[scrn].byte_pitch*2; + s0 = source[2]; + s1 = source[3]; + source += 4; + dest[0] = s0; + dest[screens[scrn].byte_pitch] = s1; + dest += screens[scrn].byte_pitch*2; + } while ((count-=4)>=0); + if (count+=4) + do { + *dest = *source++; + dest += screens[scrn].byte_pitch; + } while (--count); + } else { + // CPhipps - merged translation code here + if ((count-=4)>=0) + do { + register byte s0,s1; + s0 = source[0]; + s1 = source[1]; + s0 = trans[s0]; + s1 = trans[s1]; + dest[0] = s0; + dest[screens[scrn].byte_pitch] = s1; + dest += screens[scrn].byte_pitch*2; + s0 = source[2]; + s1 = source[3]; + s0 = trans[s0]; + s1 = trans[s1]; + source += 4; + dest[0] = s0; + dest[screens[scrn].byte_pitch] = s1; + dest += screens[scrn].byte_pitch*2; + } while ((count-=4)>=0); + if (count+=4) + do { + *dest = trans[*source++]; + dest += screens[scrn].byte_pitch; + } while (--count); + } + } + } + } + else { + // CPhipps - move stretched patch drawing code here + // - reformat initialisers, move variables into inner blocks + + int col; + int w = (patch->width << 16) - 1; // CPhipps - -1 for faster flipping + int left, right, top, bottom; + int DX = (SCREENWIDTH<<16) / 320; + int DXI = (320<<16) / SCREENWIDTH; + int DY = (SCREENHEIGHT<<16) / 200; + int DYI = (200<<16) / SCREENHEIGHT; + R_DrawColumn_f colfunc; + draw_column_vars_t dcvars; + draw_vars_t olddrawvars = drawvars; + + R_SetDefaultDrawColumnVars(&dcvars); + + drawvars.byte_topleft = screens[scrn].data; + drawvars.short_topleft = (unsigned short *)screens[scrn].data; + drawvars.int_topleft = (unsigned int *)screens[scrn].data; + drawvars.byte_pitch = screens[scrn].byte_pitch; + drawvars.short_pitch = screens[scrn].short_pitch; + drawvars.int_pitch = screens[scrn].int_pitch; + + if (!(flags & VPT_STRETCH)) { + DX = 1 << 16; + DXI = 1 << 16; + DY = 1 << 16; + DYI = 1 << 16; + } + + if (flags & VPT_TRANS) { + colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLATED, drawvars.filterpatch, RDRAW_FILTER_NONE); + dcvars.translation = trans; + } else { + colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, drawvars.filterpatch, RDRAW_FILTER_NONE); + } + + left = ( x * DX ) >> FRACBITS; + top = ( y * DY ) >> FRACBITS; + right = ( (x + patch->width) * DX ) >> FRACBITS; + bottom = ( (y + patch->height) * DY ) >> FRACBITS; + + dcvars.texheight = patch->height; + dcvars.iscale = DYI; + dcvars.drawingmasked = MAX(patch->width, patch->height) > 8; + dcvars.edgetype = drawvars.patch_edges; + + if (drawvars.filterpatch == RDRAW_FILTER_LINEAR) { + // bias the texture u coordinate + if (patch->isNotTileable) + col = -(FRACUNIT>>1); + else + col = (patch->width<>1); + } + else { + col = 0; + } + + for (dcvars.x=left; dcvars.x>16): (col>>16); + const rcolumn_t *column = R_GetPatchColumn(patch, colindex); + const rcolumn_t *prevcolumn = R_GetPatchColumn(patch, colindex-1); + const rcolumn_t *nextcolumn = R_GetPatchColumn(patch, colindex+1); + + // ignore this column if it's to the left of our clampRect + if (dcvars.x < 0) + continue; + if (dcvars.x >= SCREENWIDTH) + break; + + dcvars.texu = ((flags & VPT_FLIP) ? ((patch->width<width<numPosts; i++) { + const rpost_t *post = &column->posts[i]; + int yoffset = 0; + + dcvars.yl = (((y + post->topdelta) * DY)>>FRACBITS); + dcvars.yh = (((y + post->topdelta + post->length) * DY - (FRACUNIT>>1))>>FRACBITS); + dcvars.edgeslope = post->slope; + + if ((dcvars.yh < 0) || (dcvars.yh < top)) + continue; + if ((dcvars.yl >= SCREENHEIGHT) || (dcvars.yl >= bottom)) + continue; + + if (dcvars.yh >= bottom) { + dcvars.yh = bottom-1; + dcvars.edgeslope &= ~RDRAW_EDGESLOPE_BOT_MASK; + } + if (dcvars.yh >= SCREENHEIGHT) { + dcvars.yh = SCREENHEIGHT-1; + dcvars.edgeslope &= ~RDRAW_EDGESLOPE_BOT_MASK; + } + + if (dcvars.yl < 0) { + yoffset = 0-dcvars.yl; + dcvars.yl = 0; + dcvars.edgeslope &= ~RDRAW_EDGESLOPE_TOP_MASK; + } + if (dcvars.yl < top) { + yoffset = top-dcvars.yl; + dcvars.yl = top; + dcvars.edgeslope &= ~RDRAW_EDGESLOPE_TOP_MASK; + } + + dcvars.source = column->pixels + post->topdelta + yoffset; + dcvars.prevsource = prevcolumn ? prevcolumn->pixels + post->topdelta + yoffset: dcvars.source; + dcvars.nextsource = nextcolumn ? nextcolumn->pixels + post->topdelta + yoffset: dcvars.source; + + dcvars.texturemid = -((dcvars.yl-centery)*dcvars.iscale); + + colfunc(&dcvars); + } + } + + R_ResetColumnBuffer(); + drawvars = olddrawvars; + } +} + +// CPhipps - some simple, useful wrappers for that function, for drawing patches from wads + +// CPhipps - GNU C only suppresses generating a copy of a function if it is +// static inline; other compilers have different behaviour. +// This inline is _only_ for the function below + +static void FUNC_V_DrawNumPatch(int x, int y, int scrn, int lump, + int cm, enum patch_translation_e flags) +{ + V_DrawMemPatch(x, y, scrn, R_CachePatchNum(lump), cm, flags); + R_UnlockPatchNum(lump); +} + +unsigned short *V_Palette15 = NULL; +unsigned short *V_Palette16 = NULL; +unsigned int *V_Palette32 = NULL; +static unsigned short *Palettes15 = NULL; +static unsigned short *Palettes16 = NULL; +static unsigned int *Palettes32 = NULL; +static int currentPaletteIndex = 0; + +// +// V_UpdateTrueColorPalette +// +void V_UpdateTrueColorPalette(video_mode_t mode) { + int i, w, p; + byte r,g,b; + int nr,ng,nb; + float t; + int paletteNum = (V_GetMode() == VID_MODEGL ? 0 : currentPaletteIndex); + static int usegammaOnLastPaletteGeneration = -1; + + int pplump = W_GetNumForName("PLAYPAL"); + int gtlump = (W_CheckNumForName)("GAMMATBL",ns_prboom); + const byte *pal = W_CacheLumpNum(pplump); + // opengl doesn't use the gamma + const byte *const gtable = + (const byte *)W_CacheLumpNum(gtlump) + + (V_GetMode() == VID_MODEGL ? 0 : 256*(usegamma)) + ; + + int numPals = W_LumpLength(pplump) / (3*256); + const float dontRoundAbove = 220; + float roundUpR, roundUpG, roundUpB; + + if (usegammaOnLastPaletteGeneration != usegamma) { + if (Palettes15) free(Palettes15); + if (Palettes16) free(Palettes16); + if (Palettes32) free(Palettes32); + Palettes15 = NULL; + Palettes16 = NULL; + Palettes32 = NULL; + usegammaOnLastPaletteGeneration = usegamma; + } + + if (mode == VID_MODE32) { + if (!Palettes32) { + // set int palette + Palettes32 = (int*)malloc(numPals*256*sizeof(int)*VID_NUMCOLORWEIGHTS); + for (p=0; p dontRoundAbove) ? 0 : 0.5f; + roundUpG = (g > dontRoundAbove) ? 0 : 0.5f; + roundUpB = (b > dontRoundAbove) ? 0 : 0.5f; + + for (w=0; w dontRoundAbove) ? 0 : 0.5f; + roundUpG = (g > dontRoundAbove) ? 0 : 0.5f; + roundUpB = (b > dontRoundAbove) ? 0 : 0.5f; + + for (w=0; w>3)*t+roundUpR); + ng = (int)((g>>2)*t+roundUpG); + nb = (int)((b>>3)*t+roundUpB); + Palettes16[((p*256+i)*VID_NUMCOLORWEIGHTS)+w] = ( + (nr<<11) | (ng<<5) | nb + ); + } + } + } + } + V_Palette16 = Palettes16 + paletteNum*256*VID_NUMCOLORWEIGHTS; + } + else if (mode == VID_MODE15) { + if (!Palettes15) { + // set short palette + Palettes15 = (short*)malloc(numPals*256*sizeof(short)*VID_NUMCOLORWEIGHTS); + for (p=0; p dontRoundAbove) ? 0 : 0.5f; + roundUpG = (g > dontRoundAbove) ? 0 : 0.5f; + roundUpB = (b > dontRoundAbove) ? 0 : 0.5f; + + for (w=0; w>3)*t+roundUpR); + ng = (int)((g>>3)*t+roundUpG); + nb = (int)((b>>3)*t+roundUpB); + Palettes15[((p*256+i)*VID_NUMCOLORWEIGHTS)+w] = ( + (nr<<10) | (ng<<5) | nb + ); + } + } + } + } + V_Palette15 = Palettes15 + paletteNum*256*VID_NUMCOLORWEIGHTS; + } + + W_UnlockLumpNum(pplump); + W_UnlockLumpNum(gtlump); +} + + +//--------------------------------------------------------------------------- +// V_DestroyTrueColorPalette +//--------------------------------------------------------------------------- +static void V_DestroyTrueColorPalette(video_mode_t mode) { + if (mode == VID_MODE15) { + if (Palettes15) free(Palettes15); + Palettes15 = NULL; + V_Palette15 = NULL; + } + if (mode == VID_MODE16) { + if (Palettes16) free(Palettes16); + Palettes16 = NULL; + V_Palette16 = NULL; + } + if (mode == VID_MODE32) { + if (Palettes32) free(Palettes32); + Palettes32 = NULL; + V_Palette32 = NULL; + } +} + +void V_DestroyUnusedTrueColorPalettes(void) { + if (V_GetMode() != VID_MODE15) V_DestroyTrueColorPalette(VID_MODE15); + if (V_GetMode() != VID_MODE16) V_DestroyTrueColorPalette(VID_MODE16); + if (V_GetMode() != VID_MODE32) V_DestroyTrueColorPalette(VID_MODE32); +} + +// +// V_SetPalette +// +// CPhipps - New function to set the palette to palette number pal. +// Handles loading of PLAYPAL and calls I_SetPalette + +void V_SetPalette(int pal) +{ + currentPaletteIndex = pal; + + if (V_GetMode() == VID_MODEGL) { +#ifdef GL_DOOM + gld_SetPalette(pal); +#endif + } else { + I_SetPalette(pal); + if (V_GetMode() == VID_MODE15 || V_GetMode() == VID_MODE16 || V_GetMode() == VID_MODE32) { + // V_SetPalette can be called as part of the gamma setting before + // we've loaded any wads, which prevents us from reading the palette - POPE + if (W_CheckNumForName("PLAYPAL") >= 0) { + V_UpdateTrueColorPalette(V_GetMode()); + } + } + } +} + +// +// V_FillRect +// +// CPhipps - New function to fill a rectangle with a given colour +static void V_FillRect8(int scrn, int x, int y, int width, int height, byte colour) +{ + byte* dest = screens[scrn].data + x + y*screens[scrn].byte_pitch; + while (height--) { + memset(dest, colour, width); + dest += screens[scrn].byte_pitch; + } +} + +static void V_FillRect15(int scrn, int x, int y, int width, int height, byte colour) +{ + unsigned short* dest = (unsigned short *)screens[scrn].data + x + y*screens[scrn].short_pitch; + int w; + short c = VID_PAL15(colour, VID_COLORWEIGHTMASK); + while (height--) { + for (w=0; wa.x, fl->a.y, fl->b.x, fl->b.y, color); +} +#endif + +static void NULL_FillRect(int scrn, int x, int y, int width, int height, byte colour) {} +static void NULL_CopyRect(int srcx, int srcy, int srcscrn, int width, int height, int destx, int desty, int destscrn, enum patch_translation_e flags) {} +static void NULL_DrawBackground(const char *flatname, int n) {} +static void NULL_DrawNumPatch(int x, int y, int scrn, int lump, int cm, enum patch_translation_e flags) {} +static void NULL_DrawBlock(int x, int y, int scrn, int width, int height, const byte *src, enum patch_translation_e flags) {} +static void NULL_PlotPixel(int scrn, int x, int y, byte color) {} +static void NULL_DrawLine(fline_t* fl, int color) {} + +const char *default_videomode; +static video_mode_t current_videomode = VID_MODE8; + +V_CopyRect_f V_CopyRect = NULL_CopyRect; +V_FillRect_f V_FillRect = NULL_FillRect; +V_DrawNumPatch_f V_DrawNumPatch = NULL_DrawNumPatch; +V_DrawBackground_f V_DrawBackground = NULL_DrawBackground; +V_PlotPixel_f V_PlotPixel = NULL_PlotPixel; +V_DrawLine_f V_DrawLine = NULL_DrawLine; + +// +// V_InitMode +// +void V_InitMode(video_mode_t mode) { +#ifndef GL_DOOM + if (mode == VID_MODEGL) + mode = VID_MODE8; +#endif + switch (mode) { + case VID_MODE8: + lprintf(LO_INFO, "V_InitMode: using 8 bit video mode\n"); + V_CopyRect = FUNC_V_CopyRect; + V_FillRect = V_FillRect8; + V_DrawNumPatch = FUNC_V_DrawNumPatch; + V_DrawBackground = FUNC_V_DrawBackground; + V_PlotPixel = V_PlotPixel8; + V_DrawLine = WRAP_V_DrawLine; + current_videomode = VID_MODE8; + break; + case VID_MODE15: + lprintf(LO_INFO, "V_InitMode: using 15 bit video mode\n"); + V_CopyRect = FUNC_V_CopyRect; + V_FillRect = V_FillRect15; + V_DrawNumPatch = FUNC_V_DrawNumPatch; + V_DrawBackground = FUNC_V_DrawBackground; + V_PlotPixel = V_PlotPixel15; + V_DrawLine = WRAP_V_DrawLine; + current_videomode = VID_MODE15; + break; + case VID_MODE16: + lprintf(LO_INFO, "V_InitMode: using 16 bit video mode\n"); + V_CopyRect = FUNC_V_CopyRect; + V_FillRect = V_FillRect16; + V_DrawNumPatch = FUNC_V_DrawNumPatch; + V_DrawBackground = FUNC_V_DrawBackground; + V_PlotPixel = V_PlotPixel16; + V_DrawLine = WRAP_V_DrawLine; + current_videomode = VID_MODE16; + break; + case VID_MODE32: + lprintf(LO_INFO, "V_InitMode: using 32 bit video mode\n"); + V_CopyRect = FUNC_V_CopyRect; + V_FillRect = V_FillRect32; + V_DrawNumPatch = FUNC_V_DrawNumPatch; + V_DrawBackground = FUNC_V_DrawBackground; + V_PlotPixel = V_PlotPixel32; + V_DrawLine = WRAP_V_DrawLine; + current_videomode = VID_MODE32; + break; +#ifdef GL_DOOM + case VID_MODEGL: + lprintf(LO_INFO, "V_InitMode: using OpenGL video mode\n"); + V_CopyRect = WRAP_gld_CopyRect; + V_FillRect = WRAP_gld_FillRect; + V_DrawNumPatch = WRAP_gld_DrawNumPatch; + V_DrawBackground = WRAP_gld_DrawBackground; + V_PlotPixel = V_PlotPixelGL; + V_DrawLine = WRAP_gld_DrawLine; + current_videomode = VID_MODEGL; + break; +#endif + } + R_FilterInit(); +} + +// +// V_GetMode +// +video_mode_t V_GetMode(void) { + return current_videomode; +} + +// +// V_GetModePixelDepth +// +int V_GetModePixelDepth(video_mode_t mode) { + switch (mode) { + case VID_MODE8: return 1; + case VID_MODE15: return 2; + case VID_MODE16: return 2; + case VID_MODE32: return 4; + default: return 0; + } +} + +// +// V_GetNumPixelBits +// +int V_GetNumPixelBits(void) { + switch (current_videomode) { + case VID_MODE8: return 8; + case VID_MODE15: return 15; + case VID_MODE16: return 16; + case VID_MODE32: return 32; + default: return 0; + } +} + +// +// V_GetPixelDepth +// +int V_GetPixelDepth(void) { + return V_GetModePixelDepth(current_videomode); +} + +// +// V_AllocScreen +// +void V_AllocScreen(screeninfo_t *scrn) { + if (!scrn->not_on_heap) + if ((scrn->byte_pitch * scrn->height) > 0) + scrn->data = malloc(scrn->byte_pitch*scrn->height); +} + +// +// V_AllocScreens +// +void V_AllocScreens(void) { + int i; + + for (i=0; inot_on_heap) { + free(scrn->data); + scrn->data = NULL; + } +} + +// +// V_FreeScreens +// +void V_FreeScreens(void) { + int i; + + for (i=0; ia.x < 0 || fl->a.x >= SCREENWIDTH + || fl->a.y < 0 || fl->a.y >= SCREENHEIGHT + || fl->b.x < 0 || fl->b.x >= SCREENWIDTH + || fl->b.y < 0 || fl->b.y >= SCREENHEIGHT + ) + { + //jff 8/3/98 use logical output routine + lprintf(LO_DEBUG, "fuck %d \r", fuck++); + return; + } +#endif + +#define PUTDOT(xx,yy,cc) V_PlotPixel(0,xx,yy,(byte)cc) + + dx = fl->b.x - fl->a.x; + ax = 2 * (dx<0 ? -dx : dx); + sx = dx<0 ? -1 : 1; + + dy = fl->b.y - fl->a.y; + ay = 2 * (dy<0 ? -dy : dy); + sy = dy<0 ? -1 : 1; + + x = fl->a.x; + y = fl->a.y; + + if (ax > ay) + { + d = ay - ax/2; + while (1) + { + PUTDOT(x,y,color); + if (x == fl->b.x) return; + if (d>=0) + { + y += sy; + d -= ax; + } + x += sx; + d += ay; + } + } + else + { + d = ax - ay/2; + while (1) + { + PUTDOT(x, y, color); + if (y == fl->b.y) return; + if (d >= 0) + { + x += sx; + d -= ay; + } + y += sy; + d += ax; + } + } +} diff --git a/src/v_video.h b/src/v_video.h new file mode 100644 index 0000000..76cfaa2 --- /dev/null +++ b/src/v_video.h @@ -0,0 +1,207 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Gamma correction LUT. + * Color range translation support + * Functions to draw patches (by post) directly to screen. + * Functions to blit a block to the screen. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __V_VIDEO__ +#define __V_VIDEO__ + +#include "doomtype.h" +#include "doomdef.h" +// Needed because we are refering to patches. +#include "r_data.h" + +// +// VIDEO +// + +#define CENTERY (SCREENHEIGHT/2) + +// Screen 0 is the screen updated by I_Update screen. +// Screen 1 is an extra buffer. + +// array of pointers to color translation tables +extern const byte *colrngs[]; + +// symbolic indices into color translation table pointer array +typedef enum +{ + CR_BRICK, //0 + CR_TAN, //1 + CR_GRAY, //2 + CR_GREEN, //3 + CR_BROWN, //4 + CR_GOLD, //5 + CR_RED, //6 + CR_BLUE, //7 + CR_ORANGE, //8 + CR_YELLOW, //9 + CR_BLUE2, //10 // proff + CR_LIMIT //11 //jff 2/27/98 added for range check +} crange_idx_e; +//jff 1/16/98 end palette color range additions + +#define CR_DEFAULT CR_RED /* default value for out of range colors */ + +typedef struct { + byte *data; // pointer to the screen content + boolean not_on_heap; // if set, no malloc or free is preformed and + // data never set to NULL. Used i.e. with SDL doublebuffer. + int width; // the width of the surface + int height; // the height of the surface, used when mallocing + int byte_pitch; // tha actual width of one line, used when mallocing + int short_pitch; // tha actual width of one line, used when mallocing + int int_pitch; // tha actual width of one line, used when mallocing +} screeninfo_t; + +#define NUM_SCREENS 6 +extern screeninfo_t screens[NUM_SCREENS]; +extern int usegamma; + +// Varying bit-depth support -POPE +// +// For bilinear filtering, each palette color is pre-weighted and put in a +// table for fast blending operations. These macros decide how many weights +// to create for each color. The lower the number, the lower the blend +// accuracy, which can produce very bad artifacts in texture filtering. +#define VID_NUMCOLORWEIGHTS 64 +#define VID_COLORWEIGHTMASK (VID_NUMCOLORWEIGHTS-1) +#define VID_COLORWEIGHTBITS 6 + +// Palettes for converting from 8 bit color to 16 and 32 bit. Also +// contains the weighted versions of each palette color for filtering +// operations +extern unsigned short *V_Palette15; +extern unsigned short *V_Palette16; +extern unsigned int *V_Palette32; + +#define VID_PAL15(color, weight) V_Palette15[ (color)*VID_NUMCOLORWEIGHTS + (weight) ] +#define VID_PAL16(color, weight) V_Palette16[ (color)*VID_NUMCOLORWEIGHTS + (weight) ] +#define VID_PAL32(color, weight) V_Palette32[ (color)*VID_NUMCOLORWEIGHTS + (weight) ] + +// The available bit-depth modes +typedef enum { + VID_MODE8, + VID_MODE15, + VID_MODE16, + VID_MODE32, + VID_MODEGL, + VID_MODEMAX +} video_mode_t; + +extern const char *default_videomode; + +void V_InitMode(video_mode_t mode); + +// video mode query interface +video_mode_t V_GetMode(void); +int V_GetModePixelDepth(video_mode_t mode); +int V_GetNumPixelBits(void); +int V_GetPixelDepth(void); + +//jff 4/24/98 loads color translation lumps +void V_InitColorTranslation(void); + +// Allocates buffer screens, call before R_Init. +void V_Init (void); + +// V_CopyRect +typedef void (*V_CopyRect_f)(int srcx, int srcy, int srcscrn, + int width, int height, + int destx, int desty, int destscrn, + enum patch_translation_e flags); +extern V_CopyRect_f V_CopyRect; + +// V_FillRect +typedef void (*V_FillRect_f)(int scrn, int x, int y, + int width, int height, byte colour); +extern V_FillRect_f V_FillRect; + +// CPhipps - patch drawing +// Consolidated into the 3 really useful functions: + +// V_DrawNumPatch - Draws the patch from lump num +typedef void (*V_DrawNumPatch_f)(int x, int y, int scrn, + int lump, int cm, + enum patch_translation_e flags); +extern V_DrawNumPatch_f V_DrawNumPatch; + +// V_DrawNamePatch - Draws the patch from lump "name" +#define V_DrawNamePatch(x,y,s,n,t,f) V_DrawNumPatch(x,y,s,W_GetNumForName(n),t,f) + +/* cph - + * Functions to return width & height of a patch. + * Doesn't really belong here, but is often used in conjunction with + * this code. + */ +#define V_NamePatchWidth(name) R_NumPatchWidth(W_GetNumForName(name)) +#define V_NamePatchHeight(name) R_NumPatchHeight(W_GetNumForName(name)) + +/* cphipps 10/99: function to tile a flat over the screen */ +typedef void (*V_DrawBackground_f)(const char* flatname, int scrn); +extern V_DrawBackground_f V_DrawBackground; + +void V_DestroyUnusedTrueColorPalettes(void); +// CPhipps - function to set the palette to palette number pal. +void V_SetPalette(int pal); + +// CPhipps - function to plot a pixel + +// V_PlotPixel +typedef void (*V_PlotPixel_f)(int,int,int,byte); +extern V_PlotPixel_f V_PlotPixel; + +typedef struct +{ + int x, y; +} fpoint_t; + +typedef struct +{ + fpoint_t a, b; +} fline_t; + +// V_DrawLine +typedef void (*V_DrawLine_f)(fline_t* fl, int color); +extern V_DrawLine_f V_DrawLine; + +void V_AllocScreen(screeninfo_t *scrn); +void V_AllocScreens(); +void V_FreeScreen(screeninfo_t *scrn); +void V_FreeScreens(); + +#ifdef GL_DOOM +#include "gl_struct.h" +#endif +#endif diff --git a/src/version.c b/src/version.c new file mode 100644 index 0000000..142017e --- /dev/null +++ b/src/version.c @@ -0,0 +1,38 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Date stamp + * + *----------------------------------------------------------------------------- + */ + + +#include "version.h" + +const char version_date[] = __DATE__; diff --git a/src/version.h b/src/version.h new file mode 100644 index 0000000..f7ad161 --- /dev/null +++ b/src/version.h @@ -0,0 +1,40 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Doom version indicators. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __DOOMVERSION__ +#define __DOOMVERSION__ + +extern const char version_date[]; + +#endif diff --git a/src/w_mmap.c b/src/w_mmap.c new file mode 100644 index 0000000..51094b4 --- /dev/null +++ b/src/w_mmap.c @@ -0,0 +1,333 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 2001 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Transparent access to data in WADs using mmap + * + *----------------------------------------------------------------------------- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#include +#endif + +#include "doomstat.h" +#include "doomtype.h" + +#ifdef __GNUG__ +#pragma implementation "w_wad.h" +#endif +#include "w_wad.h" +#include "z_zone.h" +#include "lprintf.h" +#include "i_system.h" + +static struct { + void *cache; +#ifdef TIMEDIAG + int locktic; +#endif + int locks; +} *cachelump; + +#ifdef HEAPDUMP +void W_PrintLump(FILE* fp, void* p) { + int i; + for (i=0; i 0) + lprintf(LO_DEBUG, "%8.8s %6u %2d %6d\n", lumpinfo[i].name, + W_LumpLength(i), cachelump[i].locks, gametic - cachelump[i].locktic); + } +} +#endif + +#ifdef _WIN32 +typedef struct { + HANDLE hnd; + OFSTRUCT fileinfo; + HANDLE hnd_map; + void *data; +} mmap_info_t; + +mmap_info_t *mapped_wad; + +void W_DoneCache(void) +{ + size_t i; + + if (cachelump) { + free(cachelump); + cachelump = NULL; + } + + if (!mapped_wad) + return; + for (i=0; i=numwadfiles)) + I_Error("W_InitCache: wad_index out of range"); +#endif + if (!mapped_wad[wad_index].data) + { + mapped_wad[wad_index].hnd = + (HANDLE)OpenFile( + wadfiles[wad_index].name, + &mapped_wad[wad_index].fileinfo, + OF_READ + ); + if (mapped_wad[wad_index].hnd==(HANDLE)HFILE_ERROR) + I_Error("W_InitCache: OpenFile for memory mapping failed (LastError %i)",GetLastError()); + mapped_wad[wad_index].hnd_map = + CreateFileMapping( + mapped_wad[wad_index].hnd, + NULL, + PAGE_READONLY, + 0, + 0, + NULL + ); + if (mapped_wad[wad_index].hnd_map==NULL) + I_Error("W_InitCache: CreateFileMapping for memory mapping failed (LastError %i)",GetLastError()); + mapped_wad[wad_index].data = + MapViewOfFile( + mapped_wad[wad_index].hnd_map, + FILE_MAP_READ, + 0, + 0, + 0 + ); + if (mapped_wad[wad_index].hnd_map==NULL) + I_Error("W_InitCache: MapViewOfFile for memory mapping failed (LastError %i)",GetLastError()); + } + } + } +} + +const void* W_CacheLumpNum(int lump) +{ + int wad_index = (int)(lumpinfo[lump].wadfile-wadfiles); +#ifdef RANGECHECK + if ((wad_index<0)||((size_t)wad_index>=numwadfiles)) + I_Error("W_CacheLumpNum: wad_index out of range"); + if ((unsigned)lump >= (unsigned)numlumps) + I_Error ("W_CacheLumpNum: %i >= numlumps",lump); +#endif + if (!lumpinfo[lump].wadfile) + return NULL; + return (void*)((unsigned char *)mapped_wad[wad_index].data+lumpinfo[lump].position); +} + +#else + +void ** mapped_wad; + +void W_InitCache(void) +{ + int maxfd = 0; + // set up caching + cachelump = calloc(numlumps, sizeof *cachelump); + if (!cachelump) + I_Error ("W_Init: Couldn't allocate lumpcache"); + +#ifdef TIMEDIAG + atexit(W_ReportLocks); +#endif + + { + int i; + for (i=0; ihandle > maxfd) maxfd = lumpinfo[i].wadfile->handle; + } + mapped_wad = calloc(maxfd+1,sizeof *mapped_wad); + { + int i; + for (i=0; ihandle; + if (!mapped_wad[fd]) + if ((mapped_wad[fd] = mmap(NULL,I_Filelength(fd),PROT_READ,MAP_SHARED,fd,0)) == MAP_FAILED) + I_Error("W_InitCache: failed to mmap"); + } + } + } +} + +void W_DoneCache(void) +{ + { + int i; + for (i=0; ihandle; + if (mapped_wad[fd]) { + if (munmap(mapped_wad[fd],I_Filelength(fd))) + I_Error("W_DoneCache: failed to munmap"); + mapped_wad[fd] = NULL; + } + } + } + free(mapped_wad); +} + +const void* W_CacheLumpNum(int lump) +{ +#ifdef RANGECHECK + if ((unsigned)lump >= (unsigned)numlumps) + I_Error ("W_CacheLumpNum: %i >= numlumps",lump); +#endif + if (!lumpinfo[lump].wadfile) + return NULL; + return (mapped_wad[lumpinfo[lump].wadfile->handle]+lumpinfo[lump].position); +} +#endif + +/* + * W_LockLumpNum + * + * This copies the lump into a malloced memory region and returns its address + * instead of returning a pointer into the memory mapped area + * + */ +const void* W_LockLumpNum(int lump) +{ + size_t len = W_LumpLength(lump); + const void *data = W_CacheLumpNum(lump); + + if (!cachelump[lump].cache) { + // read the lump in + Z_Malloc(len, PU_CACHE, &cachelump[lump].cache); + memcpy(cachelump[lump].cache, data, len); + } + + /* cph - if wasn't locked but now is, tell z_zone to hold it */ + if (cachelump[lump].locks <= 0) { + Z_ChangeTag(cachelump[lump].cache,PU_STATIC); +#ifdef TIMEDIAG + cachelump[lump].locktic = gametic; +#endif + // reset lock counter + cachelump[lump].locks = 1; + } else { + // increment lock counter + cachelump[lump].locks += 1; + } + +#ifdef SIMPLECHECKS + if (!((cachelump[lump].locks+1) & 0xf)) + lprintf(LO_DEBUG, "W_CacheLumpNum: High lock on %8s (%d)\n", + lumpinfo[lump].name, cachelump[lump].locks); +#endif + + return cachelump[lump].cache; +} + +void W_UnlockLumpNum(int lump) { + if (cachelump[lump].locks == -1) + return; // this lump is memory mapped + +#ifdef SIMPLECHECKS + if (cachelump[lump].locks == 0) + lprintf(LO_DEBUG, "W_UnlockLumpNum: Excess unlocks on %8s\n", + lumpinfo[lump].name); +#endif + cachelump[lump].locks -= 1; + /* cph - Note: must only tell z_zone to make purgeable if currently locked, + * else it might already have been purged + */ + if (cachelump[lump].locks == 0) + Z_ChangeTag(cachelump[lump].cache, PU_CACHE); +} + diff --git a/src/w_wad.c b/src/w_wad.c new file mode 100644 index 0000000..753a227 --- /dev/null +++ b/src/w_wad.c @@ -0,0 +1,476 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2001 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Handles WAD file header, directory, lump I/O. + * + *----------------------------------------------------------------------------- + */ + +// use config.h if autoconf made one -- josh +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef _MSC_VER +#include +#include +#endif +#include + +#include "doomstat.h" +#include "d_net.h" +#include "doomtype.h" +#include "i_system.h" + +#ifdef __GNUG__ +#pragma implementation "w_wad.h" +#endif +#include "w_wad.h" +#include "lprintf.h" + +// +// GLOBALS +// + +// Location of each lump on disk. +lumpinfo_t *lumpinfo; +int numlumps; // killough + +void ExtractFileBase (const char *path, char *dest) +{ + const char *src = path + strlen(path) - 1; + int length; + + // back up until a \ or the start + while (src != path && src[-1] != ':' // killough 3/22/98: allow c:filename + && *(src-1) != '\\' + && *(src-1) != '/') + { + src--; + } + + // copy up to eight characters + memset(dest,0,8); + length = 0; + + while ((*src) && (*src != '.') && (++length<9)) + { + *dest++ = toupper(*src); + *src++; + } + /* cph - length check removed, just truncate at 8 chars. + * If there are 8 or more chars, we'll copy 8, and no zero termination + */ +} + +// +// 1/18/98 killough: adds a default extension to a path +// Note: Backslashes are treated specially, for MS-DOS. +// + +char *AddDefaultExtension(char *path, const char *ext) +{ + char *p = path; + while (*p++); + while (p-->path && *p!='/' && *p!='\\') + if (*p=='.') + return path; + if (*ext!='.') + strcat(path,"."); + return strcat(path,ext); +} + +// +// LUMP BASED ROUTINES. +// + +// +// W_AddFile +// All files are optional, but at least one file must be +// found (PWAD, if all required lumps are present). +// Files with a .wad extension are wadlink files +// with multiple lumps. +// Other files are single lumps with the base filename +// for the lump name. +// +// Reload hack removed by Lee Killough +// CPhipps - source is an enum +// +// proff - changed using pointer to wadfile_info_t +static void W_AddFile(wadfile_info_t *wadfile) +// killough 1/31/98: static, const +{ + wadinfo_t header; + lumpinfo_t* lump_p; + unsigned i; + int length; + int startlump; + filelump_t *fileinfo, *fileinfo2free=NULL; //killough + filelump_t singleinfo; + + // open the file and add to directory + + wadfile->handle = open(wadfile->name,O_RDONLY | O_BINARY); + +#ifdef HAVE_NET + if (wadfile->handle == -1 && D_NetGetWad(wadfile->name)) // CPhipps + wadfile->handle = open(wadfile->name,O_RDONLY | O_BINARY); +#endif + + if (wadfile->handle == -1) + { + if ( strlen(wadfile->name)<=4 || // add error check -- killough + (strcasecmp(wadfile->name+strlen(wadfile->name)-4 , ".lmp" ) && + strcasecmp(wadfile->name+strlen(wadfile->name)-4 , ".gwa" ) ) + ) + I_Error("W_AddFile: couldn't open %s",wadfile->name); + return; + } + + //jff 8/3/98 use logical output routine + lprintf (LO_INFO," adding %s\n",wadfile->name); + startlump = numlumps; + + if ( strlen(wadfile->name)<=4 || + ( + strcasecmp(wadfile->name+strlen(wadfile->name)-4,".wad") && + strcasecmp(wadfile->name+strlen(wadfile->name)-4,".gwa") + ) + ) + { + // single lump file + fileinfo = &singleinfo; + singleinfo.filepos = 0; + singleinfo.size = LONG(I_Filelength(wadfile->handle)); + ExtractFileBase(wadfile->name, singleinfo.name); + numlumps++; + } + else + { + // WAD file + I_Read(wadfile->handle, &header, sizeof(header)); + if (strncmp(header.identification,"IWAD",4) && + strncmp(header.identification,"PWAD",4)) + I_Error("W_AddFile: Wad file %s doesn't have IWAD or PWAD id", wadfile->name); + header.numlumps = LONG(header.numlumps); + header.infotableofs = LONG(header.infotableofs); + length = header.numlumps*sizeof(filelump_t); + fileinfo2free = fileinfo = malloc(length); // killough + lseek(wadfile->handle, header.infotableofs, SEEK_SET); + I_Read(wadfile->handle, fileinfo, length); + numlumps += header.numlumps; + } + + // Fill in lumpinfo + lumpinfo = realloc(lumpinfo, numlumps*sizeof(lumpinfo_t)); + + lump_p = &lumpinfo[startlump]; + + for (i=startlump ; (int)iwadfile = wadfile; // killough 4/25/98 + lump_p->position = LONG(fileinfo->filepos); + lump_p->size = LONG(fileinfo->size); + lump_p->li_namespace = ns_global; // killough 4/17/98 + strncpy (lump_p->name, fileinfo->name, 8); + lump_p->source = wadfile->src; // Ty 08/29/98 + } + + free(fileinfo2free); // killough +} + +// jff 1/23/98 Create routines to reorder the master directory +// putting all flats into one marked block, and all sprites into another. +// This will allow loading of sprites and flats from a PWAD with no +// other changes to code, particularly fast hashes of the lumps. +// +// killough 1/24/98 modified routines to be a little faster and smaller + +static int IsMarker(const char *marker, const char *name) +{ + return !strncasecmp(name, marker, 8) || + (*name == *marker && !strncasecmp(name+1, marker, 7)); +} + +// killough 4/17/98: add namespace tags + +static void W_CoalesceMarkedResource(const char *start_marker, + const char *end_marker, int li_namespace) +{ + lumpinfo_t *marked = malloc(sizeof(*marked) * numlumps); + size_t i, num_marked = 0, num_unmarked = 0; + int is_marked = 0, mark_end = 0; + lumpinfo_t *lump = lumpinfo; + + for (i=numlumps; i--; lump++) + if (IsMarker(start_marker, lump->name)) // start marker found + { // If this is the first start marker, add start marker to marked lumps + if (!num_marked) + { + strncpy(marked->name, start_marker, 8); + marked->size = 0; // killough 3/20/98: force size to be 0 + marked->li_namespace = ns_global; // killough 4/17/98 + marked->wadfile = NULL; + num_marked = 1; + } + is_marked = 1; // start marking lumps + } + else + if (IsMarker(end_marker, lump->name)) // end marker found + { + mark_end = 1; // add end marker below + is_marked = 0; // stop marking lumps + } + else + if (is_marked) // if we are marking lumps, + { // move lump to marked list + marked[num_marked] = *lump; + marked[num_marked++].li_namespace = li_namespace; // killough 4/17/98 + } + else + lumpinfo[num_unmarked++] = *lump; // else move down THIS list + + // Append marked list to end of unmarked list + memcpy(lumpinfo + num_unmarked, marked, num_marked * sizeof(*marked)); + + free(marked); // free marked list + + numlumps = num_unmarked + num_marked; // new total number of lumps + + if (mark_end) // add end marker + { + lumpinfo[numlumps].size = 0; // killough 3/20/98: force size to be 0 + lumpinfo[numlumps].wadfile = NULL; + lumpinfo[numlumps].li_namespace = ns_global; // killough 4/17/98 + strncpy(lumpinfo[numlumps++].name, end_marker, 8); + } +} + +// Hash function used for lump names. +// Must be mod'ed with table size. +// Can be used for any 8-character names. +// by Lee Killough + +unsigned W_LumpNameHash(const char *s) +{ + unsigned hash; + (void) ((hash = toupper(s[0]), s[1]) && + (hash = hash*3+toupper(s[1]), s[2]) && + (hash = hash*2+toupper(s[2]), s[3]) && + (hash = hash*2+toupper(s[3]), s[4]) && + (hash = hash*2+toupper(s[4]), s[5]) && + (hash = hash*2+toupper(s[5]), s[6]) && + (hash = hash*2+toupper(s[6]), + hash = hash*2+toupper(s[7])) + ); + return hash; +} + +// +// W_CheckNumForName +// Returns -1 if name not found. +// +// Rewritten by Lee Killough to use hash table for performance. Significantly +// cuts down on time -- increases Doom performance over 300%. This is the +// single most important optimization of the original Doom sources, because +// lump name lookup is used so often, and the original Doom used a sequential +// search. For large wads with > 1000 lumps this meant an average of over +// 500 were probed during every search. Now the average is under 2 probes per +// search. There is no significant benefit to packing the names into longwords +// with this new hashing algorithm, because the work to do the packing is +// just as much work as simply doing the string comparisons with the new +// algorithm, which minimizes the expected number of comparisons to under 2. +// +// killough 4/17/98: add namespace parameter to prevent collisions +// between different resources such as flats, sprites, colormaps +// + +int (W_CheckNumForName)(register const char *name, register int li_namespace) +{ + // Hash function maps the name to one of possibly numlump chains. + // It has been tuned so that the average chain length never exceeds 2. + + // proff 2001/09/07 - check numlumps==0, this happens when called before WAD loaded + register int i = (numlumps==0)?(-1):(lumpinfo[W_LumpNameHash(name) % (unsigned) numlumps].index); + + // We search along the chain until end, looking for case-insensitive + // matches which also match a namespace tag. Separate hash tables are + // not used for each namespace, because the performance benefit is not + // worth the overhead, considering namespace collisions are rare in + // Doom wads. + + while (i >= 0 && (strncasecmp(lumpinfo[i].name, name, 8) || + lumpinfo[i].li_namespace != li_namespace)) + i = lumpinfo[i].next; + + // Return the matching lump, or -1 if none found. + + return i; +} + +// +// killough 1/31/98: Initialize lump hash table +// + +void W_HashLumps(void) +{ + int i; + + for (i=0; i= numlumps) + I_Error ("W_LumpLength: %i >= numlumps",lump); + return lumpinfo[lump].size; +} + +// +// W_ReadLump +// Loads the lump into the given buffer, +// which must be >= W_LumpLength(). +// + +void W_ReadLump(int lump, void *dest) +{ + lumpinfo_t *l = lumpinfo + lump; + +#ifdef RANGECHECK + if (lump >= numlumps) + I_Error ("W_ReadLump: %i >= numlumps",lump); +#endif + + { + if (l->wadfile) + { + lseek(l->wadfile->handle, l->position, SEEK_SET); + I_Read(l->wadfile->handle, dest, l->size); + } + } +} + diff --git a/src/w_wad.h b/src/w_wad.h new file mode 100644 index 0000000..399869e --- /dev/null +++ b/src/w_wad.h @@ -0,0 +1,146 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * WAD I/O functions. + * + *-----------------------------------------------------------------------------*/ + + +#ifndef __W_WAD__ +#define __W_WAD__ + +#ifdef __GNUG__ +#pragma interface +#endif + +// +// TYPES +// + +typedef struct +{ + char identification[4]; // Should be "IWAD" or "PWAD". + int numlumps; + int infotableofs; +} wadinfo_t; + +typedef struct +{ + int filepos; + int size; + char name[8]; +} filelump_t; + +// +// WADFILE I/O related stuff. +// + +// CPhipps - defined enum in wider scope +// Ty 08/29/98 - add source field to identify where this lump came from +typedef enum { + // CPhipps - define elements in order of 'how new/unusual' + source_iwad=0, // iwad file load + source_pre, // predefined lump + source_auto_load, // lump auto-loaded by config file + source_pwad, // pwad file load + source_lmp, // lmp file load + source_net // CPhipps +} wad_source_t; + +// CPhipps - changed wad init +// We _must_ have the wadfiles[] the same as those actually loaded, so there +// is no point having these separate entities. This belongs here. +typedef struct { + const char* name; + wad_source_t src; + int handle; +} wadfile_info_t; + +extern wadfile_info_t *wadfiles; + +extern size_t numwadfiles; // CPhipps - size of the wadfiles array + +void W_Init(void); // CPhipps - uses the above array +void W_ReleaseAllWads(void); // Proff - Added for iwad switching +void W_InitCache(void); +void W_DoneCache(void); + +typedef struct +{ + // WARNING: order of some fields important (see info.c). + + char name[9]; + int size; + + // killough 1/31/98: hash table fields, used for ultra-fast hash table lookup + int index, next; + + // killough 4/17/98: namespace tags, to prevent conflicts between resources + enum { + ns_global=0, + ns_sprites, + ns_flats, + ns_colormaps, + ns_prboom + } li_namespace; // haleyjd 05/21/02: renamed from "namespace" + + wadfile_info_t *wadfile; + int position; + wad_source_t source; +} lumpinfo_t; + +extern lumpinfo_t *lumpinfo; +extern int numlumps; + +// killough 4/17/98: if W_CheckNumForName() called with only +// one argument, pass ns_global as the default namespace + +#define W_CheckNumForName(name) (W_CheckNumForName)(name, ns_global) +int (W_CheckNumForName)(const char* name, int); // killough 4/17/98 +int W_GetNumForName (const char* name); +int W_LumpLength (int lump); +void W_ReadLump (int lump, void *dest); +// CPhipps - modified for 'new' lump locking +const void* W_CacheLumpNum (int lump); +const void* W_LockLumpNum(int lump); +void W_UnlockLumpNum(int lump); + +// CPhipps - convenience macros +//#define W_CacheLumpNum(num) (W_CacheLumpNum)((num),1) +#define W_CacheLumpName(name) W_CacheLumpNum (W_GetNumForName(name)) + +//#define W_UnlockLumpNum(num) (W_UnlockLumpNum)((num),1) +#define W_UnlockLumpName(name) W_UnlockLumpNum (W_GetNumForName(name)) + +char *AddDefaultExtension(char *, const char *); // killough 1/18/98 +void ExtractFileBase(const char *, char *); // killough +unsigned W_LumpNameHash(const char *s); // killough 1/31/98 +void W_HashLumps(void); // cph 2001/07/07 - made public + +#endif diff --git a/src/wi_stuff.c b/src/wi_stuff.c new file mode 100644 index 0000000..1495a5c --- /dev/null +++ b/src/wi_stuff.c @@ -0,0 +1,1968 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Intermission screens. + * + *----------------------------------------------------------------------------- + */ + +#include "doomstat.h" +#include "m_random.h" +#include "w_wad.h" +#include "g_game.h" +#include "r_main.h" +#include "v_video.h" +#include "wi_stuff.h" +#include "s_sound.h" +#include "sounds.h" +#include "lprintf.h" // jff 08/03/98 - declaration of lprintf +#include "r_draw.h" + +// Ty 03/17/98: flag that new par times have been loaded in d_deh +extern boolean deh_pars; + +// +// Data needed to add patches to full screen intermission pics. +// Patches are statistics messages, and animations. +// Loads of by-pixel layout and placement, offsets etc. +// + +// +// Different vetween registered DOOM (1994) and +// Ultimate DOOM - Final edition (retail, 1995?). +// This is supposedly ignored for commercial +// release (aka DOOM II), which had 34 maps +// in one episode. So there. +#define NUMEPISODES 4 +#define NUMMAPS 9 + + +// Not used +// in tics +//U #define PAUSELEN (TICRATE*2) +//U #define SCORESTEP 100 +//U #define ANIMPERIOD 32 +// pixel distance from "(YOU)" to "PLAYER N" +//U #define STARDIST 10 +//U #define WK 1 + + +// GLOBAL LOCATIONS +#define WI_TITLEY 2 +#define WI_SPACINGY 33 + +// SINGLE-PLAYER STUFF +#define SP_STATSX 50 +#define SP_STATSY 50 + +#define SP_TIMEX 8 +// proff/nicolas 09/20/98 -- changed for hi-res +#define SP_TIMEY 160 +//#define SP_TIMEY (SCREENHEIGHT-32) + + +// NET GAME STUFF +#define NG_STATSY 50 +#define NG_STATSX (32 + V_NamePatchWidth(star)/2 + 32*!dofrags) + +#define NG_SPACINGX 64 + + +// Used to display the frags matrix at endgame +// DEATHMATCH STUFF +#define DM_MATRIXX 42 +#define DM_MATRIXY 68 + +#define DM_SPACINGX 40 + +#define DM_TOTALSX 269 + +#define DM_KILLERSX 10 +#define DM_KILLERSY 100 +#define DM_VICTIMSX 5 +#define DM_VICTIMSY 50 + + +// These animation variables, structures, etc. are used for the +// DOOM/Ultimate DOOM intermission screen animations. This is +// totally different from any sprite or texture/flat animations +typedef enum +{ + ANIM_ALWAYS, // determined by patch entry + ANIM_RANDOM, // occasional + ANIM_LEVEL // continuous +} animenum_t; + +typedef struct +{ + int x; // x/y coordinate pair structure + int y; +} point_t; + + +// +// Animation. +// There is another anim_t used in p_spec. +// +typedef struct +{ + animenum_t type; + + // period in tics between animations + int period; + + // number of animation frames + int nanims; + + // location of animation + point_t loc; + + // ALWAYS: n/a, + // RANDOM: period deviation (<256), + // LEVEL: level + int data1; + + // ALWAYS: n/a, + // RANDOM: random base period, + // LEVEL: n/a + int data2; + + /* actual graphics for frames of animations + * cphipps - const + */ + patchnum_t p[3]; + + // following must be initialized to zero before use! + + // next value of bcnt (used in conjunction with period) + int nexttic; + + // last drawn animation frame + int lastdrawn; + + // next frame number to animate + int ctr; + + // used by RANDOM and LEVEL when animating + int state; +} anim_t; + + +static point_t lnodes[NUMEPISODES][NUMMAPS] = +{ + // Episode 0 World Map + { + { 185, 164 }, // location of level 0 (CJ) + { 148, 143 }, // location of level 1 (CJ) + { 69, 122 }, // location of level 2 (CJ) + { 209, 102 }, // location of level 3 (CJ) + { 116, 89 }, // location of level 4 (CJ) + { 166, 55 }, // location of level 5 (CJ) + { 71, 56 }, // location of level 6 (CJ) + { 135, 29 }, // location of level 7 (CJ) + { 71, 24 } // location of level 8 (CJ) + }, + + // Episode 1 World Map should go here + { + { 254, 25 }, // location of level 0 (CJ) + { 97, 50 }, // location of level 1 (CJ) + { 188, 64 }, // location of level 2 (CJ) + { 128, 78 }, // location of level 3 (CJ) + { 214, 92 }, // location of level 4 (CJ) + { 133, 130 }, // location of level 5 (CJ) + { 208, 136 }, // location of level 6 (CJ) + { 148, 140 }, // location of level 7 (CJ) + { 235, 158 } // location of level 8 (CJ) + }, + + // Episode 2 World Map should go here + { + { 156, 168 }, // location of level 0 (CJ) + { 48, 154 }, // location of level 1 (CJ) + { 174, 95 }, // location of level 2 (CJ) + { 265, 75 }, // location of level 3 (CJ) + { 130, 48 }, // location of level 4 (CJ) + { 279, 23 }, // location of level 5 (CJ) + { 198, 48 }, // location of level 6 (CJ) + { 140, 25 }, // location of level 7 (CJ) + { 281, 136 } // location of level 8 (CJ) + } +}; + + +// +// Animation locations for episode 0 (1). +// Using patches saves a lot of space, +// as they replace 320x200 full screen frames. +// +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 } } +}; + +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 } +}; + +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 } } +}; + +static int NUMANIMS[NUMEPISODES] = +{ + sizeof(epsd0animinfo)/sizeof(anim_t), + sizeof(epsd1animinfo)/sizeof(anim_t), + sizeof(epsd2animinfo)/sizeof(anim_t) +}; + +static anim_t *anims[NUMEPISODES] = +{ + epsd0animinfo, + epsd1animinfo, + epsd2animinfo +}; + + +// +// GENERAL DATA +// + +// +// Locally used stuff. +// +#define FB 0 + + +// States for single-player +#define SP_KILLS 0 +#define SP_ITEMS 2 +#define SP_SECRET 4 +#define SP_FRAGS 6 +#define SP_TIME 8 +#define SP_PAR ST_TIME + +#define SP_PAUSE 1 + +// in seconds +#define SHOWNEXTLOCDELAY 4 +//#define SHOWLASTLOCDELAY SHOWNEXTLOCDELAY + + +// used to accelerate or skip a stage +int acceleratestage; // killough 3/28/98: made global + +// wbs->pnum +static int me; + + // specifies current state +static stateenum_t state; + +// contains information passed into intermission +static wbstartstruct_t* wbs; + +static wbplayerstruct_t* plrs; // wbs->plyr[] + +// used for general timing +static int cnt; + +// used for timing of background animation +static int bcnt; + +// signals to refresh everything for one frame +static int firstrefresh; + +static int cnt_time; +static int cnt_total_time; +static int cnt_par; +static int cnt_pause; + +// +// GRAPHICS +// + +// You Are Here graphic +static const char* yah[2] = { "WIURH0", "WIURH1" }; + +// splat +static const char* splat = "WISPLAT"; + +// %, : graphics +static const char percent[] = {"WIPCNT"}; +static const char colon[] = {"WICOLON"}; + +// 0-9 graphic +static patchnum_t num[10]; + +// minus sign +static const char wiminus[] = {"WIMINUS"}; + +// "Finished!" graphics +static const char finished[] = {"WIF"}; + +// "Entering" graphic +static const char entering[] = {"WIENTER"}; + +// "secret" +static const char sp_secret[] = {"WISCRT2"}; + +// "Kills", "Scrt", "Items", "Frags" +static const char kills[] = {"WIOSTK"}; +static const char secret[] = {"WIOSTS"}; +static const char items[] = {"WIOSTI"}; +static const char frags[] = {"WIFRGS"}; + +// Time sucks. +static const char time1[] = {"WITIME"}; +static const char par[] = {"WIPAR"}; +static const char sucks[] = {"WISUCKS"}; + +// "killers", "victims" +static const char killers[] = {"WIKILRS"}; +static const char victims[] = {"WIVCTMS"}; + +// "Total", your face, your dead face +static const char total[] = {"WIMSTT"}; +static const char star[] = {"STFST01"}; +static const char bstar[] = {"STFDEAD0"}; + +// "red P[1..MAXPLAYERS]" +static const char facebackp[] = {"STPB0"}; + +// +// CODE +// + +static void WI_endDeathmatchStats(void); +static void WI_endNetgameStats(void); +#define WI_endStats WI_endNetgameStats + +/* ==================================================================== + * WI_levelNameLump + * Purpore: Returns the name of the graphic lump containing the name of + * the given level. + * Args: Episode and level, and buffer (must by 9 chars) to write to + * Returns: void + */ +void WI_levelNameLump(int epis, int map, char* buf) +{ + if (gamemode == commercial) { + sprintf(buf, "CWILV%2.2d", map); + } else { + sprintf(buf, "WILV%d%d", epis, map); + } +} + +// ==================================================================== +// WI_slamBackground +// Purpose: Put the full-screen background up prior to patches +// Args: none +// Returns: void +// +static void WI_slamBackground(void) +{ + char name[9]; // limited to 8 characters + + if (gamemode == commercial || (gamemode == retail && wbs->epsd == 3)) + strcpy(name, "INTERPIC"); + else + sprintf(name, "WIMAP%d", wbs->epsd); + + // background + V_DrawNamePatch(0, 0, FB, name, CR_DEFAULT, VPT_STRETCH); +} + + +// ==================================================================== +// WI_Responder +// Purpose: Draw animations on intermission background screen +// Args: ev -- event pointer, not actually used here. +// Returns: False -- dummy routine +// +// The ticker is used to detect keys +// because of timing issues in netgames. +boolean WI_Responder(event_t* ev) +{ + return false; +} + + +// ==================================================================== +// WI_drawLF +// Purpose: Draw the "Finished" level name before showing stats +// Args: none +// Returns: void +// +void WI_drawLF(void) +{ + int y = WI_TITLEY; + char lname[9]; + + // draw + /* cph - get the graphic lump name and use it */ + WI_levelNameLump(wbs->epsd, wbs->last, lname); + // CPhipps - patch drawing updated + V_DrawNamePatch((320 - V_NamePatchWidth(lname))/2, y, + FB, lname, CR_DEFAULT, VPT_STRETCH); + + // draw "Finished!" + y += (5*V_NamePatchHeight(lname))/4; + + // CPhipps - patch drawing updated + V_DrawNamePatch((320 - V_NamePatchWidth(finished))/2, y, + FB, finished, CR_DEFAULT, VPT_STRETCH); +} + + +// ==================================================================== +// WI_drawEL +// Purpose: Draw introductory "Entering" and level name +// Args: none +// Returns: void +// +void WI_drawEL(void) +{ + int y = WI_TITLEY; + char lname[9]; + + /* cph - get the graphic lump name */ + WI_levelNameLump(wbs->epsd, wbs->next, lname); + + // draw "Entering" + // CPhipps - patch drawing updated + V_DrawNamePatch((320 - V_NamePatchWidth(entering))/2, + y, FB, entering, CR_DEFAULT, VPT_STRETCH); + + // draw level + y += (5*V_NamePatchHeight(lname))/4; + + // CPhipps - patch drawing updated + V_DrawNamePatch((320 - V_NamePatchWidth(lname))/2, y, FB, + lname, CR_DEFAULT, VPT_STRETCH); +} + + +/* ==================================================================== + * WI_drawOnLnode + * Purpose: Draw patches at a location based on episode/map + * Args: n -- index to map# within episode + * c[] -- array of names of patches to be drawn + * Returns: void + */ +void +WI_drawOnLnode // draw stuff at a location by episode/map# +( int n, + const char* const c[] ) +{ + int i; + boolean fits = false; + + i = 0; + do + { + int left; + int top; + int right; + int bottom; + const rpatch_t* patch = R_CachePatchName(c[i]); + + left = lnodes[wbs->epsd][n].x - patch->leftoffset; + top = lnodes[wbs->epsd][n].y - patch->topoffset; + right = left + patch->width; + bottom = top + patch->height; + R_UnlockPatchName(c[i]); + + if (left >= 0 + && right < 320 + && top >= 0 + && bottom < 200) + { + fits = true; + } + else + { + i++; + } + } while (!fits && i!=2); + + if (fits && i<2) + { + // CPhipps - patch drawing updated + V_DrawNamePatch(lnodes[wbs->epsd][n].x, lnodes[wbs->epsd][n].y, + FB, c[i], CR_DEFAULT, VPT_STRETCH); + } + else + { + // DEBUG + //jff 8/3/98 use logical output routine + lprintf(LO_DEBUG,"Could not place patch on level %d", n+1); + } +} + + +// ==================================================================== +// WI_initAnimatedBack +// Purpose: Initialize pointers and styles for background animation +// Args: none +// Returns: void +// +void WI_initAnimatedBack(void) +{ + int i; + anim_t* a; + + if (gamemode == commercial) // no animation for DOOM2 + return; + + if (wbs->epsd > 2) + return; + + for (i=0;iepsd];i++) + { + a = &anims[wbs->epsd][i]; + + // init variables + a->ctr = -1; + + // specify the next time to draw it + if (a->type == ANIM_ALWAYS) + a->nexttic = bcnt + 1 + (M_Random()%a->period); + else + if (a->type == ANIM_RANDOM) + a->nexttic = bcnt + 1 + a->data2+(M_Random()%a->data1); + else + if (a->type == ANIM_LEVEL) + a->nexttic = bcnt + 1; + } +} + + +// ==================================================================== +// WI_updateAnimatedBack +// Purpose: Figure out what animation we do on this iteration +// Args: none +// Returns: void +// +void WI_updateAnimatedBack(void) +{ + int i; + anim_t* a; + + if (gamemode == commercial) + return; + + if (wbs->epsd > 2) + return; + + for (i=0;iepsd];i++) + { + a = &anims[wbs->epsd][i]; + + if (bcnt == a->nexttic) + { + switch (a->type) + { + case ANIM_ALWAYS: + if (++a->ctr >= a->nanims) a->ctr = 0; + a->nexttic = bcnt + a->period; + break; + + case ANIM_RANDOM: + a->ctr++; + if (a->ctr == a->nanims) + { + a->ctr = -1; + a->nexttic = bcnt+a->data2+(M_Random()%a->data1); + } + else + a->nexttic = bcnt + a->period; + break; + + case ANIM_LEVEL: + // gawd-awful hack for level anims + if (!(state == StatCount && i == 7) + && wbs->next == a->data1) + { + a->ctr++; + if (a->ctr == a->nanims) a->ctr--; + a->nexttic = bcnt + a->period; + } + break; + } + } + } +} + + +// ==================================================================== +// WI_drawAnimatedBack +// Purpose: Actually do the animation (whew!) +// Args: none +// Returns: void +// +void WI_drawAnimatedBack(void) +{ + int i; + anim_t* a; + + if (gamemode==commercial) //jff 4/25/98 Someone forgot commercial an enum + return; + + if (wbs->epsd > 2) + return; + + for (i=0 ; iepsd] ; i++) + { + a = &anims[wbs->epsd][i]; + + if (a->ctr >= 0) + // CPhipps - patch drawing updated + V_DrawNumPatch(a->loc.x, a->loc.y, FB, a->p[a->ctr].lumpnum, CR_DEFAULT, VPT_STRETCH); + } +} + + +// ==================================================================== +// WI_drawNum +// Purpose: Draws a number. If digits > 0, then use that many digits +// minimum, otherwise only use as many as necessary +// Args: x, y -- location +// n -- the number to be drawn +// digits -- number of digits minimum or zero +// Returns: new x position after drawing (note we are going to the left) +// CPhipps - static +static int WI_drawNum (int x, int y, int n, int digits) +{ + int fontwidth = num[0].width; + int neg; + int temp; + + if (digits < 0) + { + if (!n) + { + // make variable-length zeros 1 digit long + digits = 1; + } + else + { + // figure out # of digits in # + digits = 0; + temp = n; + + while (temp) + { + temp /= 10; + digits++; + } + } + } + + neg = n < 0; + if (neg) + n = -n; + + // if non-number, do not draw it + if (n == 1994) + return 0; + + // draw the new number + while (digits--) + { + x -= fontwidth; + // CPhipps - patch drawing updated + V_DrawNumPatch(x, y, FB, num[ n % 10 ].lumpnum, CR_DEFAULT, VPT_STRETCH); + n /= 10; + } + + // draw a minus sign if necessary + if (neg) + // CPhipps - patch drawing updated + V_DrawNamePatch(x-=8, y, FB, wiminus, CR_DEFAULT, VPT_STRETCH); + + return x; +} + + +// ==================================================================== +// WI_drawPercent +// Purpose: Draws a percentage, really just a call to WI_drawNum +// after putting a percent sign out there +// Args: x, y -- location +// p -- the percentage value to be drawn, no negatives +// Returns: void +// CPhipps - static +static void WI_drawPercent(int x, int y, int p) +{ + if (p < 0) + return; + + // CPhipps - patch drawing updated + V_DrawNamePatch(x, y, FB, percent, CR_DEFAULT, VPT_STRETCH); + WI_drawNum(x, y, p, -1); +} + + +// ==================================================================== +// WI_drawTime +// Purpose: Draws the level completion time or par time, or "Sucks" +// if 1 hour or more +// Args: x, y -- location +// t -- the time value to be drawn +// Returns: void +// +// CPhipps - static +// - largely rewritten to display hours and use slightly better algorithm + +static void WI_drawTime(int x, int y, int t) +{ + int n; + + if (t<0) + return; + + if (t < 100*60*60) + for(;;) { + n = t % 60; + t /= 60; + x = WI_drawNum(x, y, n, (t || n>9) ? 2 : 1) - V_NamePatchWidth(colon); + + // draw + if (t) + // CPhipps - patch drawing updated + V_DrawNamePatch(x, y, FB, colon, CR_DEFAULT, VPT_STRETCH); + else break; + } + else // "sucks" (maybe should be "addicted", even I've never had a 100 hour game ;) + V_DrawNamePatch(x - V_NamePatchWidth(sucks), + y, FB, sucks, CR_DEFAULT, VPT_STRETCH); +} + + +// ==================================================================== +// WI_End +// Purpose: Unloads data structures (inverse of WI_Start) +// Args: none +// Returns: void +// +void WI_End(void) +{ + if (deathmatch) + WI_endDeathmatchStats(); + else if (netgame) + WI_endNetgameStats(); + else + WI_endStats(); +} + + +// ==================================================================== +// WI_initNoState +// Purpose: Clear state, ready for end of level activity +// Args: none +// Returns: void +// +void WI_initNoState(void) +{ + state = NoState; + acceleratestage = 0; + cnt = 10; +} + + +// ==================================================================== +// WI_drawTimeStats +// Purpose: Put the times on the screen +// Args: time, total time, par time, in seconds +// Returns: void +// +// cph - pulled from WI_drawStats below + +static void WI_drawTimeStats(int cnt_time, int cnt_total_time, int cnt_par) +{ + V_DrawNamePatch(SP_TIMEX, SP_TIMEY, FB, time1, CR_DEFAULT, VPT_STRETCH); + WI_drawTime(320/2 - SP_TIMEX, SP_TIMEY, cnt_time); + + V_DrawNamePatch(SP_TIMEX, (SP_TIMEY+200)/2, FB, total, CR_DEFAULT, VPT_STRETCH); + WI_drawTime(320/2 - SP_TIMEX, (SP_TIMEY+200)/2, cnt_total_time); + + // Ty 04/11/98: redid logic: should skip only if with pwad but + // without deh patch + // killough 2/22/98: skip drawing par times on pwads + // Ty 03/17/98: unless pars changed with deh patch + + if (!(modifiedgame && !deh_pars)) + { + if (wbs->epsd < 3) + { + V_DrawNamePatch(320/2 + SP_TIMEX, SP_TIMEY, FB, par, CR_DEFAULT, VPT_STRETCH); + WI_drawTime(320 - SP_TIMEX, SP_TIMEY, cnt_par); + } + } +} + +// ==================================================================== +// WI_updateNoState +// Purpose: Cycle until end of level activity is done +// Args: none +// Returns: void +// +void WI_updateNoState(void) +{ + + WI_updateAnimatedBack(); + + if (!--cnt) + G_WorldDone(); +} + +static boolean snl_pointeron = false; + + +// ==================================================================== +// WI_initShowNextLoc +// Purpose: Prepare to show the next level's location +// Args: none +// Returns: void +// +void WI_initShowNextLoc(void) +{ + if ((gamemode != commercial) && (gamemap == 8)) { + G_WorldDone(); + return; + } + + state = ShowNextLoc; + acceleratestage = 0; + + // e6y: That was pretty easy - only a HEX editor and luck + // There is no more desync on ddt-tas.zip\e4tux231.lmp + // --------- tasdoom.idb --------- + // .text:00031194 loc_31194: ; CODE XREF: WI_updateStats+3A9j + // .text:00031194 mov ds:state, 1 + // .text:0003119E mov ds:acceleratestage, 0 + // .text:000311A8 mov ds:cnt, 3Ch + // nowhere no hide + if (compatibility_level == tasdoom_compatibility) + cnt = 60; + else + cnt = SHOWNEXTLOCDELAY * TICRATE; + + WI_initAnimatedBack(); +} + + +// ==================================================================== +// WI_updateShowNextLoc +// Purpose: Prepare to show the next level's location +// Args: none +// Returns: void +// +void WI_updateShowNextLoc(void) +{ + WI_updateAnimatedBack(); + + if (!--cnt || acceleratestage) + WI_initNoState(); + else + snl_pointeron = (cnt & 31) < 20; +} + + +// ==================================================================== +// WI_drawShowNextLoc +// Purpose: Show the next level's location on animated backgrounds +// Args: none +// Returns: void +// +void WI_drawShowNextLoc(void) +{ + int i; + int last; + + WI_slamBackground(); + + // draw animated background + WI_drawAnimatedBack(); + + if ( gamemode != commercial) + { + if (wbs->epsd > 2) + { + WI_drawEL(); // "Entering..." if not E1 or E2 + return; + } + + last = (wbs->last == 8) ? wbs->next - 1 : wbs->last; + + // draw a splat on taken cities. + for (i=0 ; i<=last ; i++) + WI_drawOnLnode(i, &splat); + + // splat the secret level? + if (wbs->didsecret) + WI_drawOnLnode(8, &splat); + + // draw flashing ptr + if (snl_pointeron) + WI_drawOnLnode(wbs->next, yah); + } + + // draws which level you are entering.. + if ( (gamemode != commercial) + || wbs->next != 30) // check for MAP30 end game + WI_drawEL(); +} + +// ==================================================================== +// WI_drawNoState +// Purpose: Draw the pointer and next location +// Args: none +// Returns: void +// +void WI_drawNoState(void) +{ + snl_pointeron = true; + WI_drawShowNextLoc(); +} + +// ==================================================================== +// WI_fragSum +// Purpose: Calculate frags for this player based on the current totals +// of all the other players. Subtract self-frags. +// Args: playernum -- the player to be calculated +// Returns: the total frags for this player +// +int WI_fragSum(int playernum) +{ + int i; + int frags = 0; + + for (i=0 ; i 999) // Ty 03/17/98 3-digit frag count + dm_frags[i][j] = 999; + + if (dm_frags[i][j] < -999) + dm_frags[i][j] = -999; + + stillticking = true; + } + } + dm_totals[i] = WI_fragSum(i); + + if (dm_totals[i] > 999) + dm_totals[i] = 999; + + if (dm_totals[i] < -999) + dm_totals[i] = -999; // Ty 03/17/98 end 3-digit frag count + } + } + + if (!stillticking) + { + S_StartSound(0, sfx_barexp); + dm_state++; + } + } + else if (dm_state == 4) + { + if (acceleratestage) + { + S_StartSound(0, sfx_slop); + + if ( gamemode == commercial) + WI_initNoState(); + else + WI_initShowNextLoc(); + } + } + else if (dm_state & 1) + { + if (!--cnt_pause) + { + dm_state++; + cnt_pause = TICRATE; + } + } +} + + +// ==================================================================== +// WI_drawDeathmatchStats +// Purpose: Draw the stats on the screen in a matrix +// Args: none +// Returns: void +// +// proff/nicolas 09/20/98 -- changed for hi-res +// CPhipps - patch drawing updated +void WI_drawDeathmatchStats(void) +{ + int i; + int j; + int x; + int y; + int w; + + int lh; // line height + int halfface = V_NamePatchWidth(facebackp)/2; + + lh = WI_SPACINGY; + + WI_slamBackground(); + + // draw animated background + WI_drawAnimatedBack(); + WI_drawLF(); + + // draw stat titles (top line) + V_DrawNamePatch(DM_TOTALSX-V_NamePatchWidth(total)/2, + DM_MATRIXY-WI_SPACINGY+10, FB, total, CR_DEFAULT, VPT_STRETCH); + + V_DrawNamePatch(DM_KILLERSX, DM_KILLERSY, FB, killers, CR_DEFAULT, VPT_STRETCH); + V_DrawNamePatch(DM_VICTIMSX, DM_VICTIMSY, FB, victims, CR_DEFAULT, VPT_STRETCH); + + // draw P? + x = DM_MATRIXX + DM_SPACINGX; + y = DM_MATRIXY; + + for (i=0 ; imaxkills; + cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems; + + // killough 2/22/98: Make secrets = 100% if maxsecret = 0: + cnt_secret[i] = wbs->maxsecret ? + (plrs[i].ssecret * 100) / wbs->maxsecret : 100; + if (dofrags) + cnt_frags[i] = WI_fragSum(i); // we had frags + } + S_StartSound(0, sfx_barexp); // bang + ng_state = 10; + } + + if (ng_state == 2) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); // pop + + stillticking = false; + + for (i=0 ; i= (plrs[i].skills * 100) / wbs->maxkills) + cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills; + else + stillticking = true; // still got stuff to tally + } + + if (!stillticking) + { + S_StartSound(0, sfx_barexp); + ng_state++; + } + } + else if (ng_state == 4) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + stillticking = false; + + for (i=0 ; i= (plrs[i].sitems * 100) / wbs->maxitems) + cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems; + else + stillticking = true; + } + + if (!stillticking) + { + S_StartSound(0, sfx_barexp); + ng_state++; + } + } + else if (ng_state == 6) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + stillticking = false; + + for (i=0 ; i= (wbs->maxsecret ? (plrs[i].ssecret * 100) / wbs->maxsecret : compatibility_level < lxdoom_1_compatibility ? 0 : 100)) + cnt_secret[i] = wbs->maxsecret ? (plrs[i].ssecret * 100) / wbs->maxsecret : 100; + else + stillticking = true; + } + + if (!stillticking) + { + S_StartSound(0, sfx_barexp); + ng_state += 1 + 2*!dofrags; + } + } + else if (ng_state == 8) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + stillticking = false; + + for (i=0 ; i= (fsum = WI_fragSum(i))) + cnt_frags[i] = fsum; + else + stillticking = true; + } + + if (!stillticking) + { + S_StartSound(0, sfx_pldeth); + ng_state++; + } + } + else if (ng_state == 10) + { + if (acceleratestage) + { + S_StartSound(0, sfx_sgcock); + if ( gamemode == commercial ) + WI_initNoState(); + else + WI_initShowNextLoc(); + } + } + else if (ng_state & 1) + { + if (!--cnt_pause) + { + ng_state++; + cnt_pause = TICRATE; + } + } +} + + +// ==================================================================== +// WI_drawNetgameStats +// Purpose: Put the coop stats on the screen +// Args: none +// Returns: void +// +// proff/nicolas 09/20/98 -- changed for hi-res +// CPhipps - patch drawing updated +void WI_drawNetgameStats(void) +{ + int i; + int x; + int y; + int pwidth = V_NamePatchWidth(percent); + int fwidth = V_NamePatchWidth(facebackp); + + WI_slamBackground(); + + // draw animated background + WI_drawAnimatedBack(); + + WI_drawLF(); + + // draw stat titles (top line) + V_DrawNamePatch(NG_STATSX+NG_SPACINGX-V_NamePatchWidth(kills), + NG_STATSY, FB, kills, CR_DEFAULT, VPT_STRETCH); + + V_DrawNamePatch(NG_STATSX+2*NG_SPACINGX-V_NamePatchWidth(items), + NG_STATSY, FB, items, CR_DEFAULT, VPT_STRETCH); + + V_DrawNamePatch(NG_STATSX+3*NG_SPACINGX-V_NamePatchWidth(secret), + NG_STATSY, FB, secret, CR_DEFAULT, VPT_STRETCH); + + if (dofrags) + V_DrawNamePatch(NG_STATSX+4*NG_SPACINGX-V_NamePatchWidth(frags), + NG_STATSY, FB, frags, CR_DEFAULT, VPT_STRETCH); + + // draw stats + y = NG_STATSY + V_NamePatchHeight(kills); + + for (i=0 ; itotaltimes / TICRATE, wbs->partime / TICRATE); +} + +static int sp_state; + +// ==================================================================== +// WI_initStats +// Purpose: Get ready for single player stats +// Args: none +// Returns: void +// Comment: Seems like we could do all these stats in a more generic +// set of routines that weren't duplicated for dm, coop, sp +// +void WI_initStats(void) +{ + state = StatCount; + acceleratestage = 0; + sp_state = 1; + + // CPhipps - allocate (awful code, I know, but saves changing it all) and initialise + *(cnt_kills = malloc(sizeof(*cnt_kills))) = + *(cnt_items = malloc(sizeof(*cnt_items))) = + *(cnt_secret= malloc(sizeof(*cnt_secret))) = -1; + cnt_time = cnt_par = cnt_total_time = -1; + cnt_pause = TICRATE; + + WI_initAnimatedBack(); +} + +// ==================================================================== +// WI_updateStats +// Purpose: Calculate solo stats +// Args: none +// Returns: void +// +void WI_updateStats(void) +{ + WI_updateAnimatedBack(); + + if (acceleratestage && sp_state != 10) + { + acceleratestage = 0; + cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills; + cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems; + + // killough 2/22/98: Make secrets = 100% if maxsecret = 0: + cnt_secret[0] = (wbs->maxsecret ? + (plrs[me].ssecret * 100) / wbs->maxsecret : 100); + + cnt_total_time = wbs->totaltimes / TICRATE; + cnt_time = plrs[me].stime / TICRATE; + cnt_par = wbs->partime / TICRATE; + S_StartSound(0, sfx_barexp); + sp_state = 10; + } + + if (sp_state == 2) + { + cnt_kills[0] += 2; + + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + if (cnt_kills[0] >= (plrs[me].skills * 100) / wbs->maxkills) + { + cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills; + S_StartSound(0, sfx_barexp); + sp_state++; + } + } + else if (sp_state == 4) + { + cnt_items[0] += 2; + + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + if (cnt_items[0] >= (plrs[me].sitems * 100) / wbs->maxitems) + { + cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems; + S_StartSound(0, sfx_barexp); + sp_state++; + } + } + else if (sp_state == 6) + { + cnt_secret[0] += 2; + + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + // killough 2/22/98: Make secrets = 100% if maxsecret = 0: + if ((!wbs->maxsecret && compatibility_level < lxdoom_1_compatibility) || + cnt_secret[0] >= (wbs->maxsecret ? + (plrs[me].ssecret * 100) / wbs->maxsecret : 100)) + { + cnt_secret[0] = (wbs->maxsecret ? + (plrs[me].ssecret * 100) / wbs->maxsecret : 100); + S_StartSound(0, sfx_barexp); + sp_state++; + } + } + else if (sp_state == 8) + { + if (!(bcnt&3)) + S_StartSound(0, sfx_pistol); + + cnt_time += 3; + + if (cnt_time >= plrs[me].stime / TICRATE) + cnt_time = plrs[me].stime / TICRATE; + + cnt_total_time += 3; + + if (cnt_total_time >= wbs->totaltimes / TICRATE) + cnt_total_time = wbs->totaltimes / TICRATE; + + cnt_par += 3; + + if (cnt_par >= wbs->partime / TICRATE) + { + cnt_par = wbs->partime / TICRATE; + + if ((cnt_time >= plrs[me].stime / TICRATE) && (compatibility_level < lxdoom_1_compatibility || cnt_total_time >= wbs->totaltimes / TICRATE)) + { + S_StartSound(0, sfx_barexp); + sp_state++; + } + } + } + else if (sp_state == 10) + { + if (acceleratestage) + { + S_StartSound(0, sfx_sgcock); + + if (gamemode == commercial) + WI_initNoState(); + else + WI_initShowNextLoc(); + } + } + else if (sp_state & 1) + { + if (!--cnt_pause) + { + sp_state++; + cnt_pause = TICRATE; + } + } +} + +// ==================================================================== +// WI_drawStats +// Purpose: Put the solo stats on the screen +// Args: none +// Returns: void +// +// proff/nicolas 09/20/98 -- changed for hi-res +// CPhipps - patch drawing updated +void WI_drawStats(void) +{ + // line height + int lh; + + lh = (3*num[0].height)/2; + + WI_slamBackground(); + + // draw animated background + WI_drawAnimatedBack(); + + WI_drawLF(); + + V_DrawNamePatch(SP_STATSX, SP_STATSY, FB, kills, CR_DEFAULT, VPT_STRETCH); + if (cnt_kills) + WI_drawPercent(320 - SP_STATSX, SP_STATSY, cnt_kills[0]); + + V_DrawNamePatch(SP_STATSX, SP_STATSY+lh, FB, items, CR_DEFAULT, VPT_STRETCH); + if (cnt_items) + WI_drawPercent(320 - SP_STATSX, SP_STATSY+lh, cnt_items[0]); + + V_DrawNamePatch(SP_STATSX, SP_STATSY+2*lh, FB, sp_secret, CR_DEFAULT, VPT_STRETCH); + if (cnt_secret) + WI_drawPercent(320 - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]); + + WI_drawTimeStats(cnt_time, cnt_total_time, cnt_par); +} + +// ==================================================================== +// WI_checkForAccelerate +// Purpose: See if the player has hit either the attack or use key +// or mouse button. If so we set acceleratestage to 1 and +// all those display routines above jump right to the end. +// Args: none +// Returns: void +// +void WI_checkForAccelerate(void) +{ + int i; + player_t *player; + + // check for button presses to skip delays + for (i=0, player = players ; icmd.buttons & BT_ATTACK) + { + if (!player->attackdown) + acceleratestage = 1; + player->attackdown = true; + } + else + player->attackdown = false; + + if (player->cmd.buttons & BT_USE) + { + if (!player->usedown) + acceleratestage = 1; + player->usedown = true; + } + else + player->usedown = false; + } + } +} + +// ==================================================================== +// WI_Ticker +// Purpose: Do various updates every gametic, for stats, animation, +// checking that intermission music is running, etc. +// Args: none +// Returns: void +// +void WI_Ticker(void) +{ + // counter for general background animation + bcnt++; + + if (bcnt == 1) + { + // intermission music + if ( gamemode == commercial ) + S_ChangeMusic(mus_dm2int, true); + else + S_ChangeMusic(mus_inter, true); + } + + WI_checkForAccelerate(); + + switch (state) + { + case StatCount: + if (deathmatch) WI_updateDeathmatchStats(); + else if (netgame) WI_updateNetgameStats(); + else WI_updateStats(); + break; + + case ShowNextLoc: + WI_updateShowNextLoc(); + break; + + case NoState: + WI_updateNoState(); + break; + } +} + +/* ==================================================================== + * WI_loadData + * Purpose: Initialize intermission data such as background graphics, + * patches, map names, etc. + * Args: none + * Returns: void + * + * CPhipps - modified for new wad lump handling. + * - no longer preload most graphics, other funcs can use + * them by name + */ + +void WI_loadData(void) +{ + int i; + int j; + char name[9]; // limited to 8 characters + anim_t* a; + + if (gamemode != commercial) + { + if (wbs->epsd < 3) + { + for (j=0;jepsd];j++) + { + a = &anims[wbs->epsd][j]; + for (i=0;inanims;i++) + { + // MONDO HACK! + if (wbs->epsd != 1 || j != 8) + { + // animations + sprintf(name, "WIA%d%.2d%.2d", wbs->epsd, j, i); + R_SetPatchNum(&a->p[i], name); + } + else + { + // HACK ALERT! + a->p[i] = anims[1][4].p[i]; + } + } + } + } + } + + for (i=0;i<10;i++) + { + // numbers 0-9 + sprintf(name, "WINUM%d", i); + R_SetPatchNum(&num[i], name); + } +} + + +// ==================================================================== +// WI_Drawer +// Purpose: Call the appropriate stats drawing routine depending on +// what kind of game is being played (DM, coop, solo) +// Args: none +// Returns: void +// +void WI_Drawer (void) +{ + switch (state) + { + case StatCount: + if (deathmatch) + WI_drawDeathmatchStats(); + else if (netgame) + WI_drawNetgameStats(); + else + WI_drawStats(); + break; + + case ShowNextLoc: + WI_drawShowNextLoc(); + break; + + case NoState: + WI_drawNoState(); + break; + } +} + + +// ==================================================================== +// WI_initVariables +// Purpose: Initialize the intermission information structure +// Note: wbstartstruct_t is defined in d_player.h +// Args: wbstartstruct -- pointer to the structure with the data +// Returns: void +// +void WI_initVariables(wbstartstruct_t* wbstartstruct) +{ + + wbs = wbstartstruct; + +#ifdef RANGECHECKING + if (gamemode != commercial) + { + if ( gamemode == retail ) + RNGCHECK(wbs->epsd, 0, 3); + else + RNGCHECK(wbs->epsd, 0, 2); + } + else + { + RNGCHECK(wbs->last, 0, 8); + RNGCHECK(wbs->next, 0, 8); + } + RNGCHECK(wbs->pnum, 0, MAXPLAYERS); + RNGCHECK(wbs->pnum, 0, MAXPLAYERS); +#endif + + acceleratestage = 0; + cnt = bcnt = 0; + firstrefresh = 1; + me = wbs->pnum; + plrs = wbs->plyr; + + if (!wbs->maxkills) + wbs->maxkills = 1; // probably only useful in MAP30 + + if (!wbs->maxitems) + wbs->maxitems = 1; + + if ( gamemode != retail ) + if (wbs->epsd > 2) + wbs->epsd -= 3; +} + +// ==================================================================== +// WI_Start +// Purpose: Call the various init routines +// Note: wbstartstruct_t is defined in d_player.h +// Args: wbstartstruct -- pointer to the structure with the +// intermission data +// Returns: void +// +void WI_Start(wbstartstruct_t* wbstartstruct) +{ + WI_initVariables(wbstartstruct); + WI_loadData(); + + if (deathmatch) + WI_initDeathmatchStats(); + else if (netgame) + WI_initNetgameStats(); + else + WI_initStats(); +} diff --git a/src/wi_stuff.h b/src/wi_stuff.h new file mode 100644 index 0000000..c3363c8 --- /dev/null +++ b/src/wi_stuff.h @@ -0,0 +1,64 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Intermission screens. + * + *-----------------------------------------------------------------------------*/ + +#ifndef __WI_STUFF__ +#define __WI_STUFF__ + +//#include "v_video.h" + +#include "doomdef.h" + +// States for the intermission + +typedef enum +{ + NoState = -1, + StatCount, + ShowNextLoc + +} stateenum_t; + +// Called by main loop, animate the intermission. +void WI_Ticker (void); + +// Called by main loop, +// draws the intermission directly into the screen buffer. +void WI_Drawer (void); + +// Setup for an intermission screen. +void WI_Start(wbstartstruct_t* wbstartstruct); + +// Release intermission screen memory +void WI_End(void); + +#endif diff --git a/src/z_bmalloc.c b/src/z_bmalloc.c new file mode 100644 index 0000000..b415381 --- /dev/null +++ b/src/z_bmalloc.c @@ -0,0 +1,123 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * This is designed to be a fast allocator for small, regularly used block sizes + *----------------------------------------------------------------------------- + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "doomtype.h" +#include "z_zone.h" +#include "z_bmalloc.h" +#include "lprintf.h" + +typedef struct bmalpool_s { + struct bmalpool_s *nextpool; + size_t blocks; + byte used[0]; +} bmalpool_t; + +inline static void* getelem(bmalpool_t *p, size_t size, size_t n) +{ + return (((byte*)p) + sizeof(bmalpool_t) + sizeof(byte)*(p->blocks) + size*n); +} + +inline static PUREFUNC int iselem(const bmalpool_t *pool, size_t size, const void* p) +{ + // CPhipps - need portable # of bytes between pointers + int dif = (const char*)p - (const char*)pool; + + dif -= sizeof(bmalpool_t); + dif -= pool->blocks; + if (dif<0) return -1; + dif /= size; + return (((size_t)dif >= pool->blocks) ? -1 : dif); +} + +enum { unused_block = 0, used_block = 1}; + +void* Z_BMalloc(struct block_memory_alloc_s *pzone) +{ + register bmalpool_t **pool = (bmalpool_t **)&(pzone->firstpool); + while (*pool != NULL) { + byte *p = memchr((*pool)->used, unused_block, (*pool)->blocks); // Scan for unused marker + if (p) { + int n = p - (*pool)->used; +#ifdef SIMPLECHECKS + if ((n<0) || ((size_t)n>=(*pool)->blocks)) + I_Error("Z_BMalloc: memchr returned pointer outside of array"); +#endif + (*pool)->used[n] = used_block; + return getelem(*pool, pzone->size, n); + } else + pool = &((*pool)->nextpool); + } + { + // Nothing available, must allocate a new pool + bmalpool_t *newpool; + + // CPhipps: Allocate new memory, initialised to 0 + + *pool = newpool = Z_Calloc(sizeof(*newpool) + (sizeof(byte) + pzone->size)*(pzone->perpool), + 1, pzone->tag, NULL); + newpool->nextpool = NULL; // NULL = (void*)0 so this is redundant + + // Return element 0 from this pool to satisfy the request + newpool->used[0] = used_block; + newpool->blocks = pzone->perpool; + return getelem(newpool, pzone->size, 0); + } +} + +void Z_BFree(struct block_memory_alloc_s *pzone, void* p) +{ + register bmalpool_t **pool = (bmalpool_t**)&(pzone->firstpool); + + while (*pool != NULL) { + int n = iselem(*pool, pzone->size, p); + if (n >= 0) { +#ifdef SIMPLECHECKS + if ((*pool)->used[n] == unused_block) + I_Error("Z_BFree: Refree in zone %s", pzone->desc); +#endif + (*pool)->used[n] = unused_block; + if (memchr(((*pool)->used), used_block, (*pool)->blocks) == NULL) { + // Block is all unused, can be freed + bmalpool_t *oldpool = *pool; + *pool = (*pool)->nextpool; + Z_Free(oldpool); + } + return; + } else pool = &((*pool)->nextpool); + } + I_Error("Z_BFree: Free not in zone %s", pzone->desc); +} diff --git a/src/z_bmalloc.h b/src/z_bmalloc.h new file mode 100644 index 0000000..ed30c9f --- /dev/null +++ b/src/z_bmalloc.h @@ -0,0 +1,52 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Block memory allocator + * This is designed to be a fast allocator for small, regularly used block sizes + *-----------------------------------------------------------------------------*/ + +struct block_memory_alloc_s { + void *firstpool; + size_t size; + size_t perpool; + int tag; + const char *desc; +}; + +#define DECLARE_BLOCK_MEMORY_ALLOC_ZONE(name) extern struct block_memory_alloc_s name +#define IMPLEMENT_BLOCK_MEMORY_ALLOC_ZONE(name, size, tag, num, desc) \ +struct block_memory_alloc_s name = { NULL, size, num, tag, desc} +#define NULL_BLOCK_MEMORY_ALLOC_ZONE(name) name.firstpool = NULL + +void* Z_BMalloc(struct block_memory_alloc_s *pzone); + +inline static void* Z_BCalloc(struct block_memory_alloc_s *pzone) +{ void *p = Z_BMalloc(pzone); memset(p,0,pzone->size); return p; } + +void Z_BFree(struct block_memory_alloc_s *pzone, void* p); diff --git a/src/z_zone.c b/src/z_zone.c new file mode 100644 index 0000000..9b972fe --- /dev/null +++ b/src/z_zone.c @@ -0,0 +1,705 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Zone Memory Allocation. Neat. + * + * Neat enough to be rewritten by Lee Killough... + * + * Must not have been real neat :) + * + * Made faster and more general, and added wrappers for all of Doom's + * memory allocation functions, including malloc() and similar functions. + * Added line and file numbers, in case of error. Added performance + * statistics and tunables. + *----------------------------------------------------------------------------- + */ + + +// use config.h if autoconf made one -- josh +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "z_zone.h" +#include "doomstat.h" +#include "m_argv.h" +#include "v_video.h" +#include "g_game.h" +#include "lprintf.h" + +#ifdef DJGPP +#include +#endif + +// Tunables + +// Alignment of zone memory (benefit may be negated by HEADER_SIZE, CHUNK_SIZE) +#define CACHE_ALIGN 32 + +// Minimum chunk size at which blocks are allocated +#define CHUNK_SIZE 32 + +// Minimum size a block must be to become part of a split +#define MIN_BLOCK_SPLIT (1024) + +// How much RAM to leave aside for other libraries +#define LEAVE_ASIDE (128*1024) + +// Amount to subtract when retrying failed attempts to allocate initial pool +#define RETRY_AMOUNT (256*1024) + +// signature for block header +#define ZONEID 0x931d4a11 + +// Number of mallocs & frees kept in history buffer (must be a power of 2) +#define ZONE_HISTORY 4 + +// End Tunables + +typedef struct memblock { + +#ifdef ZONEIDCHECK + unsigned id; +#endif + + struct memblock *next,*prev; + size_t size; + void **user; + unsigned char tag; + +#ifdef INSTRUMENTED + const char *file; + int line; +#endif + +} memblock_t; + +/* size of block header + * cph - base on sizeof(memblock_t), which can be larger than CHUNK_SIZE on + * 64bit architectures */ +static const size_t HEADER_SIZE = (sizeof(memblock_t)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); + +static memblock_t *blockbytag[PU_MAX]; + +// 0 means unlimited, any other value is a hard limit +//static int memory_size = 8192*1024; +static int memory_size = 0; +static int free_memory = 0; + +#ifdef INSTRUMENTED + +// statistics for evaluating performance +static int active_memory = 0; +static int purgable_memory = 0; + +static void Z_DrawStats(void) // Print allocation statistics +{ + if (gamestate != GS_LEVEL) + return; + + if (memory_size > 0) { + unsigned long total_memory = free_memory + memory_size + active_memory + purgable_memory; + double s = 100.0 / total_memory; + + doom_printf("%-5i\t%6.01f%%\tstatic\n" + "%-5i\t%6.01f%%\tpurgable\n" + "%-5i\t%6.01f%%\tfree\n" + "%-5li\t\ttotal\n", + active_memory, + active_memory*s, + purgable_memory, + purgable_memory*s, + (free_memory + memory_size), + (free_memory + memory_size)*s, + total_memory + ); + } else { + unsigned long total_memory = active_memory + purgable_memory; + double s = 100.0 / total_memory; + + doom_printf("%-5i\t%6.01f%%\tstatic\n" + "%-5i\t%6.01f%%\tpurgable\n" + "%-5li\t\ttotal\n", + active_memory, + active_memory*s, + purgable_memory, + purgable_memory*s, + total_memory + ); + } +} + +#ifdef HEAPDUMP + +#ifndef HEAPDUMP_DIR +#define HEAPDUMP_DIR "." +#endif + +void W_PrintLump(FILE* fp, void* p); + +void Z_DumpMemory(void) +{ + static int dump; + char buf[PATH_MAX + 1]; + FILE* fp; + size_t total_cache = 0, total_free = 0, total_malloc = 0; + int tag; + + sprintf(buf, "%s/memdump.%d", HEAPDUMP_DIR, dump++); + fp = fopen(buf, "w"); + for (tag = PU_FREE; tag < PU_MAX; tag++) + { + memblock_t* end_block, *block; + block = blockbytag[tag]; + if (!block) + continue; + end_block = block->prev; + while (1) + { + switch (block->tag) { + case PU_FREE: + fprintf(fp, "free %d\n", block->size); + total_free += block->size; + break; + case PU_CACHE: + fprintf(fp, "cache %s:%d:%d\n", block->file, block->line, block->size); + total_cache += block->size; + break; + case PU_LEVEL: + fprintf(fp, "level %s:%d:%d\n", block->file, block->line, block->size); + total_malloc += block->size; + break; + default: + fprintf(fp, "malloc %s:%d:%d", block->file, block->line, block->size); + total_malloc += block->size; + if (block->file) + if (strstr(block->file,"w_memcache.c")) + W_PrintLump(fp, (char*)block + HEADER_SIZE); + fputc('\n', fp); + break; + } + if (block == end_block) + break; + block=block->next; + } + } + fprintf(fp, "malloc %d, cache %d, free %d, total %d\n", + total_malloc, total_cache, total_free, + total_malloc + total_cache + total_free); + fclose(fp); +} +#endif +#endif + +#ifdef INSTRUMENTED + +// killough 4/26/98: Add history information + +enum {malloc_history, free_history, NUM_HISTORY_TYPES}; + +static const char *file_history[NUM_HISTORY_TYPES][ZONE_HISTORY]; +static int line_history[NUM_HISTORY_TYPES][ZONE_HISTORY]; +static int history_index[NUM_HISTORY_TYPES]; +static const char *const desc[NUM_HISTORY_TYPES] = {"malloc()'s", "free()'s"}; + +void Z_DumpHistory(char *buf) +{ + int i,j; + char s[1024]; + strcat(buf,"\n"); + for (i=0;i= sizeof(memblock_t) && size > HEADER_SIZE)) + I_Error("Z_Init: Sanity check failed"); +#endif + + size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); // round to chunk size + size += HEADER_SIZE + CACHE_ALIGN; + + // Allocate the memory + + zonebase=(malloc)(size); + if (!zonebase) + I_Error("Z_Init: Failed on allocation of %lu bytes", (unsigned long)size); + + lprintf(LO_INFO,"Z_Init : Allocated %lukb zone memory\n", + (long unsigned)size / 1000); + + // Align on cache boundary + + zone = (memblock_t *) ((char *) zonebase + CACHE_ALIGN - + ((unsigned) zonebase & (CACHE_ALIGN-1))); + + rover = zone; // Rover points to base of zone mem + zone->next = zone->prev = zone; // Single node + zone->size = size; // All memory in one block + zone->tag = PU_FREE; // A free block + zone->vm = 0; + +#ifdef ZONEIDCHECK + zone->id = 0; +#endif + +#ifdef INSTRUMENTED + free_memory = size; + /* cph - remove unnecessary initialisations to 0 */ +#endif +#ifdef HEAPDUMP + atexit(Z_DumpMemory); +#endif +#endif +} + +/* Z_Malloc + * You can pass a NULL user if the tag is < PU_PURGELEVEL. + * + * cph - the algorithm here was a very simple first-fit round-robin + * one - just keep looping around, freeing everything we can until + * we get a large enough space + * + * This has been changed now; we still do the round-robin first-fit, + * but we only free the blocks we actually end up using; we don't + * free all the stuff we just pass on the way. + */ + +void *(Z_Malloc)(size_t size, int tag, void **user +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + memblock_t *block = NULL; + +#ifdef INSTRUMENTED +#ifdef CHECKHEAP + Z_CheckHeap(); +#endif + + file_history[malloc_history][history_index[malloc_history]] = file; + line_history[malloc_history][history_index[malloc_history]++] = line; + history_index[malloc_history] &= ZONE_HISTORY-1; +#endif + +#ifdef ZONEIDCHECK + if (tag >= PU_PURGELEVEL && !user) + I_Error ("Z_Malloc: An owner is required for purgable blocks" +#ifdef INSTRUMENTED + "Source: %s:%d", file, line +#endif + ); +#endif + + if (!size) + return user ? *user = NULL : NULL; // malloc(0) returns NULL + + size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); // round to chunk size + + if (memory_size > 0 && ((free_memory + memory_size) < (int)(size + HEADER_SIZE))) + { + memblock_t *end_block; + block = blockbytag[PU_CACHE]; + if (block) + { + end_block = block->prev; + while (1) + { + memblock_t *next = block->next; +#ifdef INSTRUMENTED + (Z_Free)((char *) block + HEADER_SIZE, file, line); +#else + (Z_Free)((char *) block + HEADER_SIZE); +#endif + if (((free_memory + memory_size) >= (int)(size + HEADER_SIZE)) || (block == end_block)) + break; + block = next; // Advance to next block + } + } + block = NULL; + } + +#ifdef HAVE_LIBDMALLOC + while (!(block = dmalloc_malloc(file,line,size + HEADER_SIZE,DMALLOC_FUNC_MALLOC,0,0))) { +#else + while (!(block = (malloc)(size + HEADER_SIZE))) { +#endif + if (!blockbytag[PU_CACHE]) + I_Error ("Z_Malloc: Failure trying to allocate %lu bytes" +#ifdef INSTRUMENTED + "\nSource: %s:%d" +#endif + ,(unsigned long) size +#ifdef INSTRUMENTED + , file, line +#endif + ); + Z_FreeTags(PU_CACHE,PU_CACHE); + } + + if (!blockbytag[tag]) + { + blockbytag[tag] = block; + block->next = block->prev = block; + } + else + { + blockbytag[tag]->prev->next = block; + block->prev = blockbytag[tag]->prev; + block->next = blockbytag[tag]; + blockbytag[tag]->prev = block; + } + + block->size = size; + +#ifdef INSTRUMENTED + if (tag >= PU_PURGELEVEL) + purgable_memory += block->size; + else + active_memory += block->size; +#endif + free_memory -= block->size; + +#ifdef INSTRUMENTED + block->file = file; + block->line = line; +#endif + +#ifdef ZONEIDCHECK + block->id = ZONEID; // signature required in block header +#endif + block->tag = tag; // tag + block->user = user; // user + block = (memblock_t *)((char *) block + HEADER_SIZE); + if (user) // if there is a user + *user = block; // set user to point to new block + +#ifdef INSTRUMENTED + Z_DrawStats(); // print memory allocation stats + // scramble memory -- weed out any bugs + memset(block, gametic & 0xff, size); +#endif + + return block; +} + +void (Z_Free)(void *p +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + memblock_t *block = (memblock_t *)((char *) p - HEADER_SIZE); + +#ifdef INSTRUMENTED +#ifdef CHECKHEAP + Z_CheckHeap(); +#endif + file_history[free_history][history_index[free_history]] = file; + line_history[free_history][history_index[free_history]++] = line; + history_index[free_history] &= ZONE_HISTORY-1; +#endif + + if (!p) + return; + + +#ifdef ZONEIDCHECK + if (block->id != ZONEID) + I_Error("Z_Free: freed a pointer without ZONEID" +#ifdef INSTRUMENTED + "\nSource: %s:%d" + "\nSource of malloc: %s:%d" + , file, line, block->file, block->line +#endif + ); + block->id = 0; // Nullify id so another free fails +#endif + + if (block->user) // Nullify user if one exists + *block->user = NULL; + + if (block == block->next) + blockbytag[block->tag] = NULL; + else + if (blockbytag[block->tag] == block) + blockbytag[block->tag] = block->next; + block->prev->next = block->next; + block->next->prev = block->prev; + + free_memory += block->size; +#ifdef INSTRUMENTED + if (block->tag >= PU_PURGELEVEL) + purgable_memory -= block->size; + else + active_memory -= block->size; + + /* scramble memory -- weed out any bugs */ + memset(block, gametic & 0xff, block->size + HEADER_SIZE); +#endif + +#ifdef HAVE_LIBDMALLOC + dmalloc_free(file,line,block,DMALLOC_FUNC_MALLOC); +#else + (free)(block); +#endif +#ifdef INSTRUMENTED + Z_DrawStats(); // print memory allocation stats +#endif +} + +void (Z_FreeTags)(int lowtag, int hightag +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ +#ifdef HEAPDUMP + Z_DumpMemory(); +#endif + + if (lowtag <= PU_FREE) + lowtag = PU_FREE+1; + + if (hightag > PU_CACHE) + hightag = PU_CACHE; + + for (;lowtag <= hightag; lowtag++) + { + memblock_t *block, *end_block; + block = blockbytag[lowtag]; + if (!block) + continue; + end_block = block->prev; + while (1) + { + memblock_t *next = block->next; +#ifdef INSTRUMENTED + (Z_Free)((char *) block + HEADER_SIZE, file, line); +#else + (Z_Free)((char *) block + HEADER_SIZE); +#endif + if (block == end_block) + break; + block = next; // Advance to next block + } + } +} + +void (Z_ChangeTag)(void *ptr, int tag +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + memblock_t *block = (memblock_t *)((char *) ptr - HEADER_SIZE); + + // proff - added sanity check, this can happen when an empty lump is locked + if (!ptr) + return; + + // proff - do nothing if tag doesn't differ + if (tag == block->tag) + return; + +#ifdef INSTRUMENTED +#ifdef CHECKHEAP + Z_CheckHeap(); +#endif +#endif + +#ifdef ZONEIDCHECK + if (block->id != ZONEID) + I_Error ("Z_ChangeTag: freed a pointer without ZONEID" +#ifdef INSTRUMENTED + "\nSource: %s:%d" + "\nSource of malloc: %s:%d" + , file, line, block->file, block->line +#endif + ); + + if (tag >= PU_PURGELEVEL && !block->user) + I_Error ("Z_ChangeTag: an owner is required for purgable blocks\n" +#ifdef INSTRUMENTED + "Source: %s:%d" + "\nSource of malloc: %s:%d" + , file, line, block->file, block->line +#endif + ); + +#endif // ZONEIDCHECK + + if (block == block->next) + blockbytag[block->tag] = NULL; + else + if (blockbytag[block->tag] == block) + blockbytag[block->tag] = block->next; + block->prev->next = block->next; + block->next->prev = block->prev; + + if (!blockbytag[tag]) + { + blockbytag[tag] = block; + block->next = block->prev = block; + } + else + { + blockbytag[tag]->prev->next = block; + block->prev = blockbytag[tag]->prev; + block->next = blockbytag[tag]; + blockbytag[tag]->prev = block; + } + +#ifdef INSTRUMENTED + if (block->tag < PU_PURGELEVEL && tag >= PU_PURGELEVEL) + { + active_memory -= block->size; + purgable_memory += block->size; + } + else + if (block->tag >= PU_PURGELEVEL && tag < PU_PURGELEVEL) + { + active_memory += block->size; + purgable_memory -= block->size; + } +#endif + + block->tag = tag; +} + +void *(Z_Realloc)(void *ptr, size_t n, int tag, void **user +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + void *p = (Z_Malloc)(n, tag, user DA(file, line)); + if (ptr) + { + memblock_t *block = (memblock_t *)((char *) ptr - HEADER_SIZE); + memcpy(p, ptr, n <= block->size ? n : block->size); + (Z_Free)(ptr DA(file, line)); + if (user) // in case Z_Free nullified same user + *user=p; + } + return p; +} + +void *(Z_Calloc)(size_t n1, size_t n2, int tag, void **user +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + return + (n1*=n2) ? memset((Z_Malloc)(n1, tag, user DA(file, line)), 0, n1) : NULL; +} + +char *(Z_Strdup)(const char *s, int tag, void **user +#ifdef INSTRUMENTED + , const char *file, int line +#endif + ) +{ + return strcpy((Z_Malloc)(strlen(s)+1, tag, user DA(file, line)), s); +} + +void (Z_CheckHeap)( +#ifdef INSTRUMENTED + const char *file, int line +#else + void +#endif + ) +{ +#if 0 + memblock_t *block; // Start at base of zone mem + if (block) + do { // Consistency check (last node treated special) + if ((block->next != zone && + (memblock_t *)((char *) block+HEADER_SIZE+block->size) != block->next) + || block->next->prev != block || block->prev->next != block) + I_Error("Z_CheckHeap: Block size does not touch the next block\n" +#ifdef INSTRUMENTED + "Source: %s:%d" + "\nSource of offending block: %s:%d" + , file, line, block->file, block->line +#endif + ); +//#ifdef INSTRUMENTED +// shouldn't be needed anymore, was just for testing +#if 0 + if (((int)block->file < 0x00001000) && (block->file != NULL) && (block->tag != 0)) { + block->file = NULL; + } +#endif + } while ((block=block->next) != zone); +#endif +} diff --git a/src/z_zone.h b/src/z_zone.h new file mode 100644 index 0000000..f70ce08 --- /dev/null +++ b/src/z_zone.h @@ -0,0 +1,129 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * Zone Memory Allocation, perhaps NeXT ObjectiveC inspired. + * Remark: this was the only stuff that, according + * to John Carmack, might have been useful for + * Quake. + * + * Rewritten by Lee Killough, though, since it was not efficient enough. + * + *---------------------------------------------------------------------*/ + +#ifndef __Z_ZONE__ +#define __Z_ZONE__ + +#ifndef __GNUC__ +#define __attribute__(x) +#endif + +// Include system definitions so that prototypes become +// active before macro replacements below are in effect. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include +#include + +// ZONE MEMORY +// PU - purge tags. + +enum {PU_FREE, PU_STATIC, PU_SOUND, PU_MUSIC, PU_LEVEL, PU_LEVSPEC, PU_CACHE, + /* Must always be last -- killough */ PU_MAX}; + +#define PU_PURGELEVEL PU_CACHE /* First purgable tag's level */ + +#ifdef INSTRUMENTED +#define DA(x,y) ,x,y +#define DAC(x,y) x,y +#else +#define DA(x,y) +#define DAC(x,y) +#endif + +void *(Z_Malloc)(size_t size, int tag, void **ptr DA(const char *, int)); +void (Z_Free)(void *ptr DA(const char *, int)); +void (Z_FreeTags)(int lowtag, int hightag DA(const char *, int)); +void (Z_ChangeTag)(void *ptr, int tag DA(const char *, int)); +void (Z_Init)(void); +void Z_Close(void); +void *(Z_Calloc)(size_t n, size_t n2, int tag, void **user DA(const char *, int)); +void *(Z_Realloc)(void *p, size_t n, int tag, void **user DA(const char *, int)); +char *(Z_Strdup)(const char *s, int tag, void **user DA(const char *, int)); +void (Z_CheckHeap)(DAC(const char *,int)); // killough 3/22/98: add file/line info +void Z_DumpHistory(char *); + +#ifdef INSTRUMENTED +/* cph - save space if not debugging, don't require file + * and line to memory calls */ +#define Z_Free(a) (Z_Free) (a, __FILE__,__LINE__) +#define Z_FreeTags(a,b) (Z_FreeTags) (a,b, __FILE__,__LINE__) +#define Z_ChangeTag(a,b) (Z_ChangeTag)(a,b, __FILE__,__LINE__) +#define Z_Malloc(a,b,c) (Z_Malloc) (a,b,c, __FILE__,__LINE__) +#define Z_Strdup(a,b,c) (Z_Strdup) (a,b,c, __FILE__,__LINE__) +#define Z_Calloc(a,b,c,d) (Z_Calloc) (a,b,c,d,__FILE__,__LINE__) +#define Z_Realloc(a,b,c,d) (Z_Realloc) (a,b,c,d,__FILE__,__LINE__) +#define Z_CheckHeap() (Z_CheckHeap)(__FILE__,__LINE__) +#endif + +/* cphipps 2001/11/18 - + * If we're using memory mapped file access to WADs, we won't need to maintain + * our own heap. So we *could* let "normal" malloc users use the libc malloc + * directly, for efficiency. Except we do need a wrapper to handle out of memory + * errors... damn, ok, we'll leave it for now. + */ +#ifndef HAVE_LIBDMALLOC +// Remove all definitions before including system definitions + +#undef malloc +#undef free +#undef realloc +#undef calloc +#undef strdup + +#define malloc(n) Z_Malloc(n,PU_STATIC,0) +#define free(p) Z_Free(p) +#define realloc(p,n) Z_Realloc(p,n,PU_STATIC,0) +#define calloc(n1,n2) Z_Calloc(n1,n2,PU_STATIC,0) +#define strdup(s) Z_Strdup(s,PU_STATIC,0) + +#else + +#ifdef HAVE_LIBDMALLOC +#include +#endif + +#endif + +void Z_ZoneHistory(char *); + +#endif -- cgit v1.2.3